Skip to content

Commit

Permalink
[WFLY-7764] - JACC integration to Undertow subsystem
Browse files Browse the repository at this point in the history
  • Loading branch information
pedroigor committed Feb 14, 2017
1 parent 99b86b5 commit 59d03be
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 61 deletions.
Expand Up @@ -32,6 +32,8 @@


import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.Permission;
import java.security.Policy;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
Expand All @@ -50,11 +52,14 @@
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors; import java.util.stream.Collectors;


import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
Expand Down Expand Up @@ -96,9 +101,11 @@
import org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler; import org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler;
import org.wildfly.elytron.web.undertow.server.ScopeSessionListener; import org.wildfly.elytron.web.undertow.server.ScopeSessionListener;
import org.wildfly.extension.undertow.logging.UndertowLogger; import org.wildfly.extension.undertow.logging.UndertowLogger;
import org.wildfly.extension.undertow.security.jacc.JACCAuthorizationManager;
import org.wildfly.extension.undertow.security.sso.DistributableApplicationSecurityDomainSingleSignOnManagerBuilder; import org.wildfly.extension.undertow.security.sso.DistributableApplicationSecurityDomainSingleSignOnManagerBuilder;
import org.wildfly.security.auth.server.HttpAuthenticationFactory; import org.wildfly.security.auth.server.HttpAuthenticationFactory;
import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.http.HttpAuthenticationException; import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpScope; import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.HttpScopeNotification; import org.wildfly.security.http.HttpScopeNotification;
Expand All @@ -113,6 +120,7 @@
import org.wildfly.security.http.util.sso.SingleSignOnSessionFactory; import org.wildfly.security.http.util.sso.SingleSignOnSessionFactory;
import org.wildfly.security.manager.WildFlySecurityManager; import org.wildfly.security.manager.WildFlySecurityManager;


import io.undertow.security.idm.Account;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.BlockingHandler; import io.undertow.server.handlers.BlockingHandler;
Expand All @@ -121,9 +129,13 @@
import io.undertow.server.session.SessionIdGenerator; import io.undertow.server.session.SessionIdGenerator;
import io.undertow.server.session.SessionManager; import io.undertow.server.session.SessionManager;
import io.undertow.servlet.api.AuthMethodConfig; import io.undertow.servlet.api.AuthMethodConfig;
import io.undertow.servlet.api.AuthorizationManager;
import io.undertow.servlet.api.Deployment; import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.LoginConfig; import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.ServletInfo;
import io.undertow.servlet.api.SingleConstraintMatch;
import io.undertow.servlet.core.DefaultAuthorizationManager;
import io.undertow.servlet.handlers.ServletRequestContext; import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.util.SavedRequest; import io.undertow.servlet.util.SavedRequest;


Expand All @@ -142,6 +154,7 @@ public class ApplicationSecurityDomainDefinition extends PersistentResourceDefin
.build(); .build();


private static final String HTTP_AUTHENITCATION_FACTORY_CAPABILITY = "org.wildfly.security.http-authentication-factory"; private static final String HTTP_AUTHENITCATION_FACTORY_CAPABILITY = "org.wildfly.security.http-authentication-factory";
private static final String JACC_POLICY_CAPABILITY = "org.wildfly.security.jacc-policy";


static final SimpleAttributeDefinition HTTP_AUTHENTICATION_FACTORY = new SimpleAttributeDefinitionBuilder(Constants.HTTP_AUTHENITCATION_FACTORY, ModelType.STRING, false) static final SimpleAttributeDefinition HTTP_AUTHENTICATION_FACTORY = new SimpleAttributeDefinitionBuilder(Constants.HTTP_AUTHENITCATION_FACTORY, ModelType.STRING, false)
.setMinSize(1) .setMinSize(1)
Expand All @@ -158,7 +171,13 @@ public class ApplicationSecurityDomainDefinition extends PersistentResourceDefin
.setStorageRuntime() .setStorageRuntime()
.build(); .build();


