| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.nifi.registry.security.authorization; |
| |
| import org.apache.nifi.registry.security.authorization.exception.AuthorizationAccessException; |
| import org.apache.nifi.registry.security.authorization.exception.UninheritableAuthorizationsException; |
| import org.apache.nifi.registry.security.exception.SecurityProviderCreationException; |
| import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.stream.XMLOutputFactory; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamWriter; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.StringWriter; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * An Authorizer that provides management of users, groups, and policies. |
| */ |
| public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer { |
| |
| static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); |
| static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance(); |
| |
| static final String USER_ELEMENT = "user"; |
| static final String GROUP_USER_ELEMENT = "groupUser"; |
| static final String GROUP_ELEMENT = "group"; |
| static final String POLICY_ELEMENT = "policy"; |
| static final String POLICY_USER_ELEMENT = "policyUser"; |
| static final String POLICY_GROUP_ELEMENT = "policyGroup"; |
| static final String IDENTIFIER_ATTR = "identifier"; |
| static final String IDENTITY_ATTR = "identity"; |
| static final String NAME_ATTR = "name"; |
| static final String RESOURCE_ATTR = "resource"; |
| static final String ACTIONS_ATTR = "actions"; |
| |
| @Override |
| public final void onConfigured(final AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException { |
| doOnConfigured(configurationContext); |
| } |
| |
| /** |
| * Allows sub-classes to take action when onConfigured is called. |
| * |
| * @param configurationContext the configuration context |
| * @throws SecurityProviderCreationException if an error occurs during onConfigured process |
| */ |
| protected abstract void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException; |
| |
| @Override |
| public final AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException { |
| final UsersAndAccessPolicies usersAndAccessPolicies = getUsersAndAccessPolicies(); |
| final String resourceIdentifier = request.getResource().getIdentifier(); |
| |
| final AccessPolicy policy = usersAndAccessPolicies.getAccessPolicy(resourceIdentifier, request.getAction()); |
| if (policy == null) { |
| return AuthorizationResult.resourceNotFound(); |
| } |
| |
| final User user = usersAndAccessPolicies.getUser(request.getIdentity()); |
| if (user == null) { |
| return AuthorizationResult.denied(String.format("Unknown user with identity '%s'.", request.getIdentity())); |
| } |
| |
| final Set<Group> userGroups = usersAndAccessPolicies.getGroups(user.getIdentity()); |
| if (policy.getUsers().contains(user.getIdentifier()) || containsGroup(userGroups, policy)) { |
| return AuthorizationResult.approved(); |
| } |
| |
| return AuthorizationResult.denied(request.getExplanationSupplier().get()); |
| } |
| |
| /** |
| * Determines if the policy contains one of the user's groups. |
| * |
| * @param userGroups the set of the user's groups |
| * @param policy the policy |
| * @return true if one of the Groups in userGroups is contained in the policy |
| */ |
| private boolean containsGroup(final Set<Group> userGroups, final AccessPolicy policy) { |
| if (userGroups.isEmpty() || policy.getGroups().isEmpty()) { |
| return false; |
| } |
| |
| for (Group userGroup : userGroups) { |
| if (policy.getGroups().contains(userGroup.getIdentifier())) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Adds a new group. |
| * |
| * @param group the Group to add |
| * @return the added Group |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| * @throws IllegalStateException if a group with the same name already exists |
| */ |
| public final synchronized Group addGroup(Group group) throws AuthorizationAccessException { |
| return doAddGroup(group); |
| } |
| |
| /** |
| * Adds a new group. |
| * |
| * @param group the Group to add |
| * @return the added Group |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Group doAddGroup(Group group) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves a Group by id. |
| * |
| * @param identifier the identifier of the Group to retrieve |
| * @return the Group with the given identifier, or null if no matching group was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Group getGroup(String identifier) throws AuthorizationAccessException; |
| |
| /** |
| * The group represented by the provided instance will be updated based on the provided instance. |
| * |
| * @param group an updated group instance |
| * @return the updated group instance, or null if no matching group was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| * @throws IllegalStateException if there is already a group with the same name |
| */ |
| public final synchronized Group updateGroup(Group group) throws AuthorizationAccessException { |
| return doUpdateGroup(group); |
| } |
| |
| /** |
| * The group represented by the provided instance will be updated based on the provided instance. |
| * |
| * @param group an updated group instance |
| * @return the updated group instance, or null if no matching group was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Group doUpdateGroup(Group group) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the given group. |
| * |
| * @param group the group to delete |
| * @return the deleted group, or null if no matching group was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Group deleteGroup(Group group) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the group with the given identifier. |
| * |
| * @param groupIdentifier the id of the group to delete |
| * @return the deleted group, or null if no matching group was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Group deleteGroup(String groupIdentifier) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves all groups. |
| * |
| * @return a list of groups |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Set<Group> getGroups() throws AuthorizationAccessException; |
| |
| |
| /** |
| * Adds the given user. |
| * |
| * @param user the user to add |
| * @return the user that was added |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| * @throws IllegalStateException if there is already a user with the same identity |
| */ |
| public final synchronized User addUser(User user) throws AuthorizationAccessException { |
| return doAddUser(user); |
| } |
| |
| /** |
| * Adds the given user. |
| * |
| * @param user the user to add |
| * @return the user that was added |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User doAddUser(User user) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves the user with the given identifier. |
| * |
| * @param identifier the id of the user to retrieve |
| * @return the user with the given id, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User getUser(String identifier) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves the user with the given identity. |
| * |
| * @param identity the identity of the user to retrieve |
| * @return the user with the given identity, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User getUserByIdentity(String identity) throws AuthorizationAccessException; |
| |
| /** |
| * The user represented by the provided instance will be updated based on the provided instance. |
| * |
| * @param user an updated user instance |
| * @return the updated user instance, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| * @throws IllegalStateException if there is already a user with the same identity |
| */ |
| public final synchronized User updateUser(final User user) throws AuthorizationAccessException { |
| return doUpdateUser(user); |
| } |
| |
| /** |
| * The user represented by the provided instance will be updated based on the provided instance. |
| * |
| * @param user an updated user instance |
| * @return the updated user instance, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User doUpdateUser(User user) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the given user. |
| * |
| * @param user the user to delete |
| * @return the user that was deleted, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User deleteUser(User user) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the user with the given id. |
| * |
| * @param userIdentifier the identifier of the user to delete |
| * @return the user that was deleted, or null if no matching user was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract User deleteUser(String userIdentifier) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves all users. |
| * |
| * @return a list of users |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Set<User> getUsers() throws AuthorizationAccessException; |
| |
| /** |
| * Adds the given policy ensuring that multiple policies can not be added for the same resource and action. |
| * |
| * @param accessPolicy the policy to add |
| * @return the policy that was added |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public final synchronized AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { |
| return doAddAccessPolicy(accessPolicy); |
| } |
| |
| /** |
| * Adds the given policy. |
| * |
| * @param accessPolicy the policy to add |
| * @return the policy that was added |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| protected abstract AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves the policy with the given identifier. |
| * |
| * @param identifier the id of the policy to retrieve |
| * @return the policy with the given id, or null if no matching policy exists |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException; |
| |
| /** |
| * The policy represented by the provided instance will be updated based on the provided instance. |
| * |
| * @param accessPolicy an updated policy |
| * @return the updated policy, or null if no matching policy was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the given policy. |
| * |
| * @param policy the policy to delete |
| * @return the deleted policy, or null if no matching policy was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract AccessPolicy deleteAccessPolicy(AccessPolicy policy) throws AuthorizationAccessException; |
| |
| /** |
| * Deletes the policy with the given id. |
| * |
| * @param policyIdentifier the id of the policy to delete |
| * @return the deleted policy, or null if no matching policy was found |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract AccessPolicy deleteAccessPolicy(String policyIdentifier) throws AuthorizationAccessException; |
| |
| /** |
| * Retrieves all access policies. |
| * |
| * @return a list of policies |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException; |
| |
| /** |
| * Returns the UserAccessPolicies instance. |
| * |
| * @return the UserAccessPolicies instance |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| */ |
| public abstract UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException; |
| |
| /** |
| * Returns whether the proposed fingerprint is inheritable. |
| * |
| * @param proposedFingerprint the proposed fingerprint |
| * @throws AuthorizationAccessException if there was an unexpected error performing the operation |
| * @throws UninheritableAuthorizationsException if the proposed fingerprint was uninheritable |
| */ |
| @Override |
| public final void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { |
| try { |
| // ensure we understand the proposed fingerprint |
| parsePoliciesUsersAndGroups(proposedFingerprint); |
| } catch (final AuthorizationAccessException e) { |
| throw new UninheritableAuthorizationsException("Unable to parse proposed fingerprint: " + e); |
| } |
| |
| final List<User> users = getSortedUsers(); |
| final List<Group> groups = getSortedGroups(); |
| final List<AccessPolicy> accessPolicies = getSortedAccessPolicies(); |
| |
| // ensure we're in a state to inherit |
| if (!users.isEmpty() || !groups.isEmpty() || !accessPolicies.isEmpty()) { |
| throw new UninheritableAuthorizationsException("Proposed fingerprint is not inheritable because the current Authorizations is not empty.."); |
| } |
| } |
| |
| /** |
| * Parses the fingerprint and adds any users, groups, and policies to the current Authorizer. |
| * |
| * @param fingerprint the fingerprint that was obtained from calling getFingerprint() on another Authorizer. |
| */ |
| @Override |
| public final void inheritFingerprint(final String fingerprint) throws AuthorizationAccessException { |
| if (fingerprint == null || fingerprint.trim().isEmpty()) { |
| return; |
| } |
| |
| final PoliciesUsersAndGroups policiesUsersAndGroups = parsePoliciesUsersAndGroups(fingerprint); |
| policiesUsersAndGroups.getUsers().forEach(user -> addUser(user)); |
| policiesUsersAndGroups.getGroups().forEach(group -> addGroup(group)); |
| policiesUsersAndGroups.getAccessPolicies().forEach(policy -> addAccessPolicy(policy)); |
| } |
| |
| private PoliciesUsersAndGroups parsePoliciesUsersAndGroups(final String fingerprint) { |
| final List<AccessPolicy> accessPolicies = new ArrayList<>(); |
| final List<User> users = new ArrayList<>(); |
| final List<Group> groups = new ArrayList<>(); |
| |
| final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8); |
| try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) { |
| final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder(); |
| final Document document = docBuilder.parse(in); |
| final Element rootElement = document.getDocumentElement(); |
| |
| // parse all the users and add them to the current authorizer |
| NodeList userNodes = rootElement.getElementsByTagName(USER_ELEMENT); |
| for (int i=0; i < userNodes.getLength(); i++) { |
| Node userNode = userNodes.item(i); |
| users.add(parseUser((Element) userNode)); |
| } |
| |
| // parse all the groups and add them to the current authorizer |
| NodeList groupNodes = rootElement.getElementsByTagName(GROUP_ELEMENT); |
| for (int i=0; i < groupNodes.getLength(); i++) { |
| Node groupNode = groupNodes.item(i); |
| groups.add(parseGroup((Element) groupNode)); |
| } |
| |
| // parse all the policies and add them to the current authorizer |
| NodeList policyNodes = rootElement.getElementsByTagName(POLICY_ELEMENT); |
| for (int i=0; i < policyNodes.getLength(); i++) { |
| Node policyNode = policyNodes.item(i); |
| accessPolicies.add(parsePolicy((Element) policyNode)); |
| } |
| } catch (SAXException | ParserConfigurationException | IOException e) { |
| throw new AuthorizationAccessException("Unable to parse fingerprint", e); |
| } |
| |
| return new PoliciesUsersAndGroups(accessPolicies, users, groups); |
| } |
| |
| private User parseUser(final Element element) { |
| final User.Builder builder = new User.Builder() |
| .identifier(element.getAttribute(IDENTIFIER_ATTR)) |
| .identity(element.getAttribute(IDENTITY_ATTR)); |
| |
| return builder.build(); |
| } |
| |
| private Group parseGroup(final Element element) { |
| final Group.Builder builder = new Group.Builder() |
| .identifier(element.getAttribute(IDENTIFIER_ATTR)) |
| .name(element.getAttribute(NAME_ATTR)); |
| |
| NodeList groupUsers = element.getElementsByTagName(GROUP_USER_ELEMENT); |
| for (int i=0; i < groupUsers.getLength(); i++) { |
| Element groupUserNode = (Element) groupUsers.item(i); |
| builder.addUser(groupUserNode.getAttribute(IDENTIFIER_ATTR)); |
| } |
| |
| return builder.build(); |
| } |
| |
| private AccessPolicy parsePolicy(final Element element) { |
| final AccessPolicy.Builder builder = new AccessPolicy.Builder() |
| .identifier(element.getAttribute(IDENTIFIER_ATTR)) |
| .resource(element.getAttribute(RESOURCE_ATTR)); |
| |
| final String actions = element.getAttribute(ACTIONS_ATTR); |
| if (actions.equals(RequestAction.READ.name())) { |
| builder.action(RequestAction.READ); |
| } else if (actions.equals(RequestAction.WRITE.name())) { |
| builder.action(RequestAction.WRITE); |
| } else if (actions.equals(RequestAction.DELETE.name())) { |
| builder.action(RequestAction.DELETE); |
| } else { |
| throw new IllegalStateException("Unknown Policy Action: " + actions); |
| } |
| |
| NodeList policyUsers = element.getElementsByTagName(POLICY_USER_ELEMENT); |
| for (int i=0; i < policyUsers.getLength(); i++) { |
| Element policyUserNode = (Element) policyUsers.item(i); |
| builder.addUser(policyUserNode.getAttribute(IDENTIFIER_ATTR)); |
| } |
| |
| NodeList policyGroups = element.getElementsByTagName(POLICY_GROUP_ELEMENT); |
| for (int i=0; i < policyGroups.getLength(); i++) { |
| Element policyGroupNode = (Element) policyGroups.item(i); |
| builder.addGroup(policyGroupNode.getAttribute(IDENTIFIER_ATTR)); |
| } |
| |
| return builder.build(); |
| } |
| |
| @Override |
| public final AccessPolicyProvider getAccessPolicyProvider() { |
| return new ConfigurableAccessPolicyProvider() { |
| @Override |
| public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getAccessPolicies(); |
| } |
| |
| @Override |
| public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getAccessPolicy(identifier); |
| } |
| |
| @Override |
| public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.addAccessPolicy(accessPolicy); |
| } |
| |
| @Override |
| public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.updateAccessPolicy(accessPolicy); |
| } |
| |
| @Override |
| public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteAccessPolicy(accessPolicy); |
| } |
| |
| @Override |
| public AccessPolicy deleteAccessPolicy(String accessPolicyIdentifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteAccessPolicy(accessPolicyIdentifier); |
| } |
| |
| @Override |
| public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException { |
| final UsersAndAccessPolicies usersAndAccessPolicies = AbstractPolicyBasedAuthorizer.this.getUsersAndAccessPolicies(); |
| return usersAndAccessPolicies.getAccessPolicy(resourceIdentifier, action); |
| } |
| |
| @Override |
| public String getFingerprint() throws AuthorizationAccessException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public UserGroupProvider getUserGroupProvider() { |
| return new ConfigurableUserGroupProvider() { |
| @Override |
| public User addUser(User user) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.addUser(user); |
| } |
| |
| @Override |
| public User updateUser(User user) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.updateUser(user); |
| } |
| |
| @Override |
| public User deleteUser(User user) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteUser(user); |
| } |
| |
| @Override |
| public User deleteUser(String userIdentifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteUser(userIdentifier); |
| } |
| |
| @Override |
| public Group addGroup(Group group) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.addGroup(group); |
| } |
| |
| @Override |
| public Group updateGroup(Group group) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.updateGroup(group); |
| } |
| |
| @Override |
| public Group deleteGroup(Group group) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteGroup(group); |
| } |
| |
| @Override |
| public Group deleteGroup(String groupIdentifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.deleteGroup(groupIdentifier); |
| } |
| |
| @Override |
| public Set<User> getUsers() throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getUsers(); |
| } |
| |
| @Override |
| public User getUser(String identifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getUser(identifier); |
| } |
| |
| @Override |
| public User getUserByIdentity(String identity) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getUserByIdentity(identity); |
| } |
| |
| @Override |
| public Set<Group> getGroups() throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getGroups(); |
| } |
| |
| @Override |
| public Group getGroup(String identifier) throws AuthorizationAccessException { |
| return AbstractPolicyBasedAuthorizer.this.getGroup(identifier); |
| } |
| |
| @Override |
| public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException { |
| final UsersAndAccessPolicies usersAndAccessPolicies = AbstractPolicyBasedAuthorizer.this.getUsersAndAccessPolicies(); |
| final User user = usersAndAccessPolicies.getUser(identity); |
| final Set<Group> groups = usersAndAccessPolicies.getGroups(identity); |
| |
| return new UserAndGroups() { |
| @Override |
| public User getUser() { |
| return user; |
| } |
| |
| @Override |
| public Set<Group> getGroups() { |
| return groups; |
| } |
| }; |
| } |
| |
| @Override |
| public String getFingerprint() throws AuthorizationAccessException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { |
| // fingerprint is managed by the encapsulating class |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void initialize(UserGroupProviderInitializationContext initializationContext) throws SecurityProviderCreationException { |
| } |
| |
| @Override |
| public void onConfigured(AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException { |
| } |
| |
| @Override |
| public void preDestruction() throws SecurityProviderDestructionException { |
| } |
| }; |
| } |
| |
| @Override |
| public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws SecurityProviderCreationException { |
| } |
| |
| @Override |
| public void onConfigured(AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException { |
| } |
| |
| @Override |
| public void preDestruction() throws SecurityProviderDestructionException { |
| } |
| }; |
| } |
| |
| /** |
| * Returns a fingerprint representing the authorizations managed by this authorizer. The fingerprint will be |
| * used for comparison to determine if two policy-based authorizers represent a compatible set of users, |
| * groups, and policies. |
| * |
| * @return the fingerprint for this Authorizer |
| */ |
| @Override |
| public final String getFingerprint() throws AuthorizationAccessException { |
| final List<User> users = getSortedUsers(); |
| final List<Group> groups = getSortedGroups(); |
| final List<AccessPolicy> policies = getSortedAccessPolicies(); |
| |
| XMLStreamWriter writer = null; |
| final StringWriter out = new StringWriter(); |
| try { |
| writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out); |
| writer.writeStartDocument(); |
| writer.writeStartElement("authorizations"); |
| |
| for (User user : users) { |
| writeUser(writer, user); |
| } |
| for (Group group : groups) { |
| writeGroup(writer, group); |
| } |
| for (AccessPolicy policy : policies) { |
| writePolicy(writer, policy); |
| } |
| |
| writer.writeEndElement(); |
| writer.writeEndDocument(); |
| writer.flush(); |
| } catch (XMLStreamException e) { |
| throw new AuthorizationAccessException("Unable to generate fingerprint", e); |
| } finally { |
| if (writer != null) { |
| try { |
| writer.close(); |
| } catch (XMLStreamException e) { |
| // nothing to do here |
| } |
| } |
| } |
| |
| return out.toString(); |
| } |
| |
| private void writeUser(final XMLStreamWriter writer, final User user) throws XMLStreamException { |
| writer.writeStartElement(USER_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, user.getIdentifier()); |
| writer.writeAttribute(IDENTITY_ATTR, user.getIdentity()); |
| writer.writeEndElement(); |
| } |
| |
| private void writeGroup(final XMLStreamWriter writer, final Group group) throws XMLStreamException { |
| List<String> users = new ArrayList<>(group.getUsers()); |
| Collections.sort(users); |
| |
| writer.writeStartElement(GROUP_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, group.getIdentifier()); |
| writer.writeAttribute(NAME_ATTR, group.getName()); |
| |
| for (String user : users) { |
| writer.writeStartElement(GROUP_USER_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, user); |
| writer.writeEndElement(); |
| } |
| |
| writer.writeEndElement(); |
| } |
| |
| private void writePolicy(final XMLStreamWriter writer, final AccessPolicy policy) throws XMLStreamException { |
| // sort the users for the policy |
| List<String> policyUsers = new ArrayList<>(policy.getUsers()); |
| Collections.sort(policyUsers); |
| |
| // sort the groups for this policy |
| List<String> policyGroups = new ArrayList<>(policy.getGroups()); |
| Collections.sort(policyGroups); |
| |
| writer.writeStartElement(POLICY_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, policy.getIdentifier()); |
| writer.writeAttribute(RESOURCE_ATTR, policy.getResource()); |
| writer.writeAttribute(ACTIONS_ATTR, policy.getAction().name()); |
| |
| for (String policyUser : policyUsers) { |
| writer.writeStartElement(POLICY_USER_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, policyUser); |
| writer.writeEndElement(); |
| } |
| |
| for (String policyGroup : policyGroups) { |
| writer.writeStartElement(POLICY_GROUP_ELEMENT); |
| writer.writeAttribute(IDENTIFIER_ATTR, policyGroup); |
| writer.writeEndElement(); |
| } |
| |
| writer.writeEndElement(); |
| } |
| |
| private List<AccessPolicy> getSortedAccessPolicies() { |
| final List<AccessPolicy> policies = new ArrayList<>(getAccessPolicies()); |
| Collections.sort(policies, Comparator.comparing(AccessPolicy::getIdentifier)); |
| return policies; |
| } |
| |
| private List<Group> getSortedGroups() { |
| final List<Group> groups = new ArrayList<>(getGroups()); |
| Collections.sort(groups, Comparator.comparing(Group::getIdentifier)); |
| return groups; |
| } |
| |
| private List<User> getSortedUsers() { |
| final List<User> users = new ArrayList<>(getUsers()); |
| Collections.sort(users, Comparator.comparing(User::getIdentifier)); |
| return users; |
| } |
| |
| private static class PoliciesUsersAndGroups { |
| final List<AccessPolicy> accessPolicies; |
| final List<User> users; |
| final List<Group> groups; |
| |
| public PoliciesUsersAndGroups(List<AccessPolicy> accessPolicies, List<User> users, List<Group> groups) { |
| this.accessPolicies = accessPolicies; |
| this.users = users; |
| this.groups = groups; |
| } |
| |
| public List<AccessPolicy> getAccessPolicies() { |
| return accessPolicies; |
| } |
| |
| public List<User> getUsers() { |
| return users; |
| } |
| |
| public List<Group> getGroups() { |
| return groups; |
| } |
| } |
| } |