org.entrystore.repository.impl.PrincipalManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.entrystore.repository.impl.PrincipalManagerImpl.java

Source

/*
 * Copyright (c) 2007-2014 MetaSolutions AB
 *
 * 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.entrystore.repository.impl;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.entrystore.repository.EntryType;
import org.entrystore.repository.GraphType;
import org.entrystore.repository.Entry;
import org.entrystore.repository.Group;
import org.entrystore.repository.PrincipalManager;
import org.entrystore.repository.RepositoryProperties;
import org.entrystore.repository.User;
import org.entrystore.repository.security.AuthorizationException;
import org.entrystore.repository.util.URISplit;
import org.entrystore.repository.util.URISplit.URIType;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.ValueFactory;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;

/**
 * Creates a 
 * @author Olov Wikberg, IML Ume University
 * @author matthias
 * @author Hannes Ebner
 *
 */
public class PrincipalManagerImpl extends EntryNamesContext implements PrincipalManager {
    private static Log log = LogFactory.getLog(PrincipalManagerImpl.class);
    private static final ThreadLocal<URI> authenticatedUserURI = new ThreadLocal<URI>();
    public User adminUser = null;
    public Group adminGroup = null;
    public User guestUser = null;
    public Group userGroup = null;
    private EntryImpl allPrincipals;

    /**
     * Creates a principal manager
     * @param entry this principal managers entry
     * @param uri this principal managers URI 
     * @param cache
     */
    public PrincipalManagerImpl(EntryImpl entry, String uri, SoftCache cache) {
        super(entry, uri, cache);
    }

    public String getPrincipalName(URI principal) {
        URISplit us = new URISplit(principal, this.entry.getRepositoryManager().getRepositoryURL());
        if (us.getURIType() == URIType.Resource) {
            return getName(us.getMetaMetadataURI());
        }
        throw new org.entrystore.repository.RepositoryException(
                "Given URI is not an existing resourceURI of a Principal.");
    }

    public Entry getPrincipalEntry(String name) {
        Entry principalEntry = getEntryByName(name);
        if (principalEntry == null) {
            return null;
        } else if (principalEntry.getGraphType() == GraphType.User
                || principalEntry.getGraphType() == GraphType.Group) {
            return principalEntry;
        }
        throw new org.entrystore.repository.RepositoryException("Found entry for the name is not a principal...\n"
                + "this is either a programming error or someone have been tampering with the RDF directly.");
    }

    public boolean setPrincipalName(URI principal, String newName) {
        URISplit us = new URISplit(principal, this.entry.getRepositoryManager().getRepositoryURL());
        Entry principalEntry = getByEntryURI(us.getMetaMetadataURI());
        if (principalEntry == null) {
            throw new org.entrystore.repository.RepositoryException("Cannot find an entry for the specified URI");
        } else if (principalEntry.getGraphType() == GraphType.User
                || principalEntry.getGraphType() == GraphType.Group) {
            return setEntryName(us.getMetaMetadataURI(), newName);
        }
        throw new org.entrystore.repository.RepositoryException("Given URI does not refer to a Principal.");
    }

    /**
     * Returns this principal managers all user URIs
     * @return all user URIs in this principal manager
     */
    public List<URI> getUsersAsUris() {
        Iterator<URI> entryIterator = getEntries().iterator();
        List<URI> userUris = new ArrayList<URI>();

        //sort out the users
        while (entryIterator.hasNext()) {
            URI nextURI = entryIterator.next();

            Entry nextEntry = getByEntryURI(nextURI);
            if (nextEntry.getGraphType() == GraphType.User) {
                userUris.add(nextEntry.getResourceURI());
            }
        }

        return userUris;
    }

    /**
     * Returns this principal managers all user URIs
     * @return all user URIs in this principal manager
     */
    public List<User> getUsers() {
        Iterator<URI> entryIterator = getEntries().iterator();
        List<User> userUris = new ArrayList<User>();

        //sort out the users
        while (entryIterator.hasNext()) {
            URI nextURI = entryIterator.next();

            Entry nextEntry = getByEntryURI(nextURI);
            if (nextEntry.getGraphType() == GraphType.User) {
                userUris.add((User) nextEntry.getResource());
            }
        }

        return userUris;
    }

