All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.authz.jacc.JaccDelegatingPolicy Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.wildfly.security.authz.jacc;

import org.wildfly.common.Assert;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.authz.Roles;

import javax.security.jacc.EJBMethodPermission;
import javax.security.jacc.EJBRoleRefPermission;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.security.jacc.WebUserDataPermission;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static java.lang.System.getSecurityManager;
import static java.security.AccessController.doPrivileged;
import static org.wildfly.security.authz.jacc.ElytronMessages.log;

/**
 * 

A {@link Policy} implementation that knows how to process JACC permissions. * *

Elytron's JACC implementation is fully integrated with the Permission Mapping API, which allows users to specify custom permissions * for a {@link SecurityDomain} and its identities by configuring a {@link org.wildfly.security.authz.PermissionMapper}. In this case, * the permissions are evaluated considering both JACC-specific permissions (as defined by the specs) and also the ones associated with the current * and authorized {@link SecurityIdentity}. * * @author Pedro Igor */ public class JaccDelegatingPolicy extends Policy { private static final PrivilegedAction GET_POLICY_ACTION = Policy::getPolicy; private static final String ANY_AUTHENTICATED_USER_ROLE = "**"; private final Policy delegate; private final Set> supportedPermissionTypes = new HashSet<>(); /** * Create a new instance. In this case, the current policy will be automatically obtained and used to delegate method * calls. */ public JaccDelegatingPolicy() { this(getSecurityManager() != null ? doPrivileged(GET_POLICY_ACTION) : Policy.getPolicy()); } /** * Create a new instance based on the given {@code delegate}. * * @param delegate the policy that will be used to delegate method calls */ public JaccDelegatingPolicy(Policy delegate) { this.delegate = Assert.checkNotNullParam("delegate", delegate); this.supportedPermissionTypes.add(WebResourcePermission.class); this.supportedPermissionTypes.add(WebRoleRefPermission.class); this.supportedPermissionTypes.add(WebUserDataPermission.class); this.supportedPermissionTypes.add(EJBMethodPermission.class); this.supportedPermissionTypes.add(EJBRoleRefPermission.class); } @Override public boolean implies(ProtectionDomain domain, Permission permission) { try { if (isJaccPermission(permission)) { ElytronPolicyConfiguration policyConfiguration = ElytronPolicyConfigurationFactory.getCurrentPolicyConfiguration(); if (impliesExcludedPermission(permission, policyConfiguration)) { return false; } if (impliesUncheckedPermission(permission, policyConfiguration)) { return true; } if (impliesRolePermission(domain, permission, policyConfiguration)) { return true; } // Here we check the permissions mapped to the current identity. // We only perform this check for JACC permissions otherwise we intercept all // SecurityManager checks. if (impliesIdentityPermission(permission)) { return true; } } } catch (Exception e) { log.authzFailedToCheckPermission(domain, permission, e); } return this.delegate.implies(domain, permission); } @Override public PermissionCollection getPermissions(ProtectionDomain domain) { final PermissionCollection delegatePermissions = delegate.getPermissions(domain); return new PermissionCollection() { @Override public void add(Permission permission) { if (isJaccPermission(permission)) { throw ElytronMessages.log.readOnlyPermissionCollection(); } else { delegatePermissions.add(permission); } } @Override public boolean implies(Permission permission) { if (!isJaccPermission(permission) && delegatePermissions.implies(permission)) { return true; } return JaccDelegatingPolicy.this.implies(domain, permission); } @Override public Enumeration elements() { return delegatePermissions.elements(); } }; } @Override public PermissionCollection getPermissions(CodeSource codeSource) { return codeSource == null ? Policy.UNSUPPORTED_EMPTY_COLLECTION : getPermissions(new ProtectionDomain(codeSource, null)); } @Override public void refresh() { //TODO: we can probably provide some caching for permissions and checks. In this case, we can use this method to refresh the cache. this.delegate.refresh(); } private boolean impliesIdentityPermission(Permission permission) { SecurityIdentity actualIdentity = getCurrentSecurityIdentity(); return actualIdentity != null && actualIdentity.implies(permission); } private SecurityIdentity getCurrentSecurityIdentity() { try { return (SecurityIdentity) PolicyContext.getContext(SecurityIdentityHandler.KEY); } catch (Exception cause) { log.authzCouldNotObtainSecurityIdentity(cause); } return null; } private void extractRolesFromCurrentIdentity(Set roles) throws PolicyContextException, ClassNotFoundException { SecurityIdentity identity = getCurrentSecurityIdentity(); if (identity != null) { Roles identityRoles = identity.getRoles(); if (identityRoles != null) { for (String roleName : identityRoles) { roles.add(roleName); } } } } private void extractRolesFromProtectionDomain(ProtectionDomain domain, Set roles) { Principal[] domainPrincipals = domain.getPrincipals(); if (domainPrincipals != null) { for (Principal principal : domainPrincipals) { roles.add(principal.getName()); } } } private boolean impliesRolePermission(ProtectionDomain domain, Permission permission, ElytronPolicyConfiguration policyConfiguration) throws PolicyContextException, ClassNotFoundException { Set roles = new HashSet<>(); // keep JACC behavior where roles are obtained as Principal instances from a ProtectionDomain extractRolesFromProtectionDomain(domain, roles); // obtain additional roles from the current authenticated identity. // in this case the a RoleMapper will be used to map roles from the authenticated identity extractRolesFromCurrentIdentity(roles); roles.add(ANY_AUTHENTICATED_USER_ROLE); Map rolePermissions = policyConfiguration.getRolePermissions(); synchronized (rolePermissions) { for (String roleName : roles) { Permissions permissions = rolePermissions.get(roleName); if (permissions != null) { if (permissions.implies(permission)) { return true; } } } } return false; } private boolean impliesUncheckedPermission(Permission permission, ElytronPolicyConfiguration policyConfiguration) { Permissions uncheckedPermissions = policyConfiguration.getUncheckedPermissions(); synchronized (uncheckedPermissions) { return uncheckedPermissions.implies(permission); } } private boolean impliesExcludedPermission(Permission permission, ElytronPolicyConfiguration policyConfiguration) { Permissions excludedPermissions = policyConfiguration.getExcludedPermissions(); synchronized (excludedPermissions) { return excludedPermissions.implies(permission); } } private boolean isJaccPermission(Permission permission) { return this.supportedPermissionTypes.contains(permission.getClass()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy