Skip to content

Commit

Permalink
[WFLY-8227] Ensure principalVsRolesMap always gets processed when usi…
Browse files Browse the repository at this point in the history
…ng Elytron regardless of whether or not JACC is enabled
  • Loading branch information
fjuma committed Feb 24, 2017
1 parent 14f5e2e commit 38f8f59
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public static final class View {
public static final int USER_APP_SPECIFIC_CONTAINER_INTERCEPTORS = 0x249;
public static final int SECURITY_CONTEXT = 0x250;
public static final int POLICY_CONTEXT = 0x260;
public static final int SECURITY_ROLES = 0x270;
public static final int EJB_SECURITY_AUTHORIZATION_INTERCEPTOR = 0x300;
public static final int RUN_AS_PRINCIPAL = 0x310;
public static final int EXTRA_PRINCIPAL_ROLES = 0x320;
Expand Down
18 changes: 13 additions & 5 deletions ejb3/src/main/java/org/jboss/as/ejb3/component/EJBComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,11 @@ public boolean isCallerInRole(final String roleName) throws IllegalStateExceptio
if (isSecurityDomainKnown()) {
if (enableJacc) {
Policy policy = WildFlySecurityManager.isChecking() ? doPrivileged((PrivilegedAction<Policy>) Policy::getPolicy) : Policy.getPolicy();
ProtectionDomain domain = new ProtectionDomain(null, null, null, JaccInterceptor.getGrantedRoles(this));
if (policy.implies(domain, new EJBRoleRefPermission(getComponentName(), roleName))) {
return true;
}
ProtectionDomain domain = new ProtectionDomain(null, null, null, JaccInterceptor.getGrantedRoles(getCallerSecurityIdentity()));
return policy.implies(domain, new EJBRoleRefPermission(getComponentName(), roleName));
} else {
return checkCallerSecurityIdentityRole(roleName);
}
return false;
} else if (WildFlySecurityManager.isChecking()) {
return WildFlySecurityManager.doUnchecked((PrivilegedAction<Boolean>) () -> serverSecurityManager.isCallerInRole(getComponentName(), policyContextID, securityMetaData.getSecurityRoles(), securityMetaData.getSecurityRoleLinks(), roleName));
} else {
Expand Down Expand Up @@ -610,6 +609,15 @@ protected ShutDownInterceptorFactory getShutDownInterceptorFactory() {
return shutDownInterceptorFactory;
}

private boolean checkCallerSecurityIdentityRole(String roleName) {
final SecurityIdentity identity = getCallerSecurityIdentity();
return "**".equals(roleName) ? ! identity.isAnonymous() : identity.getRoles("ejb", true).contains(roleName);
}

private SecurityIdentity getCallerSecurityIdentity() {
return (incomingRunAsIdentity == null) ? securityDomain.getCurrentSecurityIdentity() : incomingRunAsIdentity;
}

public EJBSuspendHandlerService getEjbSuspendHandlerService() {
return this.ejbSuspendHandlerService;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import org.jboss.as.ejb3.security.RunAsPrincipalInterceptor;
import org.jboss.as.ejb3.security.SecurityContextInterceptorFactory;
import org.jboss.as.ejb3.security.SecurityDomainInterceptorFactory;
import org.jboss.as.ejb3.security.SecurityRolesAddingInterceptor;
import org.jboss.as.ejb3.subsystem.ApplicationSecurityDomainDefinition;
import org.jboss.as.ejb3.subsystem.ApplicationSecurityDomainService.ApplicationSecurityDomain;
import org.jboss.as.ejb3.suspend.EJBSuspendHandlerService;
Expand Down Expand Up @@ -1145,6 +1146,13 @@ public HashMap<Integer, InterceptorFactory> getElytronInterceptorFactories(Strin
interceptorFactories.put(InterceptorOrder.View.POLICY_CONTEXT, new ImmediateInterceptorFactory(new PolicyContextIdInterceptor(policyContextID)));
}

if (securityRoles != null) {
final Map<String, Set<String>> principalVsRolesMap = securityRoles.getPrincipalVersusRolesMap();
if (! principalVsRolesMap.isEmpty()) {
interceptorFactories.put(InterceptorOrder.View.SECURITY_ROLES, new ImmediateInterceptorFactory(new SecurityRolesAddingInterceptor("ejb", principalVsRolesMap)));
}
}

// Next interceptor: run-as-principal
// Switch users if there's a run-as principal
if (runAsPrincipal != null) {
Expand Down
42 changes: 12 additions & 30 deletions ejb3/src/main/java/org/jboss/as/ejb3/security/JaccInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

Expand All @@ -48,7 +46,8 @@
import org.jboss.invocation.Interceptor;
import org.jboss.invocation.InterceptorContext;
import org.jboss.metadata.ejb.spec.MethodInterfaceType;
import org.jboss.metadata.javaee.spec.SecurityRolesMetaData;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.manager.WildFlySecurityManager;

Expand All @@ -68,6 +67,9 @@ public JaccInterceptor(String viewClassName, Method viewMethod) {
@Override
public Object processInvocation(InterceptorContext context) throws Exception {
Component component = context.getPrivateData(Component.class);
final SecurityDomain securityDomain = context.getPrivateData(SecurityDomain.class);
Assert.checkNotNullParam("securityDomain", securityDomain);
final SecurityIdentity currentIdentity = securityDomain.getCurrentSecurityIdentity();

if (component instanceof EJBComponent == false) {
throw EjbLogger.ROOT_LOGGER.unexpectedComponent(component, EJBComponent.class);
Expand All @@ -87,14 +89,14 @@ public Object processInvocation(InterceptorContext context) throws Exception {
if(WildFlySecurityManager.isChecking()) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
hasPermission(ejbComponent, componentView, invokedMethod);
hasPermission(ejbComponent, componentView, invokedMethod, currentIdentity);
return null;
});
} catch (PrivilegedActionException e) {
throw e.getException();
}
} else {
hasPermission(ejbComponent, componentView, invokedMethod);
hasPermission(ejbComponent, componentView, invokedMethod, currentIdentity);
}

// successful authorization, let the invocation proceed
Expand All @@ -105,10 +107,10 @@ private EJBMethodPermission createEjbMethodPermission(Method invokedMethod, EJBC
return new EJBMethodPermission(ejbComponent.getComponentName(), methodIntfType.name(), invokedMethod);
}

private void hasPermission(EJBComponent ejbComponent, ComponentView componentView, Method method) {
private void hasPermission(EJBComponent ejbComponent, ComponentView componentView, Method method, SecurityIdentity securityIdentity) {
MethodInterfaceType methodIntfType = getMethodInterfaceType(componentView.getPrivateData(MethodIntf.class));
EJBMethodPermission permission = createEjbMethodPermission(method, ejbComponent, methodIntfType);
ProtectionDomain domain = new ProtectionDomain (componentView.getProxyClass().getProtectionDomain().getCodeSource(), null, null, getGrantedRoles(ejbComponent));
ProtectionDomain domain = new ProtectionDomain (componentView.getProxyClass().getProtectionDomain().getCodeSource(), null, null, getGrantedRoles(securityIdentity));
Policy policy = WildFlySecurityManager.isChecking() ? doPrivileged((PrivilegedAction<Policy>) Policy::getPolicy) : Policy.getPolicy();
if (!policy.implies(domain, permission)) {
throw EjbLogger.ROOT_LOGGER.invocationOfMethodNotAllowed(method,ejbComponent.getComponentName());
Expand Down Expand Up @@ -149,33 +151,13 @@ protected MethodInterfaceType getMethodInterfaceType(MethodIntf viewType) {
* invoking the EJB. This method will check performs checks against run as identities in order to
* resolve the correct set of roles to be granted.
*
* @param ejbComponent the ejb component
* @param securityIdentity the identity invoking the EJB
* @return an array of {@link Principal} representing the roles associated with the identity
*/
public static Principal[] getGrantedRoles(EJBComponent ejbComponent) {
EJBSecurityMetaData securityMetaData = ejbComponent.getSecurityMetaData();

if (securityMetaData == null) {
return new Principal[] {};
}

public static Principal[] getGrantedRoles(SecurityIdentity securityIdentity) {
Set<String> roles = new HashSet<>();

SecurityIdentity identity = ejbComponent.getIncomingRunAsIdentity();

if (identity == null) {
identity = ejbComponent.getSecurityDomain().getCurrentSecurityIdentity();
}

identity.getRoles("ejb").forEach(roles::add);

SecurityRolesMetaData securityRoles = securityMetaData.getSecurityRoles();

if (securityRoles != null && securityRoles.getPrincipalVersusRolesMap() != null) {
Map<String, Set<String>> principalVersusRolesMap = securityRoles.getPrincipalVersusRolesMap();
roles.addAll(principalVersusRolesMap.getOrDefault(identity.getPrincipal().getName(), Collections.emptySet()));
}

securityIdentity.getRoles("ejb").forEach(roles::add);
return roles.stream().map((Function<String, Principal>) roleName -> (Principal) () -> roleName).toArray(Principal[]::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.ejb3.security;

import java.util.Map;
import java.util.Set;

import org.jboss.invocation.Interceptor;
import org.jboss.invocation.InterceptorContext;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.authz.RoleMapper;
import org.wildfly.security.authz.Roles;

/**
* @author <a href="mailto:fjuma@redhat.com">Farah Juma</a>
*/
public class SecurityRolesAddingInterceptor implements Interceptor {
private final String category;
private final Map<String, Set<String>> principalVsRolesMap;

public SecurityRolesAddingInterceptor(final String category, final Map<String,Set<String>> principalVsRolesMap) {
this.category = category;
this.principalVsRolesMap = principalVsRolesMap;
}

public Object processInvocation(final InterceptorContext context) throws Exception {
final SecurityDomain securityDomain = context.getPrivateData(SecurityDomain.class);
Assert.checkNotNullParam("securityDomain", securityDomain);
final SecurityIdentity currentIdentity = securityDomain.getCurrentSecurityIdentity();
final Set<String> securityRoles = principalVsRolesMap.get(currentIdentity.getPrincipal().getName());
if (securityRoles != null && ! securityRoles.isEmpty()) {
final RoleMapper roleMapper = RoleMapper.constant(Roles.fromSet(securityRoles));
final RoleMapper mergeMapper = roleMapper.or((roles) -> currentIdentity.getRoles(category));
final SecurityIdentity newIdentity = currentIdentity.withRoleMapper(category, mergeMapper);
return newIdentity.runAs(context);
} else {
return context.proceed();
}
}
}

0 comments on commit 38f8f59

Please sign in to comment.