    /**
     * Returns a User object representing a user.
     * @param userUri The URI to the user.
     * @return the User object
     */
    public User getUser(URI userUri) {
        for (Entry user : getByResourceURI(userUri)) {
            if (user.getGraphType() == GraphType.User) {
                return (User) user.getResource();
            }
        }
        return null;
    }

    /**
     * Returns a Group object representing a group of users.
     * @param groupUri URI to the group.
     * @return the Group object
     */
    public Group getGroup(URI groupUri) {
        for (Entry user : getByResourceURI(groupUri)) {
            if (user.getGraphType() == GraphType.Group) {
                return (Group) user.getResource();
            }
        }
        return null;
    }

    public Set<URI> getGroupUris() {
        Iterator<URI> entryIterator = getEntries().iterator();
        Set<URI> groupUris = new HashSet<URI>();

        //sort out the groups
        while (entryIterator.hasNext()) {
            URI nextURI = entryIterator.next();

            Entry nextGroup = getByEntryURI(nextURI);
            if (nextGroup.getGraphType() == GraphType.Group) {
                groupUris.add(nextGroup.getResourceURI());
            }
        }

        return groupUris;
    }

    public Set<URI> getGroupUris(URI userUri) {
        Iterator<URI> entryIterator = getEntries().iterator();
        Set<URI> groupUris = new HashSet<URI>();

        User user = getUser(userUri);
        if (user != null) {
            while (entryIterator.hasNext()) {
                URI nextURI = entryIterator.next();
                Entry nextEntry = getByEntryURI(nextURI);
                if (nextEntry.getGraphType() == GraphType.Group) {
                    Group nextGroup = (Group) nextEntry.getResource();
                    if (nextGroup != null) {
                        if (nextGroup.isMember(user)) {
                            groupUris.add(nextGroup.getURI());
                        }
                    }
                }
            }
        }

        return groupUris;
    }

    public List<URI> getGroupEntryUris() {
        Iterator<URI> entryIterator = getEntries().iterator();
        List<URI> groupUris = new ArrayList<URI>();

        //sort out the groups
        while (entryIterator.hasNext()) {
            URI nextURI = entryIterator.next();
            Entry e = getByEntryURI(nextURI);
            if (e.getGraphType() == GraphType.Group) {
                groupUris.add(nextURI);
            }
        }

        return groupUris;
    }

    /**
     * Sets which user that is authenticated in this specific thread.
     * @param userUri The URI to the user that was authenticated.
     */
    public void setAuthenticatedUserURI(URI userUri) {
        authenticatedUserURI.set(userUri);
    }

    public URI getAuthenticatedUserURI() {
        return authenticatedUserURI.get();
    }

    /**
     * Checks if the authenticated user it authorized to perform a specific task on a Entry. The task is defined by an access property.
     * @param entry the entry on which to check the specified accessProperty.
     * @param accessProperty the access property to check the entry for.
     * @throws AuthorizationException if not allowed.
     */
    public void checkAuthenticatedUserAuthorized(Entry entry, AccessProperty accessProperty)
            throws AuthorizationException {

        //is check authorization on?
        if (!entry.getRepositoryManager().isCheckForAuthorization()) {
            return;
        }

        URI currentUserURI = getAuthenticatedUserURI();

        //is anyone logged in on this thread?
        if (currentUserURI == null) {
            currentUserURI = getGuestUser().getURI();
            log.warn("Authenticated user not set, assuming guest user");
        }

        //is admin?
        if (currentUserURI.equals(getAdminUser().getURI())) {
            return;
        }

        //Switch to admin so that the PrincipalManager can perform all
        //neccessary checks without being hindered by itself (results in loops).
        setAuthenticatedUserURI(getAdminUser().getURI());

        try {

            //Fetch the current user from thread local.
            User currentUser = getUser(currentUserURI);

            //Check if user is in admingroup.
            if (getAdminGroup().isMember(currentUser)) {
                return;
            }

            Entry contextEntry = entry.getContext().getEntry();
            //Check if user is owner of surrounding context
            if (hasAccess(currentUser, contextEntry, AccessProperty.Administer)) {
                return;
            } else {
                //If entry overrides Context ACL (only relevant if the user is not an owner of the context)
                if (entry.hasAllowedPrincipals()) {
                    if (hasAccess(currentUser, entry, accessProperty)) {
                        return;
                    }
                } else {
                    //Check if user has access to the surrounding context of the entry.
                    if (accessProperty == AccessProperty.ReadMetadata
                            || accessProperty == AccessProperty.ReadResource) {
                        if (hasAccess(currentUser, contextEntry, AccessProperty.ReadResource)) {
                            return;
                        }
                    } else {
                        if (hasAccess(currentUser, contextEntry, AccessProperty.WriteResource)) {
                            return;
                        }
                    }
                }
            }

            throw new AuthorizationException(currentUser, entry, accessProperty);
        } finally {
            //Switch back to the current user.
            setAuthenticatedUserURI(currentUserURI);
        }
    }

