diff --git a/impl/src/main/java/org/glassfish/soteria/cdi/CdiUtils.java b/impl/src/main/java/org/glassfish/soteria/cdi/CdiUtils.java
index 5ead0c3..c7e4db6 100644
--- a/impl/src/main/java/org/glassfish/soteria/cdi/CdiUtils.java
+++ b/impl/src/main/java/org/glassfish/soteria/cdi/CdiUtils.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022 Contributors to the Eclipse Foundation
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -37,11 +38,10 @@
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.naming.InitialContext;
-import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
public class CdiUtils {
-
+
public static Optional getAnnotation(BeanManager beanManager, Annotated annotated, Class annotationType) {
annotated.getAnnotation(annotationType);
@@ -74,13 +74,13 @@ public static Optional getAnnotation(BeanManager beanM
return empty();
}
-
+
public static void addAnnotatedTypes(BeforeBeanDiscovery beforeBean, BeanManager beanManager, Class>... types) {
for (Class> type : types) {
beforeBean.addAnnotatedType(beanManager.createAnnotatedType(type), "Soteria " + type.getName());
}
}
-
+
public static Optional getAnnotation(BeanManager beanManager, Class> annotatedClass, Class annotationType) {
if (annotatedClass.isAnnotationPresent(annotationType)) {
@@ -107,23 +107,28 @@ public static Optional getAnnotation(BeanManager beanM
return empty();
}
-
- public static BeanManager getBeanManager() {
- BeanManager beanManager = jndiLookup("java:comp/BeanManager");
- if (beanManager == null) {
- // Servlet containers
- beanManager = jndiLookup("java:comp/env/BeanManager");
+ /**
+ * @return non-null {@link BeanManager}
+ * @throws IllegalStateException if it wasn't possible to find the CDI BeanManager.
+ */
+ public static BeanManager getBeanManager() throws IllegalStateException {
+ try {
+ return jndiLookup("java:comp/BeanManager","java:comp/env/BeanManager");
+ } catch (NamingException e) {
+ throw new IllegalStateException("The CDI Bean Manager is not available.", e);
}
-
- return beanManager;
}
-
- //
+
+ /**
+ * @param type the required bean type the reference must have
+ * @param qualifiers the required qualifiers the reference must have
+ * @return a bean reference adhering to the required type and qualifiers
+ */
public static T getBeanReference(Class type, Annotation... qualifiers) {
return type.cast(getBeanReferenceByType(getBeanManager(), type, qualifiers));
}
-
+
/**
* @param beanManager the bean manager
* @param type the required bean type the reference must have
@@ -145,17 +150,17 @@ public static Object getBeanReferenceByType(BeanManager beanManager, Type type,
return beanReference;
}
-
+
@SuppressWarnings("unchecked")
private static T getContextualReference(Class type, BeanManager beanManager, Set> beans) {
-
+
Object beanReference = null;
-
+
Bean> bean = beanManager.resolve(beans);
if (bean != null) {
beanReference = beanManager.getReference(bean, type, beanManager.createCreationalContext(bean));
}
-
+
return (T) beanReference;
}
@@ -172,19 +177,19 @@ public static List getBeanReferencesByType(Class type, boolean optiona
return result;
}
-
+
public static ELProcessor getELProcessor(ELProcessor elProcessor) {
if (elProcessor != null) {
return elProcessor;
}
-
+
return getELProcessor();
}
-
+
public static ELProcessor getELProcessor() {
ELProcessor elProcessor = new ELProcessor();
elProcessor.getELManager().addELResolver(getBeanManager().getELResolver());
-
+
return elProcessor;
}
@@ -192,27 +197,40 @@ private static Set> getBeanDefinitions(Class type, boolean option
Set> beans = beanManager.getBeans(type, new AnyAnnotationLiteral());
if (!isEmpty(beans)) {
return beans;
- }
-
+ }
+
if (optional) {
return emptySet();
- }
-
+ }
+
throw new IllegalStateException("Could not find beans for Type=" + type);
}
- @SuppressWarnings("unchecked")
- public static T jndiLookup(String name) {
+ /**
+ * Tries provided names, first found non-null object is returned.
+ *
+ * @param expected type
+ * @param names list of JNDI names to try.
+ * @return non-null object
+ * @throws NamingException if all lookups ended with an exception or null values.
+ */
+ public static T jndiLookup(String... names) throws NamingException {
InitialContext context = null;
try {
context = new InitialContext();
- return (T) context.lookup(name);
- } catch (NamingException e) {
- if (is(e, NameNotFoundException.class)) {
- return null;
- } else {
- throw new IllegalStateException(e);
+ NamingException exceptionCollector = new NamingException(String.join(", ", names));
+ for (String name : names) {
+ try {
+ @SuppressWarnings("unchecked")
+ T found = (T) context.lookup(name);
+ if (found != null) {
+ return found;
+ }
+ } catch (NamingException e) {
+ exceptionCollector.addSuppressed(e);
+ }
}
+ throw exceptionCollector;
} finally {
close(context);
}
@@ -227,7 +245,7 @@ private static void close(InitialContext context) {
throw new IllegalStateException(e);
}
}
-
+
public static boolean is(Throwable exception, Class type) {
Throwable unwrappedException = exception;
diff --git a/impl/src/main/java/org/glassfish/soteria/identitystores/DatabaseIdentityStore.java b/impl/src/main/java/org/glassfish/soteria/identitystores/DatabaseIdentityStore.java
index 257e38c..92712ec 100644
--- a/impl/src/main/java/org/glassfish/soteria/identitystores/DatabaseIdentityStore.java
+++ b/impl/src/main/java/org/glassfish/soteria/identitystores/DatabaseIdentityStore.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022 Contributors to the Eclipse Foundation
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -46,6 +47,8 @@
import jakarta.security.enterprise.identitystore.IdentityStore;
import jakarta.security.enterprise.identitystore.IdentityStorePermission;
import jakarta.security.enterprise.identitystore.PasswordHash;
+
+import javax.naming.NamingException;
import javax.sql.DataSource;
public class DatabaseIdentityStore implements IdentityStore {
@@ -54,7 +57,7 @@ public class DatabaseIdentityStore implements IdentityStore {
private final Set validationTypes;
private final PasswordHash hashAlgorithm; // Note: effectively application scoped, no support for @PreDestroy now
-
+
// CDI requires a no-arg constructor to be portable
// It's only used to create the proxy
protected DatabaseIdentityStore() {
@@ -62,10 +65,10 @@ protected DatabaseIdentityStore() {
this.validationTypes = null;
this.hashAlgorithm = null;
}
-
+
public DatabaseIdentityStore(DatabaseIdentityStoreDefinition dataBaseIdentityStoreDefinition) {
this.dataBaseIdentityStoreDefinition = dataBaseIdentityStoreDefinition;
-
+
validationTypes = unmodifiableSet(new HashSet<>(asList(dataBaseIdentityStoreDefinition.useFor())));
hashAlgorithm = getBeanReference(dataBaseIdentityStoreDefinition.hashAlgorithm());
hashAlgorithm.initialize(
@@ -74,7 +77,7 @@ public DatabaseIdentityStore(DatabaseIdentityStoreDefinition dataBaseIdentitySto
dataBaseIdentityStoreDefinition.hashAlgorithmParameters())
.flatMap(s -> toStream(evalImmediate(s, (Object)s)))
.collect(toMap(
- s -> s.substring(0, s.indexOf('=')) ,
+ s -> s.substring(0, s.indexOf('=')) ,
s -> evalImmediate(s.substring(s.indexOf('=') + 1))
))));
}
@@ -93,15 +96,15 @@ public CredentialValidationResult validate(UsernamePasswordCredential usernamePa
DataSource dataSource = getDataSource();
List passwords = executeQuery(
- dataSource,
+ dataSource,
dataBaseIdentityStoreDefinition.callerQuery(),
usernamePasswordCredential.getCaller()
);
-
+
if (passwords.isEmpty()) {
return INVALID_RESULT;
}
-
+
if (hashAlgorithm.verify(usernamePasswordCredential.getPassword().getValue(), passwords.get(0))) {
Set groups = emptySet();
if (validationTypes.contains(ValidationType.PROVIDE_GROUPS)) {
@@ -113,7 +116,7 @@ public CredentialValidationResult validate(UsernamePasswordCredential usernamePa
return INVALID_RESULT;
}
-
+
@Override
public Set getCallerGroups(CredentialValidationResult validationResult) {
@@ -159,31 +162,25 @@ public int priority() {
public Set validationTypes() {
return validationTypes;
}
-
+
@SuppressWarnings("unchecked")
private Stream toStream(Object raw) {
if (raw instanceof String[]) {
- return stream((String[])raw);
+ return stream((String[]) raw);
}
if (raw instanceof Stream>) {
- return ((Stream) raw).map(s -> s.toString());
+ return ((Stream) raw).map(String::toString);
}
-
+
return asList(raw.toString()).stream();
}
private DataSource getDataSource() {
- DataSource dataSource = null;
try {
- dataSource = jndiLookup(dataBaseIdentityStoreDefinition.dataSourceLookup());
- if (dataSource == null) {
- throw new IdentityStoreConfigurationException("Jndi lookup failed for DataSource " + dataBaseIdentityStoreDefinition.dataSourceLookup());
- }
- } catch (IdentityStoreConfigurationException e) {
- throw e;
- } catch (Exception e) {
- throw new IdentityStoreRuntimeException(e);
+ return jndiLookup(dataBaseIdentityStoreDefinition.dataSourceLookup());
+ } catch (NamingException e) {
+ throw new IdentityStoreRuntimeException(
+ "JNDI lookup failed for DataSource " + dataBaseIdentityStoreDefinition.dataSourceLookup(), e);
}
- return dataSource;
}
}
diff --git a/impl/src/main/java/org/glassfish/soteria/servlet/SamRegistrationInstaller.java b/impl/src/main/java/org/glassfish/soteria/servlet/SamRegistrationInstaller.java
index d3a7db1..72f07cc 100644
--- a/impl/src/main/java/org/glassfish/soteria/servlet/SamRegistrationInstaller.java
+++ b/impl/src/main/java/org/glassfish/soteria/servlet/SamRegistrationInstaller.java
@@ -74,7 +74,6 @@ public void onStartup(Set> c, ServletContext ctx) throws ServletExcepti
// and calling CDI.current() will throw an exception. It's no use to continue then.
// TODO: Do we need to find out *why* the default module does not have CDI initialized?
logger.log(FINEST, "CDI not available for app context id: " + Jaspic.getAppContextID(ctx), e);
-
return;
}