diff --git a/connector/pom.xml b/connector/pom.xml
index 92fb88241aa7..89d0e7b13e76 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -97,6 +97,10 @@
org.jboss.ironjacamar
ironjacamar-validator
+
+ org.jboss.spec.javax.security.auth.message
+ jboss-jaspi-api_1.1_spec
+
org.jboss.logging
jboss-logging
diff --git a/connector/src/main/java/org/jboss/as/connector/security/ElytronCallbackHandler.java b/connector/src/main/java/org/jboss/as/connector/security/ElytronCallbackHandler.java
index eace268c0968..270ba5b36ad3 100644
--- a/connector/src/main/java/org/jboss/as/connector/security/ElytronCallbackHandler.java
+++ b/connector/src/main/java/org/jboss/as/connector/security/ElytronCallbackHandler.java
@@ -19,35 +19,56 @@
import java.io.IOException;
import java.io.Serializable;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import javax.resource.spi.security.PasswordCredential;
+import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.message.callback.CallerPrincipalCallback;
+import javax.security.auth.message.callback.GroupPrincipalCallback;
+import javax.security.auth.message.callback.PasswordValidationCallback;
import org.jboss.jca.core.spi.security.Callback;
+import org.wildfly.security.auth.principal.NamePrincipal;
+import org.wildfly.security.auth.server.RealmUnavailableException;
+import org.wildfly.security.auth.server.SecurityDomain;
+import org.wildfly.security.auth.server.SecurityIdentity;
+import org.wildfly.security.auth.server.ServerAuthenticationContext;
+import org.wildfly.security.authz.RoleMapper;
+import org.wildfly.security.authz.Roles;
+import org.wildfly.security.evidence.PasswordGuessEvidence;
+import org.wildfly.security.manager.WildFlySecurityManager;
/**
- * CallbackHandler implementation for Elytron
+ * An Elytron based {@link CallbackHandler} implementation designed for the JCA security inflow. It uses the information
+ * obtained from the {@link javax.security.auth.callback.Callback}s to authenticate and authorize the identity supplied
+ * by the resource adapter and inserts the {@link SecurityIdentity} representing the authorized identity in the subject's
+ * private credentials set.
*
* @author Flavia Rainone
+ * @author Stefan Guilhen
*/
public class ElytronCallbackHandler implements CallbackHandler, Serializable {
- /** Callback mappings */
- private Callback mappings;
+ private final SecurityDomain securityDomain;
- /**
- * Constructor
- */
- public ElytronCallbackHandler() {
- this(null);
- }
+ /** Callback mappings */
+ private final Callback mappings;
+ // TODO initialize the execution subject at the constructor.
+ private Subject executionSubject;
/**
* Constructor
* @param mappings The mappings
*/
- public ElytronCallbackHandler(Callback mappings) {
+ public ElytronCallbackHandler(final SecurityDomain securityDomain, final Callback mappings) {
+ this.securityDomain = securityDomain;
this.mappings = mappings;
}
@@ -64,7 +85,164 @@ public void handle(javax.security.auth.callback.Callback[] callbacks) throws Uns
{
callbacks = mappings.mapCallbacks(callbacks);
}
- // TODO
+
+ GroupPrincipalCallback groupPrincipalCallback = null;
+ CallerPrincipalCallback callerPrincipalCallback = null;
+ PasswordValidationCallback passwordValidationCallback = null;
+
+ for (javax.security.auth.callback.Callback callback : callbacks) {
+ if (callback instanceof GroupPrincipalCallback) {
+ groupPrincipalCallback = (GroupPrincipalCallback) callback;
+ if (executionSubject == null) {
+ executionSubject = groupPrincipalCallback.getSubject();
+ } else if (!executionSubject.equals(groupPrincipalCallback.getSubject())) {
+ // TODO merge the contents of the subjects?
+ }
+ } else if (callback instanceof CallerPrincipalCallback) {
+ callerPrincipalCallback = (CallerPrincipalCallback) callback;
+ if (executionSubject == null) {
+ executionSubject = callerPrincipalCallback.getSubject();
+ } else if (!executionSubject.equals(callerPrincipalCallback.getSubject())) {
+ // TODO merge the contents of the subjects?
+ }
+ } else if (callback instanceof PasswordValidationCallback) {
+ passwordValidationCallback = (PasswordValidationCallback) callback;
+ if (executionSubject == null) {
+ executionSubject = passwordValidationCallback.getSubject();
+ } else if (!executionSubject.equals(passwordValidationCallback.getSubject())) {
+ // TODO merge the contents of the subjects?
+ }
+ } else {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ this.processResults(callerPrincipalCallback, groupPrincipalCallback, passwordValidationCallback);
+ }
+ }
+
+ protected void processResults(final CallerPrincipalCallback callerPrincipalCallback, final GroupPrincipalCallback groupPrincipalCallback,
+ final PasswordValidationCallback passwordValidationCallback) throws IOException {//, UnsupportedCallbackException {
+
+ // spec section 16.4.5 - no CallerPrincipalCallback was handled, check the execution subject's principal set.
+ SecurityIdentity authenticatedIdentity = this.securityDomain.getAnonymousSecurityIdentity();
+ Principal callerPrincipal = null;
+ if (callerPrincipalCallback == null) {
+ if (executionSubject.getPrincipals().size() == 1) {
+ Principal subjectPrincipal = executionSubject.getPrincipals().iterator().next();
+ callerPrincipal = new NamePrincipal(subjectPrincipal.getName());
+ // TODO apply mapping to the principal if needed
+ } else if (!executionSubject.getPrincipals().isEmpty()) {
+ // TODO throw exception here (spec violation)?
+ }
+ } else {
+ Principal callbackPrincipal = callerPrincipalCallback.getPrincipal();
+ callerPrincipal = callbackPrincipal != null ? new NamePrincipal(callbackPrincipal.getName()) :
+ callerPrincipalCallback.getName() != null ? new NamePrincipal(callerPrincipalCallback.getName()) : null;
+ }
+
+ // a null principal is the ra contract for requiring the use of the unauthenticated identity - there's no point trying to authenticate any identity.
+ if (callerPrincipal != null) {
+ // check if we have a username/password pair to authenticate - first try the password validation callback.
+ if (passwordValidationCallback != null) {
+ authenticatedIdentity = this.authenticate(passwordValidationCallback.getUsername(), passwordValidationCallback.getPassword());
+ } else {
+ // identity not established using the callback - check if the execution subject contains a password credential.
+ PasswordCredential passwordCredential = this.getPasswordCredential(this.executionSubject);
+ if (passwordCredential != null) {
+ authenticatedIdentity = this.authenticate(passwordCredential.getUserName(), passwordCredential.getPassword());
+ }
+ }
+ }
+
+ // if the caller principal is different from the authenticated identity principal, switch to the caller principal identity.
+ if (callerPrincipal != null && !callerPrincipal.equals(authenticatedIdentity.getPrincipal())) {
+ authenticatedIdentity = authenticatedIdentity.createRunAsIdentity(callerPrincipal.getName());
+ }
+
+ // if we have new roles coming from the group callback, set a new mapper in the identity.
+ if (groupPrincipalCallback != null) {
+ String[] groups = groupPrincipalCallback.getGroups();
+ if (groups != null) {
+ Set roles = new HashSet<>(Arrays.asList(groups));
+ // TODO what category should we use here? Is it right to assume every entry in the groups array represents a role?
+ authenticatedIdentity = authenticatedIdentity.withRoleMapper("jca", RoleMapper.constant(Roles.fromSet(roles)));
+ }
+ }
+
+ // set the authenticated identity as a private credential in the subject.
+ if (executionSubject != null) {
+ this.addPrivateCredential(executionSubject, authenticatedIdentity);
+ }
+ }
+
+ /**
+ * Authenticate the user with the given credential against the configured Elytron security domain.
+ *
+ * @param username the user being authenticated.
+ * @param credential the credential used as evidence to verify the user's identity.
+ * @return the authenticated and authorized {@link SecurityIdentity}.
+ * @throws IOException if an error occurs while authenticating the user.
+ */
+ private SecurityIdentity authenticate(final String username, final char[] credential) throws IOException {
+ final ServerAuthenticationContext context = this.securityDomain.createNewAuthenticationContext();
+ final PasswordGuessEvidence evidence = new PasswordGuessEvidence(credential != null ? credential : null);
+ try {
+ context.setAuthenticationName(username);
+ if (context.verifyEvidence(evidence)) {
+ if (context.authorize()) {
+ context.succeed();
+ return context.getAuthorizedIdentity();
+ } else {
+ context.fail();
+ throw new SecurityException("Authorization failed");
+ }
+ } else {
+ context.fail();
+ throw new SecurityException("Authentication failed");
+ }
+ } catch (IllegalArgumentException | IllegalStateException | RealmUnavailableException e) {
+ context.fail();
+ throw e;
+ } finally {
+ if (!context.isDone()) {
+ context.fail();
+ }
+ evidence.destroy();
+ }
+ }
+
+ protected PasswordCredential getPasswordCredential(final Subject subject) {
+ PasswordCredential credential = null;
+ if (subject != null) {
+ Set credentialSet;
+ if (!WildFlySecurityManager.isChecking()) {
+ credentialSet = subject.getPrivateCredentials(PasswordCredential.class);
+ } else {
+ credentialSet = AccessController.doPrivileged((PrivilegedAction>) () ->
+ subject.getPrivateCredentials(PasswordCredential.class));
+ }
+ if (!credentialSet.isEmpty()) {
+ credential = credentialSet.iterator().next();
+ }
+ }
+ return credential;
+ }
+
+ /**
+ * Add the specified credential to the subject's private credentials set.
+ *
+ * @param subject the {@link Subject} to add the credential to.
+ * @param credential a reference to the credential.
+ */
+ protected void addPrivateCredential(final Subject subject, final Object credential) {
+ if (!WildFlySecurityManager.isChecking()) {
+ subject.getPrivateCredentials().add(credential);
+ }
+ else {
+ AccessController.doPrivileged((PrivilegedAction) () -> {
+ subject.getPrivateCredentials().add(credential);
+ return null;
+ });
}
}
diff --git a/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityContext.java b/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityContext.java
index d0d8e0adbbf3..17431de0892e 100644
--- a/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityContext.java
+++ b/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityContext.java
@@ -15,43 +15,52 @@
*/
package org.jboss.as.connector.security;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
+
import javax.security.auth.Subject;
import org.jboss.jca.core.spi.security.SecurityContext;
+import org.wildfly.security.auth.server.SecurityIdentity;
+import org.wildfly.security.manager.WildFlySecurityManager;
/**
- * SecurityContext implementation for Elytron.
+ * An Elytron based {@link SecurityContext} implementation.
*
* @author Flavia Rainone
+ * @author Stefan Guilhen
*/
public class ElytronSecurityContext implements SecurityContext {
- /**
- * Constructor
- */
- public ElytronSecurityContext() {
- }
+ private Subject authenticatedSubject;
- /**
- * {@inheritDoc}
- */
+ @Override
public Subject getAuthenticatedSubject() {
- // TODO
- return null;
+ return this.authenticatedSubject;
}
- /**
- * {@inheritDoc}
- */
- public void setAuthenticatedSubject(Subject subject) {
- // TODO
+ @Override
+ public void setAuthenticatedSubject(final Subject subject) {
+ this.authenticatedSubject = subject;
}
- /**
- * {@inheritDoc}
- */
+ @Override
public String[] getRoles() {
- return null; // TODO
+ if (this.authenticatedSubject != null) {
+ // check if the authenticated subject contains a SecurityIdentity in its private credentials.
+ Set authenticatedIdentities = this.getPrivateCredentials(SecurityIdentity.class);
+ // iterate through the identities adding all the roles found.
+ final Set rolesSet = new HashSet<>();
+ for (SecurityIdentity identity : authenticatedIdentities) {
+ for (String role : identity.getRoles()) {
+ rolesSet.add(role);
+ }
+ }
+ return rolesSet.toArray(new String[rolesSet.size()]);
+ }
+ return new String[0];
}
/**
@@ -60,6 +69,25 @@ public String[] getRoles() {
* @param work executes the work
*/
public void runWork(Runnable work) {
- // TODO
+ // if we have an authenticated subject we check if it contains a security identity and use the identity to run the work.
+ if (this.authenticatedSubject != null) {
+ Set authenticatedIdentities = this.getPrivateCredentials(SecurityIdentity.class);
+ if (!authenticatedIdentities.isEmpty()) {
+ SecurityIdentity identity = authenticatedIdentities.iterator().next();
+ identity.runAs(work);
+ return;
+ }
+ }
+ // no authenticated subject found or the subject didn't have a security identity - just run the work.
+ work.run();
}
+
+ protected Set getPrivateCredentials(Class credentialClass) {
+ if (!WildFlySecurityManager.isChecking()) {
+ return this.authenticatedSubject.getPrivateCredentials(credentialClass);
+ } else {
+ return AccessController.doPrivileged((PrivilegedAction>) () -> this.authenticatedSubject.getPrivateCredentials(credentialClass));
+ }
+ }
+
}
diff --git a/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityIntegration.java b/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityIntegration.java
index 706ef306f4a8..a1e561e7c585 100644
--- a/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityIntegration.java
+++ b/connector/src/main/java/org/jboss/as/connector/security/ElytronSecurityIntegration.java
@@ -15,63 +15,83 @@
*/
package org.jboss.as.connector.security;
+import java.security.AccessController;
+
import javax.security.auth.callback.CallbackHandler;
+import org.jboss.as.controller.capability.RuntimeCapability;
+import org.jboss.as.server.CurrentServiceContainer;
import org.jboss.jca.core.spi.security.Callback;
import org.jboss.jca.core.spi.security.SecurityContext;
import org.jboss.jca.core.spi.security.SecurityIntegration;
+import org.jboss.msc.service.ServiceContainer;
+import org.jboss.msc.service.ServiceName;
+import org.wildfly.security.auth.server.SecurityDomain;
+import org.wildfly.security.manager.WildFlySecurityManager;
/**
- * SecurityIntegration implementation for Elytron.
+ * An Elytron based {@link SecurityIntegration} implementation.
*
* @author Flavia Rainone
+ * @author Stefan Guilhen
*/
public class ElytronSecurityIntegration implements SecurityIntegration {
- /**
- * Constructor
- */
- public ElytronSecurityIntegration() {
- }
- /**
- * {@inheritDoc}
- */
+ private static final String SECURITY_DOMAIN_CAPABILITY = "org.wildfly.security.security-domain";
+
+ private static final RuntimeCapability SECURITY_DOMAIN_RUNTIME_CAPABILITY = RuntimeCapability
+ .Builder.of(SECURITY_DOMAIN_CAPABILITY, true, SecurityDomain.class)
+ .build();
+
+ private final ThreadLocal securityContext = new ThreadLocal<>();
+
+ @Override
public SecurityContext createSecurityContext(String sd) throws Exception {
- // TODO
return new ElytronSecurityContext();
}
- /**
- * {@inheritDoc}
- */
+ @Override
public SecurityContext getSecurityContext() {
- // TODO
- return new ElytronSecurityContext();
+ return this.securityContext.get();
}
- /**
- * {@inheritDoc}
- */
+ @Override
public void setSecurityContext(SecurityContext context) {
- if (context == null) {
- // TODO
- }
- assert context instanceof ElytronSecurityContext;
- // TODO
+ this.securityContext.set(context);
}
- /**
- * {@inheritDoc}
- */
+ @Override
public CallbackHandler createCallbackHandler() {
- return new ElytronCallbackHandler();
+ // we need a Callback to retrieve the Elytron security domain that will be used by the CallbackHandler.
+ throw new UnsupportedOperationException();
}
- /**
- * {@inheritDoc}
- */
+ @Override
public CallbackHandler createCallbackHandler(Callback callback) {
- return new ElytronCallbackHandler(callback);
+ if (callback != null) {
+ // TODO switch to use the elytron security domain once the callback has that info available.
+ final String securityDomainName = callback.getDomain();
+ // get domain reference from the service container and create the callback handler using the domain.
+ if (securityDomainName != null) {
+ final ServiceContainer container = this.currentServiceContainer();
+ final ServiceName securityDomainServiceName = SECURITY_DOMAIN_RUNTIME_CAPABILITY.getCapabilityServiceName(securityDomainName);
+ final SecurityDomain securityDomain = (SecurityDomain) container.getRequiredService(securityDomainServiceName).getValue();
+ return new ElytronCallbackHandler(securityDomain, callback);
+ }
+ }
+ // TODO use subsystem logger for the exception.
+ throw new IllegalArgumentException("Supplied Callback must be non null and must contain an Elytron security domain reference");
}
+ /**
+ * Get a reference to the current {@link ServiceContainer}.
+ *
+ * @return a reference to the current {@link ServiceContainer}.
+ */
+ private ServiceContainer currentServiceContainer() {
+ if(WildFlySecurityManager.isChecking()) {
+ return AccessController.doPrivileged(CurrentServiceContainer.GET_ACTION);
+ }
+ return CurrentServiceContainer.getServiceContainer();
+ }
}
diff --git a/connector/src/main/java/org/jboss/as/connector/security/ElytronSubjectFactory.java b/connector/src/main/java/org/jboss/as/connector/security/ElytronSubjectFactory.java
index 47270b8d6341..e52f7b296004 100644
--- a/connector/src/main/java/org/jboss/as/connector/security/ElytronSubjectFactory.java
+++ b/connector/src/main/java/org/jboss/as/connector/security/ElytronSubjectFactory.java
@@ -15,31 +15,82 @@
*/
package org.jboss.as.connector.security;
+import org.jboss.as.controller.capability.RuntimeCapability;
+import org.jboss.as.server.CurrentServiceContainer;
import org.jboss.jca.core.spi.security.SubjectFactory;
+import org.jboss.msc.service.ServiceContainer;
+import org.jboss.msc.service.ServiceName;
+import org.wildfly.security.auth.client.AuthenticationConfiguration;
+import org.wildfly.security.auth.client.AuthenticationContext;
+import org.wildfly.security.auth.client.AuthenticationContextConfigurationClient;
+import org.wildfly.security.auth.principal.NamePrincipal;
+import org.wildfly.security.manager.WildFlySecurityManager;
+import javax.resource.spi.security.PasswordCredential;
import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
import static org.jboss.as.connector.logging.ConnectorLogger.ROOT_LOGGER;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
/**
- * SubjectFactory implementation for Elytron.
+ * An Elytron based {@link SubjectFactory} implementation. It uses an {@link AuthenticationContext} to select a configuration
+ * that matches the resource {@link URI} to obtain the username and password pair that will be inserted into the constructed
+ * {@link Subject} instance.
*
* @author Flavia Rainone
+ * @author Stefan Guilhen
*/
public class ElytronSubjectFactory implements SubjectFactory {
+ private static final String AUTHENTICATION_CONTEXT_CAPABILITY = "org.wildfly.security.authentication-context";
+
+ private static final RuntimeCapability AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY = RuntimeCapability
+ .Builder.of(AUTHENTICATION_CONTEXT_CAPABILITY, true, AuthenticationContext.class)
+ .build();
+
+ private static final AuthenticationContextConfigurationClient AUTH_CONFIG_CLIENT =
+ AccessController.doPrivileged(AuthenticationContextConfigurationClient.ACTION);
+
+ private URI targetURI;
+
/**
* Constructor
*/
public ElytronSubjectFactory() {
+ this(null);
+ }
+ /**
+ * Constructor.
+ *
+ * @param targetURI the {@link URI} of the target.
+ */
+ public ElytronSubjectFactory(final URI targetURI) {
+ if (targetURI == null) {
+ try {
+ // TODO remove this - used for testing only
+ this.targetURI = new URI("jdbc://localhost");
+ } catch(URISyntaxException e) {}
+ }
+ this.targetURI = targetURI;
}
/**
* {@inheritDoc}
*/
public Subject createSubject() {
- Subject subject = null; // TODO
+ // no authentication configuration name has been supplied - capture the current configuration.
+ final Subject subject = this.createSubject(AuthenticationContext.captureCurrent());
if (ROOT_LOGGER.isTraceEnabled()) {
ROOT_LOGGER.subject(subject, Integer.toHexString(System.identityHashCode(subject)));
}
@@ -49,15 +100,78 @@ public Subject createSubject() {
/**
* {@inheritDoc}
*/
- public Subject createSubject(String authenticationContext) {
- Subject subject = null; // TODO
-
+ public Subject createSubject(final String authenticationContextName) {
+ AuthenticationContext context;
+ if (authenticationContextName != null && !authenticationContextName.isEmpty()) {
+ final ServiceContainer container = this.currentServiceContainer();
+ final ServiceName authContextServiceName = AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(authenticationContextName);
+ context = (AuthenticationContext) container.getRequiredService(authContextServiceName).getValue();
+ }
+ else {
+ context = AuthenticationContext.captureCurrent();
+ }
+ final Subject subject = this.createSubject(context);
if (ROOT_LOGGER.isTraceEnabled()) {
ROOT_LOGGER.subject(subject, Integer.toHexString(System.identityHashCode(subject)));
}
return subject;
}
+ /**
+ * Create a {@link Subject} with the principal and password credential obtained from the authentication configuration
+ * that matches the target {@link URI}.
+ *
+ * @param authenticationContext the {@link AuthenticationContext} used to select a configuration that matches the
+ * target {@link URI}.
+ * @return the constructed {@link Subject}. It contains a single principal and a {@link PasswordCredential}.
+ */
+ private Subject createSubject(final AuthenticationContext authenticationContext) {
+ final AuthenticationConfiguration configuration = AUTH_CONFIG_CLIENT.getAuthenticationConfiguration(this.targetURI, authenticationContext);
+ final CallbackHandler handler = AUTH_CONFIG_CLIENT.getCallbackHandler(configuration);
+ final NameCallback nameCallback = new NameCallback("Username: ");
+ final PasswordCallback passwordCallback = new PasswordCallback("Password: ", false);
+ try {
+ handler.handle(new Callback[]{nameCallback, passwordCallback});
+ Subject subject = new Subject();
+ subject.getPrincipals().add(new NamePrincipal(nameCallback.getName()));
+ // add the password as a private credential in the Subject.
+ this.addPrivateCredential(subject, new PasswordCredential(nameCallback.getName(), passwordCallback.getPassword()));
+ return subject;
+ } catch(IOException | UnsupportedCallbackException e) {
+ throw new SecurityException(e);
+ }
+ }
+
+ /**
+ * Get a reference to the current {@link ServiceContainer}.
+ *
+ * @return a reference to the current {@link ServiceContainer}.
+ */
+ private ServiceContainer currentServiceContainer() {
+ if(WildFlySecurityManager.isChecking()) {
+ return AccessController.doPrivileged(CurrentServiceContainer.GET_ACTION);
+ }
+ return CurrentServiceContainer.getServiceContainer();
+ }
+
+ /**
+ * Add the specified credential to the subject's private credentials set.
+ *
+ * @param subject the {@link Subject} to add the credential to.
+ * @param credential a reference to the credential.
+ */
+ private void addPrivateCredential(final Subject subject, final Object credential) {
+ if (!WildFlySecurityManager.isChecking()) {
+ subject.getPrivateCredentials().add(credential);
+ }
+ else {
+ AccessController.doPrivileged((PrivilegedAction) () -> {
+ subject.getPrivateCredentials().add(credential);
+ return null;
+ });
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/connector/src/main/java/org/jboss/as/connector/services/resourceadapters/deployment/AbstractResourceAdapterDeploymentService.java b/connector/src/main/java/org/jboss/as/connector/services/resourceadapters/deployment/AbstractResourceAdapterDeploymentService.java
index a3c375cd2762..4083a46bbd0d 100644
--- a/connector/src/main/java/org/jboss/as/connector/services/resourceadapters/deployment/AbstractResourceAdapterDeploymentService.java
+++ b/connector/src/main/java/org/jboss/as/connector/services/resourceadapters/deployment/AbstractResourceAdapterDeploymentService.java
@@ -28,6 +28,7 @@
import java.io.File;
import java.io.PrintWriter;
+import java.net.URISyntaxException;
import java.net.URL;
import java.security.PrivilegedAction;
import java.util.List;
@@ -623,7 +624,11 @@ protected org.jboss.jca.core.spi.security.SubjectFactory getSubjectFactory(
assert securityMetadata instanceof SecurityMetadata;
final String securityDomain = securityMetadata.resolveSecurityDomain();
if (((SecurityMetadata)securityMetadata).isElytronEnabled()) {
- return new ElytronSubjectFactory();
+ try {
+ return new ElytronSubjectFactory(this.url.toURI());
+ } catch (URISyntaxException e) {
+ throw ConnectorLogger.ROOT_LOGGER.cannotDeploy(e);
+ }
} else if (securityDomain == null || securityDomain.trim().equals("")) {
return null;
} else {
diff --git a/connector/src/main/java/org/jboss/as/connector/subsystems/datasources/AbstractDataSourceService.java b/connector/src/main/java/org/jboss/as/connector/subsystems/datasources/AbstractDataSourceService.java
index 794f0a3c7e52..8c8c9070bcb6 100644
--- a/connector/src/main/java/org/jboss/as/connector/subsystems/datasources/AbstractDataSourceService.java
+++ b/connector/src/main/java/org/jboss/as/connector/subsystems/datasources/AbstractDataSourceService.java
@@ -27,6 +27,7 @@
import static org.jboss.as.connector.logging.ConnectorLogger.DS_DEPLOYER_LOGGER;
import java.net.MalformedURLException;
+import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Driver;
import java.util.ArrayList;
@@ -438,7 +439,11 @@ protected org.jboss.jca.core.spi.security.SubjectFactory getSubjectFactory(
assert credential instanceof Credential;
final String securityDomain = credential.getSecurityDomain();
if (((Credential) credential).isElytronEnabled()) {
- return new ElytronSubjectFactory();
+ try {
+ return new ElytronSubjectFactory(new java.net.URI(this.dataSourceConfig.getConnectionUrl()));
+ } catch (URISyntaxException e) {
+ throw ConnectorLogger.ROOT_LOGGER.cannotDeploy(e);
+ }
} else if (securityDomain == null || securityDomain.trim().equals("") || subjectFactory.getOptionalValue() == null) {
return null;
} else {
diff --git a/pom.xml b/pom.xml
index 77f1b11a2f50..0f38b41cdedc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -161,7 +161,7 @@
2.2.0.Final
2.0.0.Alpha1
1.0.0.Final
- 1.4.0.Final
+ 1.4.1-SNAPSHOT
7.5.0.Final
10.0.0.Final
5.5.0.Final