    protected boolean hasAccess(User currentUser, Entry entry, AccessProperty prop) {
        Set<URI> principals = entry.getAllowedPrincipalsFor(prop);
        if (!principals.isEmpty()) {

            //Check if guest is in principals.
            if (principals.contains(getGuestUser().getURI())) {
                return true;
            }

            //Check if the special "user" group is in principals and user is not guest.
            if (currentUser != getGuestUser() && principals.contains(getUserGroup().getURI())) {
                return true;
            }

            //Check if user is in principals.
            if (principals.contains(currentUser.getURI())) {
                return true;
            }

            //Check if any of the groups the user belongs to is in principals
            Set<URI> groups = getGroupUris(currentUser.getURI());
            groups.retainAll(principals);
            if (!groups.isEmpty()) {
                return true;
            }
        }

        if (prop != AccessProperty.Administer) {
            principals = entry.getAllowedPrincipalsFor(AccessProperty.Administer);
            if (!principals.isEmpty()) {

                //Check if user is in principals.
                if (principals.contains(currentUser.getURI())) {
                    return true;
                }

                //Check if any of the groups the user belongs to is in principals
                Set<URI> groups = getGroupUris(currentUser.getURI());
                groups.retainAll(principals);
                if (!groups.isEmpty()) {
                    return true;
                }
            }
        }
        return false;
    }

    public Set<AccessProperty> getRights(Entry entry) {
        Set<AccessProperty> set = new HashSet<AccessProperty>();
        //is check authorization on?
        if (!entry.getRepositoryManager().isCheckForAuthorization()) {
            set.add(AccessProperty.Administer);
            return set;
        }

        URI currentUserURI = getAuthenticatedUserURI();

        //is anyone logged in on this thread?
        if (currentUserURI == null) {
            //TODO, should we perhaps assume guest if none set?
            log.error("Authenticated user not set, should at least be guest.");
            throw new AuthorizationException(null, entry, null);
        }

        //is admin?
        if (currentUserURI.equals(getAdminUser().getURI())) {
            set.add(AccessProperty.Administer);
            return set;
        }

        //Switch to admin so that the PrincipalManager can perform all
        //neccessary checks without being hindered by itself (results in loops).
        setAuthenticatedUserURI(getAdminUser().getURI());

        try {

            //Fetch the current user from thread local.
            User currentUser = getUser(currentUserURI);

            //Check if user is in admingroup.
            if (getAdminGroup().isMember(currentUser)) {
                set.add(AccessProperty.Administer);
                return set;
            }

            Entry contextEntry = entry.getContext().getEntry();
            //Check if user is owner of surrounding context
            if (hasAccess(currentUser, contextEntry, AccessProperty.Administer)) {
                set.add(AccessProperty.Administer);
            } else {
                //If entry overrides Context ACL (only relevant if the user is not an owner of the context)
                if (entry.hasAllowedPrincipals()) {
                    if (hasAccess(currentUser, entry, AccessProperty.Administer)) {
                        set.add(AccessProperty.Administer);
                        return set;
                    } else {
                        if (hasAccess(currentUser, entry, AccessProperty.WriteMetadata)) {
                            set.add(AccessProperty.WriteMetadata);
                        } else if (hasAccess(currentUser, entry, AccessProperty.ReadMetadata)) {
                            set.add(AccessProperty.ReadMetadata);
                        }
                        if (hasAccess(currentUser, entry, AccessProperty.WriteResource)) {
                            set.add(AccessProperty.WriteResource);
                        } else if (hasAccess(currentUser, entry, AccessProperty.ReadResource)) {
                            set.add(AccessProperty.ReadResource);
                        }
                    }
                } else {
                    if (hasAccess(currentUser, contextEntry, AccessProperty.WriteResource)) {
                        set.add(AccessProperty.Administer);
                    } else if (hasAccess(currentUser, contextEntry, AccessProperty.ReadResource)) {
                        set.add(AccessProperty.ReadMetadata);
                        set.add(AccessProperty.ReadResource);
                    }
                }
            }
        } finally {
            //Switch back to the current user.
            setAuthenticatedUserURI(currentUserURI);
        }
        return set;
    }

