/* * 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 javax.security.jacc.PolicyConfiguration; import javax.security.jacc.PolicyContextException; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import static org.wildfly.common.Assert.checkNotNullParam; import static org.wildfly.security._private.ElytronMessages.log; /** * {@link javax.security.jacc.PolicyConfiguration} implementation. * * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @see org.wildfly.security.authz.jacc.ElytronPolicyConfigurationFactory */ class ElytronPolicyConfiguration implements PolicyConfiguration { /** * An enum with all the possible states accordingly with the specification. */ enum State { OPEN, IN_SERVICE, DELETED } private final String contextId; private final Map<String, Permissions> rolePermissions = Collections.synchronizedMap(new HashMap<>()); private State state = State.OPEN; private Permissions uncheckedPermissions = new Permissions(); private Permissions excludedPermissions = new Permissions(); private Set<PolicyConfiguration> linkedPolicies = Collections.synchronizedSet(new LinkedHashSet<>()); ElytronPolicyConfiguration(String contextID) { checkNotNullParam("contextID", contextID); this.contextId = contextID; } @Override public void addToExcludedPolicy(Permission permission) throws PolicyContextException { checkNotNullParam("permission", permission); synchronized (this) { checkIfInOpenState(); this.excludedPermissions.add(permission); } } @Override public void addToExcludedPolicy(PermissionCollection permissions) throws PolicyContextException { checkNotNullParam("permissions", permissions); Enumeration<Permission> elements = permissions.elements(); while (elements.hasMoreElements()) { addToExcludedPolicy(elements.nextElement()); } } @Override public void addToRole(String roleName, Permission permission) throws PolicyContextException { checkNotNullParam("roleName", roleName); checkNotNullParam("permission", permission); synchronized (this) { checkIfInOpenState(); this.rolePermissions.computeIfAbsent(roleName, s -> new Permissions()).add(permission); } } @Override public void addToRole(String roleName, PermissionCollection permissions) throws PolicyContextException { checkNotNullParam("roleName", roleName); checkNotNullParam("permissions", permissions); Enumeration<Permission> elements = permissions.elements(); while (elements.hasMoreElements()) { addToRole(roleName, elements.nextElement()); } } @Override public void addToUncheckedPolicy(Permission permission) throws PolicyContextException { checkNotNullParam("permission", permission); synchronized (this) { checkIfInOpenState(); this.uncheckedPermissions.add(permission); } } @Override public void addToUncheckedPolicy(PermissionCollection permissions) throws PolicyContextException { checkNotNullParam("permissions", permissions); Enumeration<Permission> elements = permissions.elements(); while (elements.hasMoreElements()) { addToUncheckedPolicy(elements.nextElement()); } } @Override public void commit() throws PolicyContextException { synchronized (this) { if (isDeleted()) { throw log.authzInvalidStateForOperation(this.state.name()); } transitionTo(State.IN_SERVICE); } } @Override public void delete() throws PolicyContextException { synchronized (this) { transitionTo(State.DELETED); this.uncheckedPermissions = new Permissions(); this.excludedPermissions = new Permissions(); this.rolePermissions.clear(); this.linkedPolicies.remove(this); } } @Override public String getContextID() throws PolicyContextException { return this.contextId; } @Override public boolean inService() { synchronized (this) { return State.IN_SERVICE.equals(this.state); } } @Override public void linkConfiguration(PolicyConfiguration link) throws PolicyContextException { checkNotNullParam("link", link); synchronized (this) { checkIfInOpenState(); if (getContextID().equals(link.getContextID())) { throw log.authzLinkSamePolicyConfiguration(getContextID()); } this.linkedPolicies.add(this); if (!this.linkedPolicies.add(link)) { return; } ElytronPolicyConfiguration linkedPolicyConfiguration = (ElytronPolicyConfiguration) link; linkedPolicyConfiguration.linkConfiguration(this); // policies share the same set of linked policies, so we can remove policies from the set when they are deleted. this.linkedPolicies = linkedPolicyConfiguration.getLinkedPolicies(); } } @Override public void removeExcludedPolicy() throws PolicyContextException { synchronized (this) { checkIfInOpenState(); this.excludedPermissions = new Permissions(); } } @Override public void removeRole(String roleName) throws PolicyContextException { checkNotNullParam("roleName", roleName); checkNotNullParam("roleName", roleName); synchronized (this) { checkIfInOpenState(); this.rolePermissions.remove(roleName); } } @Override public void removeUncheckedPolicy() throws PolicyContextException { synchronized (this) { checkIfInOpenState(); this.uncheckedPermissions = new Permissions(); } } Set<PolicyConfiguration> getLinkedPolicies() { return this.linkedPolicies; } Permissions getUncheckedPermissions() { return this.uncheckedPermissions; } Permissions getExcludedPermissions() { return this.excludedPermissions; } Map<String, Permissions> getRolePermissions() { return this.rolePermissions; } void transitionTo(State state) { this.state = state; } private void checkIfInOpenState() { if (!State.OPEN.equals(this.state)) { throw log.authzInvalidStateForOperation(this.state.name()); } } private boolean isDeleted() { return State.DELETED.equals(this.state); } }