| /* |
| * 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.file; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.nifi.registry.security.authorization.AuthorizerConfigurationContext; |
| import org.apache.nifi.registry.security.authorization.ConfigurableUserGroupProvider; |
| import org.apache.nifi.registry.security.authorization.Group; |
| import org.apache.nifi.registry.security.authorization.User; |
| import org.apache.nifi.registry.security.authorization.UserAndGroups; |
| import org.apache.nifi.registry.security.authorization.UserGroupProviderInitializationContext; |
| import org.apache.nifi.registry.security.authorization.annotation.AuthorizerContext; |
| import org.apache.nifi.registry.security.authorization.exception.AuthorizationAccessException; |
| import org.apache.nifi.registry.security.authorization.exception.UninheritableAuthorizationsException; |
| import org.apache.nifi.registry.security.authorization.file.tenants.generated.Groups; |
| import org.apache.nifi.registry.security.authorization.file.tenants.generated.Tenants; |
| import org.apache.nifi.registry.security.authorization.file.tenants.generated.Users; |
| import org.apache.nifi.registry.security.authorization.util.UserGroupProviderUtils; |
| import org.apache.nifi.registry.security.exception.SecurityProviderCreationException; |
| import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException; |
| import org.apache.nifi.registry.security.identity.IdentityMapper; |
| import org.apache.nifi.registry.util.PropertyValue; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| 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.XMLConstants; |
| import javax.xml.bind.JAXBContext; |
| import javax.xml.bind.JAXBElement; |
| import javax.xml.bind.JAXBException; |
| import javax.xml.bind.Marshaller; |
| import javax.xml.bind.Unmarshaller; |
| 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 javax.xml.transform.stream.StreamSource; |
| import javax.xml.validation.Schema; |
| import javax.xml.validation.SchemaFactory; |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| 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.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| public class FileUserGroupProvider implements ConfigurableUserGroupProvider { |
| |
| private static final Logger logger = LoggerFactory.getLogger(FileUserGroupProvider.class); |
| |
| private static final String TENANTS_XSD = "/tenants.xsd"; |
| private static final String JAXB_TENANTS_PATH = "org.apache.nifi.registry.security.authorization.file.tenants.generated"; |
| |
| private static final JAXBContext JAXB_TENANTS_CONTEXT = initializeJaxbContext(JAXB_TENANTS_PATH); |
| |
| /** |
| * Load the JAXBContext. |
| */ |
| private static JAXBContext initializeJaxbContext(final String contextPath) { |
| try { |
| return JAXBContext.newInstance(contextPath, FileAuthorizer.class.getClassLoader()); |
| //return JAXBContext.newInstance(contextPath); |
| } catch (JAXBException e) { |
| throw new RuntimeException("Unable to create JAXBContext: " + e); |
| } |
| } |
| |
| private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); |
| private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance(); |
| |
| private static final String USER_ELEMENT = "user"; |
| private static final String GROUP_USER_ELEMENT = "groupUser"; |
| private static final String GROUP_ELEMENT = "group"; |
| private static final String IDENTIFIER_ATTR = "identifier"; |
| private static final String IDENTITY_ATTR = "identity"; |
| private static final String NAME_ATTR = "name"; |
| |
| static final String PROP_TENANTS_FILE = "Users File"; |
| |
| private Schema tenantsSchema; |
| private File tenantsFile; |
| private Set<String> initialUserIdentities; |
| private IdentityMapper identityMapper; |
| |
| private final AtomicReference<UserGroupHolder> userGroupHolder = new AtomicReference<>(); |
| |
| @Override |
| public void initialize(UserGroupProviderInitializationContext initializationContext) throws SecurityProviderCreationException { |
| try { |
| final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); |
| tenantsSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(TENANTS_XSD)); |
| } catch (Exception e) { |
| throw new SecurityProviderCreationException(e); |
| } |
| } |
| |
| @Override |
| public void onConfigured(AuthorizerConfigurationContext configurationContext) throws SecurityProviderCreationException { |
| try { |
| final PropertyValue tenantsPath = configurationContext.getProperty(PROP_TENANTS_FILE); |
| if (StringUtils.isBlank(tenantsPath.getValue())) { |
| throw new SecurityProviderCreationException("The users file must be specified."); |
| } |
| |
| // get the tenants file and ensure it exists |
| tenantsFile = new File(tenantsPath.getValue()); |
| if (!tenantsFile.exists()) { |
| logger.info("Creating new users file at {}", new Object[] {tenantsFile.getAbsolutePath()}); |
| saveTenants(new Tenants()); |
| } |
| |
| // extract any nifi identities |
| initialUserIdentities = UserGroupProviderUtils.getInitialUserIdentities(configurationContext, identityMapper); |
| |
| load(); |
| |
| logger.info(String.format("Users/Groups file loaded at %s", new Date().toString())); |
| } catch (SecurityProviderCreationException | JAXBException | IllegalStateException | SAXException e) { |
| throw new SecurityProviderCreationException(e); |
| } |
| } |
| |
| @Override |
| public Set<User> getUsers() throws AuthorizationAccessException { |
| return userGroupHolder.get().getAllUsers(); |
| } |
| |
| @Override |
| public synchronized User addUser(User user) throws AuthorizationAccessException { |
| if (user == null) { |
| throw new IllegalArgumentException("User cannot be null"); |
| } |
| |
| final org.apache.nifi.registry.security.authorization.file.tenants.generated.User jaxbUser = createJAXBUser(user); |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final Tenants tenants = holder.getTenants(); |
| tenants.getUsers().getUser().add(jaxbUser); |
| |
| saveAndRefreshHolder(tenants); |
| |
| return userGroupHolder.get().getUsersById().get(user.getIdentifier()); |
| } |
| |
| @Override |
| public User getUser(String identifier) throws AuthorizationAccessException { |
| if (identifier == null) { |
| return null; |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| return holder.getUsersById().get(identifier); |
| } |
| |
| @Override |
| public synchronized User updateUser(User user) throws AuthorizationAccessException { |
| if (user == null) { |
| throw new IllegalArgumentException("User cannot be null"); |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final Tenants tenants = holder.getTenants(); |
| |
| final List<org.apache.nifi.registry.security.authorization.file.tenants.generated.User> users = tenants.getUsers().getUser(); |
| |
| // fine the User that needs to be updated |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.User updateUser = null; |
| for (org.apache.nifi.registry.security.authorization.file.tenants.generated.User jaxbUser : users) { |
| if (user.getIdentifier().equals(jaxbUser.getIdentifier())) { |
| updateUser = jaxbUser; |
| break; |
| } |
| } |
| |
| // if user wasn't found return null, otherwise update the user and save changes |
| if (updateUser == null) { |
| return null; |
| } else { |
| updateUser.setIdentity(user.getIdentity()); |
| saveAndRefreshHolder(tenants); |
| |
| return userGroupHolder.get().getUsersById().get(user.getIdentifier()); |
| } |
| } |
| |
| @Override |
| public User getUserByIdentity(String identity) throws AuthorizationAccessException { |
| if (identity == null) { |
| return null; |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| return holder.getUsersByIdentity().get(identity); |
| } |
| |
| @Override |
| public synchronized User deleteUser(User user) throws AuthorizationAccessException { |
| if (user == null) { |
| throw new IllegalArgumentException("User cannot be null"); |
| } |
| |
| return deleteUser(user.getIdentifier()); |
| } |
| |
| private synchronized User deleteUser(String userIdentifier) throws AuthorizationAccessException { |
| if (userIdentifier == null) { |
| throw new IllegalArgumentException("User identifier cannot be null"); |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final User deletedUser = holder.getUsersById().get(userIdentifier); |
| if (deletedUser == null) { |
| return null; |
| } |
| |
| // for each group iterate over the user references and remove the user reference if it matches the user being deleted |
| final Tenants tenants = holder.getTenants(); |
| for (org.apache.nifi.registry.security.authorization.file.tenants.generated.Group group : tenants.getGroups().getGroup()) { |
| Iterator<org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User> groupUserIter = group.getUser().iterator(); |
| while (groupUserIter.hasNext()) { |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User groupUser = groupUserIter.next(); |
| if (groupUser.getIdentifier().equals(userIdentifier)) { |
| groupUserIter.remove(); |
| break; |
| } |
| } |
| } |
| |
| // remove the actual user |
| Iterator<org.apache.nifi.registry.security.authorization.file.tenants.generated.User> iter = tenants.getUsers().getUser().iterator(); |
| while (iter.hasNext()) { |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.User jaxbUser = iter.next(); |
| if (userIdentifier.equals(jaxbUser.getIdentifier())) { |
| iter.remove(); |
| break; |
| } |
| } |
| |
| saveAndRefreshHolder(tenants); |
| return deletedUser; |
| } |
| |
| @Override |
| public Set<Group> getGroups() throws AuthorizationAccessException { |
| return userGroupHolder.get().getAllGroups(); |
| } |
| |
| @Override |
| public synchronized Group addGroup(Group group) throws AuthorizationAccessException { |
| if (group == null) { |
| throw new IllegalArgumentException("Group cannot be null"); |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final Tenants tenants = holder.getTenants(); |
| |
| // create a new JAXB Group based on the incoming Group |
| final org.apache.nifi.registry.security.authorization.file.tenants.generated.Group jaxbGroup = |
| new org.apache.nifi.registry.security.authorization.file.tenants.generated.Group(); |
| jaxbGroup.setIdentifier(group.getIdentifier()); |
| jaxbGroup.setName(group.getName()); |
| |
| // add each user to the group |
| for (String groupUser : group.getUsers()) { |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User jaxbGroupUser = |
| new org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User(); |
| jaxbGroupUser.setIdentifier(groupUser); |
| jaxbGroup.getUser().add(jaxbGroupUser); |
| } |
| |
| tenants.getGroups().getGroup().add(jaxbGroup); |
| saveAndRefreshHolder(tenants); |
| |
| return userGroupHolder.get().getGroupsById().get(group.getIdentifier()); |
| } |
| |
| @Override |
| public Group getGroup(String identifier) throws AuthorizationAccessException { |
| if (identifier == null) { |
| return null; |
| } |
| return userGroupHolder.get().getGroupsById().get(identifier); |
| } |
| |
| @Override |
| public UserAndGroups getUserAndGroups(final String identity) throws AuthorizationAccessException { |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final User user = holder.getUser(identity); |
| final Set<Group> groups = holder.getGroups(identity); |
| |
| return new UserAndGroups() { |
| @Override |
| public User getUser() { |
| return user; |
| } |
| |
| @Override |
| public Set<Group> getGroups() { |
| return groups; |
| } |
| }; |
| } |
| |
| @Override |
| public synchronized Group updateGroup(Group group) throws AuthorizationAccessException { |
| if (group == null) { |
| throw new IllegalArgumentException("Group cannot be null"); |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final Tenants tenants = holder.getTenants(); |
| |
| // find the group that needs to be update |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group updateGroup = null; |
| for (org.apache.nifi.registry.security.authorization.file.tenants.generated.Group jaxbGroup : tenants.getGroups().getGroup()) { |
| if (jaxbGroup.getIdentifier().equals(group.getIdentifier())) { |
| updateGroup = jaxbGroup; |
| break; |
| } |
| } |
| |
| // if the group wasn't found return null, otherwise update the group and save changes |
| if (updateGroup == null) { |
| return null; |
| } |
| |
| // reset the list of users and add each user to the group |
| updateGroup.getUser().clear(); |
| for (String groupUser : group.getUsers()) { |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User jaxbGroupUser = |
| new org.apache.nifi.registry.security.authorization.file.tenants.generated.Group.User(); |
| jaxbGroupUser.setIdentifier(groupUser); |
| updateGroup.getUser().add(jaxbGroupUser); |
| } |
| |
| updateGroup.setName(group.getName()); |
| saveAndRefreshHolder(tenants); |
| |
| return userGroupHolder.get().getGroupsById().get(group.getIdentifier()); |
| } |
| |
| @Override |
| public synchronized Group deleteGroup(Group group) throws AuthorizationAccessException { |
| if (group == null) { |
| throw new IllegalArgumentException("Group cannot be null"); |
| } |
| |
| return deleteGroup(group.getIdentifier()); |
| } |
| |
| private synchronized Group deleteGroup(String groupIdentifier) throws AuthorizationAccessException { |
| if (groupIdentifier == null) { |
| throw new IllegalArgumentException("Group identifier cannot be null"); |
| } |
| |
| final UserGroupHolder holder = userGroupHolder.get(); |
| final Group deletedGroup = holder.getGroupsById().get(groupIdentifier); |
| if (deletedGroup == null) { |
| return null; |
| } |
| |
| // now remove the actual group from the top-level list of groups |
| final Tenants tenants = holder.getTenants(); |
| Iterator<org.apache.nifi.registry.security.authorization.file.tenants.generated.Group> iter = tenants.getGroups().getGroup().iterator(); |
| while (iter.hasNext()) { |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group jaxbGroup = iter.next(); |
| if (groupIdentifier.equals(jaxbGroup.getIdentifier())) { |
| iter.remove(); |
| break; |
| } |
| } |
| |
| saveAndRefreshHolder(tenants); |
| return deletedGroup; |
| } |
| |
| UserGroupHolder getUserGroupHolder() { |
| return userGroupHolder.get(); |
| } |
| |
| @AuthorizerContext |
| public void setIdentityMapper(final IdentityMapper identityMapper) { |
| this.identityMapper = identityMapper; |
| } |
| |
| @Override |
| public synchronized void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { |
| final UsersAndGroups usersAndGroups = parseUsersAndGroups(fingerprint); |
| usersAndGroups.getUsers().forEach(user -> addUser(user)); |
| usersAndGroups.getGroups().forEach(group -> addGroup(group)); |
| } |
| |
| @Override |
| public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException { |
| try { |
| // ensure we understand the proposed fingerprint |
| parseUsersAndGroups(proposedFingerprint); |
| } catch (final AuthorizationAccessException e) { |
| throw new UninheritableAuthorizationsException("Unable to parse the proposed fingerprint: " + e); |
| } |
| |
| final UserGroupHolder usersAndGroups = userGroupHolder.get(); |
| |
| // ensure we are in a proper state to inherit the fingerprint |
| if (!usersAndGroups.getAllUsers().isEmpty() || !usersAndGroups.getAllGroups().isEmpty()) { |
| throw new UninheritableAuthorizationsException("Proposed fingerprint is not inheritable because the current users and groups is not empty."); |
| } |
| } |
| |
| @Override |
| public String getFingerprint() throws AuthorizationAccessException { |
| final UserGroupHolder usersAndGroups = userGroupHolder.get(); |
| |
| final List<User> users = new ArrayList<>(usersAndGroups.getAllUsers()); |
| Collections.sort(users, Comparator.comparing(User::getIdentifier)); |
| |
| final List<Group> groups = new ArrayList<>(usersAndGroups.getAllGroups()); |
| Collections.sort(groups, Comparator.comparing(Group::getIdentifier)); |
| |
| XMLStreamWriter writer = null; |
| final StringWriter out = new StringWriter(); |
| try { |
| writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out); |
| writer.writeStartDocument(); |
| writer.writeStartElement("tenants"); |
| |
| for (User user : users) { |
| writeUser(writer, user); |
| } |
| for (Group group : groups) { |
| writeGroup(writer, group); |
| } |
| |
| 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 UsersAndGroups parseUsersAndGroups(final String fingerprint) { |
| 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 user group provider |
| 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 user group provider |
| NodeList groupNodes = rootElement.getElementsByTagName(GROUP_ELEMENT); |
| for (int i=0; i < groupNodes.getLength(); i++) { |
| Node groupNode = groupNodes.item(i); |
| groups.add(parseGroup((Element) groupNode)); |
| } |
| } catch (SAXException | ParserConfigurationException | IOException e) { |
| throw new AuthorizationAccessException("Unable to parse fingerprint", e); |
| } |
| |
| return new UsersAndGroups(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 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 org.apache.nifi.registry.security.authorization.file.tenants.generated.User createJAXBUser(User user) { |
| final org.apache.nifi.registry.security.authorization.file.tenants.generated.User jaxbUser = |
| new org.apache.nifi.registry.security.authorization.file.tenants.generated.User(); |
| jaxbUser.setIdentifier(user.getIdentifier()); |
| jaxbUser.setIdentity(user.getIdentity()); |
| return jaxbUser; |
| } |
| |
| /** |
| * Loads the authorizations file and populates the AuthorizationsHolder, only called during start-up. |
| * |
| * @throws JAXBException Unable to reload the authorized users file |
| * @throws IllegalStateException Unable to sync file with restore |
| * @throws SAXException Unable to unmarshall tenants |
| */ |
| private synchronized void load() throws JAXBException, IllegalStateException, SAXException { |
| final Tenants tenants = unmarshallTenants(); |
| if (tenants.getUsers() == null) { |
| tenants.setUsers(new Users()); |
| } |
| if (tenants.getGroups() == null) { |
| tenants.setGroups(new Groups()); |
| } |
| |
| final UserGroupHolder userGroupHolder = new UserGroupHolder(tenants); |
| final boolean emptyTenants = userGroupHolder.getAllUsers().isEmpty() && userGroupHolder.getAllGroups().isEmpty(); |
| |
| if (emptyTenants) { |
| |
| populateInitialUsers(tenants); |
| |
| // save any changes that were made and repopulate the holder |
| saveAndRefreshHolder(tenants); |
| } else { |
| this.userGroupHolder.set(userGroupHolder); |
| } |
| } |
| |
| private void saveTenants(final Tenants tenants) throws JAXBException { |
| final Marshaller marshaller = JAXB_TENANTS_CONTEXT.createMarshaller(); |
| marshaller.setSchema(tenantsSchema); |
| marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
| marshaller.marshal(tenants, tenantsFile); |
| } |
| |
| private Tenants unmarshallTenants() throws JAXBException { |
| final Unmarshaller unmarshaller = JAXB_TENANTS_CONTEXT.createUnmarshaller(); |
| unmarshaller.setSchema(tenantsSchema); |
| |
| final JAXBElement<Tenants> element = unmarshaller.unmarshal(new StreamSource(tenantsFile), Tenants.class); |
| return element.getValue(); |
| } |
| |
| private void populateInitialUsers(final Tenants tenants) { |
| for (String initialUserIdentity : initialUserIdentities) { |
| getOrCreateUser(tenants, initialUserIdentity); |
| } |
| } |
| |
| /** |
| * Finds the User with the given identity, or creates a new one and adds it to the Tenants. |
| * |
| * @param tenants the Tenants reference |
| * @param userIdentity the user identity to find or create |
| * @return the User from Tenants with the given identity, or a new instance that was added to Tenants |
| */ |
| private org.apache.nifi.registry.security.authorization.file.tenants.generated.User getOrCreateUser(final Tenants tenants, final String userIdentity) { |
| if (StringUtils.isBlank(userIdentity)) { |
| return null; |
| } |
| |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.User foundUser = null; |
| for (org.apache.nifi.registry.security.authorization.file.tenants.generated.User user : tenants.getUsers().getUser()) { |
| if (user.getIdentity().equals(userIdentity)) { |
| foundUser = user; |
| break; |
| } |
| } |
| |
| if (foundUser == null) { |
| final User newUser = new User.Builder().identifierGenerateFromSeed(userIdentity).identity(userIdentity).build(); |
| foundUser = new org.apache.nifi.registry.security.authorization.file.tenants.generated.User(); |
| foundUser.setIdentifier(newUser.getIdentifier()); |
| foundUser.setIdentity(newUser.getIdentity()); |
| tenants.getUsers().getUser().add(foundUser); |
| } |
| |
| return foundUser; |
| } |
| |
| /** |
| * Finds the Group with the given name, or creates a new one and adds it to Tenants. |
| * |
| * @param tenants the Tenants reference |
| * @param groupName the name of the group to look for |
| * @return the Group from Tenants with the given name, or a new instance that was added to Tenants |
| */ |
| private org.apache.nifi.registry.security.authorization.file.tenants.generated.Group getOrCreateGroup(final Tenants tenants, final String groupName) { |
| if (StringUtils.isBlank(groupName)) { |
| return null; |
| } |
| |
| org.apache.nifi.registry.security.authorization.file.tenants.generated.Group foundGroup = null; |
| for (org.apache.nifi.registry.security.authorization.file.tenants.generated.Group group : tenants.getGroups().getGroup()) { |
| if (group.getName().equals(groupName)) { |
| foundGroup = group; |
| break; |
| } |
| } |
| |
| if (foundGroup == null) { |
| final Group newGroup = new Group.Builder().identifierGenerateFromSeed(groupName).name(groupName).build(); |
| foundGroup = new org.apache.nifi.registry.security.authorization.file.tenants.generated.Group(); |
| foundGroup.setIdentifier(newGroup.getIdentifier()); |
| foundGroup.setName(newGroup.getName()); |
| tenants.getGroups().getGroup().add(foundGroup); |
| } |
| |
| return foundGroup; |
| } |
| |
| /** |
| * Saves the Authorizations instance by marshalling to a file, then re-populates the |
| * in-memory data structures and sets the new holder. |
| * |
| * Synchronized to ensure only one thread writes the file at a time. |
| * |
| * @param tenants the tenants to save and populate from |
| * @throws AuthorizationAccessException if an error occurs saving the authorizations |
| */ |
| private synchronized void saveAndRefreshHolder(final Tenants tenants) throws AuthorizationAccessException { |
| try { |
| saveTenants(tenants); |
| |
| this.userGroupHolder.set(new UserGroupHolder(tenants)); |
| } catch (JAXBException e) { |
| throw new AuthorizationAccessException("Unable to save Authorizations", e); |
| } |
| } |
| |
| @Override |
| public void preDestruction() throws SecurityProviderDestructionException { |
| } |
| |
| private static class UsersAndGroups { |
| final List<User> users; |
| final List<Group> groups; |
| |
| public UsersAndGroups(List<User> users, List<Group> groups) { |
| this.users = users; |
| this.groups = groups; |
| } |
| |
| public List<User> getUsers() { |
| return users; |
| } |
| |
| public List<Group> getGroups() { |
| return groups; |
| } |
| } |
| } |