    /**
     * Checks if a secret is valid.
     * @param secret Secret to be checked.
     * @return true If the secret fullfils minimum requirements, currently a minimum length of 8 characters.
     */
    public boolean isValidSecret(String secret) {
        if (secret == null || secret.length() < 8) {
            return false;
        }
        return true;
    }

    public User getAdminUser() {
        return adminUser;
    }

    public Group getAdminGroup() {
        return adminGroup;
    }

    public User getGuestUser() {
        return guestUser;
    }

    public Group getUserGroup() {
        return userGroup;
    }

    @Override
    public void initResource(EntryImpl newEntry) throws RepositoryException {
        if (newEntry.getEntryType() != EntryType.Local) {
            return;
        }
        switch (newEntry.getGraphType()) {
        case User:
            newEntry.setResource(new UserImpl(newEntry, newEntry.getSesameResourceURI(), cache));
            break;
        case Group:
            newEntry.setResource(new GroupImpl(newEntry, newEntry.getSesameResourceURI(), cache));
            break;
        default:
            super.initResource(newEntry);
        }
    }

    public void initializeSystemEntries() {
        super.initializeSystemEntries();
        Entry adminUserEntry;
        Entry adminGroupEntry;
        Entry userGroupEntry;
        Entry guestUserEntry;
        Entry top;

        top = get("_top");
        if (top == null) {
            top = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.List, null, "_top");
            setMetadata(top, "Top folder", null);
            log.info("Successfully added the top list");
        }
        addSystemEntryToSystemEntries(top.getEntryURI());