private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[] { HTTP_AUTHENTICATION_FACTORY, OVERRIDE_DEPLOYMENT_CONFIG }; static final SimpleAttributeDefinition ENABLE_JACC = new SimpleAttributeDefinitionBuilder(Constants.ENABLE_JACC, ModelType.BOOLEAN, true)
.setDefaultValue(new ModelNode(false))
.setMinSize(1)
.setRestartAllServices()
.build();

private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[] { HTTP_AUTHENTICATION_FACTORY, OVERRIDE_DEPLOYMENT_CONFIG, ENABLE_JACC };


static final ApplicationSecurityDomainDefinition INSTANCE = new ApplicationSecurityDomainDefinition(); static final ApplicationSecurityDomainDefinition INSTANCE = new ApplicationSecurityDomainDefinition();


Expand Down Expand Up @@ -232,19 +251,24 @@ protected void performRuntime(OperationContext context, ModelNode operation, Res


String httpServerMechanismFactory = HTTP_AUTHENTICATION_FACTORY.resolveModelAttribute(context, model).asString(); String httpServerMechanismFactory = HTTP_AUTHENTICATION_FACTORY.resolveModelAttribute(context, model).asString();
boolean overrideDeploymentConfig = OVERRIDE_DEPLOYMENT_CONFIG.resolveModelAttribute(context, model).asBoolean(); boolean overrideDeploymentConfig = OVERRIDE_DEPLOYMENT_CONFIG.resolveModelAttribute(context, model).asBoolean();
boolean enableJacc = ENABLE_JACC.resolveModelAttribute(context, model).asBoolean();


String securityDomainName = context.getCurrentAddressValue(); String securityDomainName = context.getCurrentAddressValue();
RuntimeCapability<?> runtimeCapability = APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.fromBaseCapability(securityDomainName); RuntimeCapability<?> runtimeCapability = APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.fromBaseCapability(securityDomainName);
ServiceName serviceName = runtimeCapability.getCapabilityServiceName(Function.class); ServiceName serviceName = runtimeCapability.getCapabilityServiceName(Function.class);


ApplicationSecurityDomainService applicationSecurityDomainService = new ApplicationSecurityDomainService(overrideDeploymentConfig); ApplicationSecurityDomainService applicationSecurityDomainService = new ApplicationSecurityDomainService(overrideDeploymentConfig, enableJacc);


ServiceBuilder<Function<DeploymentInfo, Registration>> serviceBuilder = target.addService(serviceName, applicationSecurityDomainService) ServiceBuilder<Function<DeploymentInfo, Registration>> serviceBuilder = target.addService(serviceName, applicationSecurityDomainService)
.setInitialMode(Mode.LAZY); .setInitialMode(Mode.LAZY);


serviceBuilder.addDependency(context.getCapabilityServiceName(HTTP_AUTHENITCATION_FACTORY_CAPABILITY, serviceBuilder.addDependency(context.getCapabilityServiceName(HTTP_AUTHENITCATION_FACTORY_CAPABILITY,
httpServerMechanismFactory, HttpAuthenticationFactory.class), HttpAuthenticationFactory.class, applicationSecurityDomainService.getHttpAuthenticationFactoryInjector()); httpServerMechanismFactory, HttpAuthenticationFactory.class), HttpAuthenticationFactory.class, applicationSecurityDomainService.getHttpAuthenticationFactoryInjector());


if (enableJacc) {
serviceBuilder.addDependency(ServiceBuilder.DependencyType.REQUIRED, context.getCapabilityServiceName(JACC_POLICY_CAPABILITY, Policy.class));
}

if (resource.hasChild(UndertowExtension.PATH_SSO)) { if (resource.hasChild(UndertowExtension.PATH_SSO)) {
ModelNode ssoModel = resource.getChild(UndertowExtension.PATH_SSO).getModel(); ModelNode ssoModel = resource.getChild(UndertowExtension.PATH_SSO).getModel();


Expand Down Expand Up @@ -322,12 +346,15 @@ private static class ApplicationSecurityDomainService implements Service<Functio
private final boolean overrideDeploymentConfig; private final boolean overrideDeploymentConfig;
private final InjectedValue<HttpAuthenticationFactory> httpAuthenticationFactoryInjector = new InjectedValue<>(); private final InjectedValue<HttpAuthenticationFactory> httpAuthenticationFactoryInjector = new InjectedValue<>();
private final InjectedValue<UnaryOperator<HttpServerAuthenticationMechanismFactory>> singleSignOnTransformer = new InjectedValue<>(); private final InjectedValue<UnaryOperator<HttpServerAuthenticationMechanismFactory>> singleSignOnTransformer = new InjectedValue<>();
private final InjectedValue<Policy> jaccPolicyInjector = new InjectedValue<>();
private final Set<RegistrationImpl> registrations = new HashSet<>(); private final Set<RegistrationImpl> registrations = new HashSet<>();
private final boolean enableJacc;


private HttpAuthenticationFactory httpAuthenticationFactory; private HttpAuthenticationFactory httpAuthenticationFactory;


private ApplicationSecurityDomainService(final boolean overrideDeploymentConfig) { private ApplicationSecurityDomainService(final boolean overrideDeploymentConfig, boolean enableJacc) {
this.overrideDeploymentConfig = overrideDeploymentConfig; this.overrideDeploymentConfig = overrideDeploymentConfig;
this.enableJacc = enableJacc;
} }


@Override @Override
Expand Down Expand Up @@ -371,6 +398,12 @@ private Registration applyElytronSecurity(final DeploymentInfo deploymentInfo) {
deploymentInfo.addInnerHandlerChainWrapper(this::finalSecurityHandlers); deploymentInfo.addInnerHandlerChainWrapper(this::finalSecurityHandlers);
deploymentInfo.setInitialSecurityWrapper(h -> initialSecurityHandler(deploymentInfo, h, scopeSessionListener)); deploymentInfo.setInitialSecurityWrapper(h -> initialSecurityHandler(deploymentInfo, h, scopeSessionListener));


if (enableJacc) {
deploymentInfo.setAuthorizationManager(new JACCAuthorizationManager());
} else {
deploymentInfo.setAuthorizationManager(createElytronAuthorizationManager());
}

RegistrationImpl registration = new RegistrationImpl(deploymentInfo); RegistrationImpl registration = new RegistrationImpl(deploymentInfo);
synchronized(registrations) { synchronized(registrations) {
registrations.add(registration); registrations.add(registration);
Expand Down Expand Up @@ -660,6 +693,54 @@ private HttpHandler finalSecurityHandlers(HttpHandler toWrap) {
return new BlockingHandler(new ElytronRunAsHandler(toWrap)); return new BlockingHandler(new ElytronRunAsHandler(toWrap));
} }


private AuthorizationManager createElytronAuthorizationManager() {
return new AuthorizationManager() {
@Override
public boolean isUserInRole(String roleName, Account account, ServletInfo servletInfo, HttpServletRequest request, Deployment deployment) {
return DefaultAuthorizationManager.INSTANCE.isUserInRole(roleName, account, servletInfo, request, deployment);
}

@Override
public boolean canAccessResource(List<SingleConstraintMatch> mappedConstraints, Account account, ServletInfo servletInfo, HttpServletRequest request, Deployment deployment) {
if (DefaultAuthorizationManager.INSTANCE.canAccessResource(mappedConstraints, account, servletInfo, request, deployment)) {
return true;
}

SecurityDomain securityDomain = httpAuthenticationFactory.getSecurityDomain();
SecurityIdentity securityIdentity = securityDomain.getCurrentSecurityIdentity();

if (securityIdentity == null) {
return false;
}

List<Permission> permissions = new ArrayList<>();

permissions.add(new WebResourcePermission(getCanonicalURI(request), request.getMethod()));
permissions.addAll(account.getRoles().stream().map((Function<String, Permission>) roleName -> new WebRoleRefPermission(getCanonicalURI(request), request.getMethod())).collect(Collectors.toList()));

for (Permission permission : permissions) {
if (securityIdentity.implies(permission)) {
return true;
}
}

return false;
}

@Override
public io.undertow.servlet.api.TransportGuaranteeType transportGuarantee(io.undertow.servlet.api.TransportGuaranteeType currentConnectionGuarantee, io.undertow.servlet.api.TransportGuaranteeType configuredRequiredGuarantee, HttpServletRequest request) {
return DefaultAuthorizationManager.INSTANCE.transportGuarantee(currentConnectionGuarantee, configuredRequiredGuarantee, request);
}

private String getCanonicalURI(HttpServletRequest request) {
String canonicalURI = request.getRequestURI().substring(request.getContextPath().length());
if (canonicalURI == null || canonicalURI.equals("/"))
canonicalURI = "";
return canonicalURI;
}
};
}

private String[] getDeployments() { private String[] getDeployments() {
synchronized(registrations) { synchronized(registrations) {
return registrations.stream().map(r -> r.deploymentInfo.getDeploymentName()).collect(Collectors.toList()).toArray(new String[registrations.size()]); return registrations.stream().map(r -> r.deploymentInfo.getDeploymentName()).collect(Collectors.toList()).toArray(new String[registrations.size()]);
Expand Down
Expand Up @@ -235,5 +235,6 @@ public interface Constants {
String OVERRIDE_DEPLOYMENT_CONFIG = "override-deployment-config"; String OVERRIDE_DEPLOYMENT_CONFIG = "override-deployment-config";
String REFERENCING_DEPLOYMENTS = "referencing-deployments"; String REFERENCING_DEPLOYMENTS = "referencing-deployments";
String SECURITY_DOMAIN = "security-domain"; String SECURITY_DOMAIN = "security-domain";
String ENABLE_JACC = "enable-jacc";


} }
Expand Up @@ -321,7 +321,7 @@ public class UndertowSubsystemParser_4_0 extends PersistentResourceXMLParser {
.addChild( .addChild(
builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement()) builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement())
.setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS) .setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS)
.addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG) .addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG, ApplicationSecurityDomainDefinition.ENABLE_JACC)
.addChild(builder(UndertowExtension.PATH_SSO) .addChild(builder(UndertowExtension.PATH_SSO)
.addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition())
.addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition())
Expand Down
Expand Up @@ -982,6 +982,10 @@ private DeploymentInfo createServletConfig() throws StartException {
Function<DeploymentInfo, Registration> securityFunction = this.securityFunction.getOptionalValue(); Function<DeploymentInfo, Registration> securityFunction = this.securityFunction.getOptionalValue();
if (securityFunction != null) { if (securityFunction != null) {
registration = securityFunction.apply(d); registration = securityFunction.apply(d);
d.addOuterHandlerChainWrapper(JACCContextIdHandler.wrapper(jaccContextId));
if(mergedMetaData.isUseJBossAuthorization()) {
UndertowLogger.ROOT_LOGGER.configurationOptionIgnoredWhenUsingElytron("use-jboss-authorization");
}
} else { } else {
if (securityDomain != null) { if (securityDomain != null) {
d.addThreadSetupAction(new SecurityContextThreadSetupAction(securityDomain, securityDomainContextValue.getValue(), principalVersusRolesMap)); d.addThreadSetupAction(new SecurityContextThreadSetupAction(securityDomain, securityDomainContextValue.getValue(), principalVersusRolesMap));
Expand Down
Expand Up @@ -383,4 +383,9 @@ public interface UndertowLogger extends BasicLogger {


@Message(id = 93, value = "Credential %s is not a clear text password") @Message(id = 93, value = "Credential %s is not a clear text password")
IllegalArgumentException credentialNotClearPassword(String alias); IllegalArgumentException credentialNotClearPassword(String alias);

@Message(id = 94, value = "Configuration option [%s] ignored when using Elytron subsystem")
@LogMessage(level = WARN)
void configurationOptionIgnoredWhenUsingElytron(String option);

} }

0 comments on commit 59d03be

Please sign in to comment.