        guestUserEntry = get("_guest");
        if (guestUserEntry != null) {
            guestUser = (User) guestUserEntry.getResource();
        } else {
            guestUserEntry = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.User, null, "_guest");
            setMetadata(guestUserEntry, "Guest user",
                    "All non logged in users will automatically appear as this user.");
            guestUser = (User) guestUserEntry.getResource();
            guestUser.setName("guest");
            guestUserEntry.addAllowedPrincipalsFor(AccessProperty.ReadMetadata, guestUser.getURI());
            log.info("Successfully added the guest user");
        }
        addSystemEntryToSystemEntries(guestUserEntry.getEntryURI());

        adminUserEntry = get("_admin");
        if (adminUserEntry != null) {
            adminUser = (User) adminUserEntry.getResource();
        } else {
            adminUserEntry = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.User, null, "_admin");
            setMetadata(adminUserEntry, "Admin user", "Default super user, has all rights.");
            adminUser = (User) adminUserEntry.getResource();
            adminUser.setName("admin");
            adminUser.setSecret("adminadmin");
            adminUserEntry.addAllowedPrincipalsFor(AccessProperty.ReadMetadata, guestUser.getURI());
            log.info("Successfully added the admin user");
        }
        addSystemEntryToSystemEntries(adminUserEntry.getEntryURI());

        adminGroupEntry = get("_admins");
        if (adminGroupEntry != null) {
            adminGroup = (Group) adminGroupEntry.getResource();
        } else {
            adminGroupEntry = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.Group, null,
                    "_admins");
            setMetadata(adminGroupEntry, "Admin group", "All members of this group have super user rights.");
            adminGroup = (Group) adminGroupEntry.getResource();
            adminGroup.setName("admins");
            adminGroupEntry.addAllowedPrincipalsFor(AccessProperty.ReadMetadata, guestUser.getURI());
            log.info("Successfully added the admin group");
        }
        addSystemEntryToSystemEntries(adminGroupEntry.getEntryURI());

        userGroupEntry = get("_users");
        if (userGroupEntry == null) {
            userGroupEntry = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.Group, null,
                    "_users");
            setMetadata(userGroupEntry, "Users group", "All regular users are part of this group.");
            setPrincipalName(userGroupEntry.getResourceURI(), "users");
            userGroupEntry.addAllowedPrincipalsFor(AccessProperty.ReadMetadata, guestUser.getURI());
            log.info("Successfully added the user group");
        }
        EntryImpl e = (EntryImpl) userGroupEntry;
        e.setResource(new SystemGroup(e, e.getSesameResourceURI()) {
            @Override
            public boolean isMember(User user) {
                return (user != null && PrincipalManagerImpl.this.guestUser != null
                        && !user.getURI().equals(PrincipalManagerImpl.this.guestUser.getURI()));
                // return true;
            }

            @Override
            public List<User> members() {
                return getUsers();
            }

            @Override
            public List<URI> memberUris() {
                return getUsersAsUris();
            }
        });

        userGroup = (Group) userGroupEntry.getResource();
        addSystemEntryToSystemEntries(userGroupEntry.getEntryURI());

        allPrincipals = (EntryImpl) get("_all");
        if (allPrincipals == null) {
            allPrincipals = this.createNewMinimalItem(null, null, EntryType.Local, GraphType.List, null, "_all");
            setMetadata(allPrincipals, "all principals",
                    "This is a list of all principals in the PrincipalManager.");
            allPrincipals.addAllowedPrincipalsFor(AccessProperty.ReadMetadata, this.getGuestUser().getURI());
            allPrincipals.addAllowedPrincipalsFor(AccessProperty.ReadResource, this.getGuestUser().getURI());
            log.info("Successfully added the _all contexts list");
        }
        allPrincipals.setResource(new SystemList(allPrincipals, allPrincipals.getSesameResourceURI()) {
            @Override
            public List<URI> getChildren() {
                Iterator<URI> entryIterator = getEntries().iterator();
                List<URI> principalUris = new ArrayList<URI>();

                //sort out the principals
                while (entryIterator.hasNext()) {
                    URI nextURI = entryIterator.next();

                    Entry nextEntry = getByEntryURI(nextURI);
                    GraphType bt = nextEntry.getGraphType();
                    if (bt == GraphType.User || bt == GraphType.Group) {
                        principalUris.add(nextEntry.getEntryURI());
                    }
                }
                return principalUris;
            }
        });
        addSystemEntryToSystemEntries(allPrincipals.getEntryURI());
    }

    /**
     * @param externalID
     *            An E-Mail address
     * @return A user that can be mapped to the external E-Mail address (that
     *         e.g. originates from an OpenID service)
     * @see org.entrystore.repository.PrincipalManager#getUserByExternalID(java.lang.String)
     */
    public User getUserByExternalID(String externalID) {
        RepositoryConnection rc = null;
        Resource userResourceURI = null;
        try {
            rc = entry.getRepository().getConnection();
            ValueFactory vf = rc.getValueFactory();
            RepositoryResult<Statement> rr = rc.getStatements(null, RepositoryProperties.externalID,
                    vf.createURI("mailto:", externalID), false);
            if (rr.hasNext()) {
                userResourceURI = rr.next().getSubject();
            }
            rr.close();
        } catch (RepositoryException re) {
            log.error(re.getMessage(), re);
        } finally {
            if (rc != null) {
                try {
                    rc.close();
                } catch (RepositoryException ignore) {
                }
            }
        }
        if (userResourceURI == null) {
            return null;
        }
        return getUser(URI.create(userResourceURI.stringValue()));
    }

}