001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.auth.common;
017
018import static org.fcrepo.auth.common.ServletContainerAuthenticationProvider.EVERYONE;
019
020import org.modeshape.jcr.security.AdvancedAuthorizationProvider;
021import org.modeshape.jcr.security.SecurityContext;
022import org.modeshape.jcr.value.Path;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026import java.security.Principal;
027
028/**
029 * The security context for Fedora servlet users. These users are not
030 * necessarily authenticated by the container, i.e. users may include the
031 * general public. This security context delegates all access decisions to the
032 * configured authorization delegate.
033 *
034 * @author Gregory Jansen
035 */
036public class FedoraUserSecurityContext implements SecurityContext,
037        AdvancedAuthorizationProvider {
038
039    private static final Logger LOGGER = LoggerFactory
040            .getLogger(FedoraUserSecurityContext.class);
041
042    private Principal userPrincipal = null;
043
044    private FedoraAuthorizationDelegate fad = null;
045
046    private boolean loggedIn = true;
047
048    /**
049     * Constructs a new security context.
050     *
051     * @param userPrincipal the user principal associated with this security
052     *        context
053     * @param fad the authorization delegate
054     */
055    protected FedoraUserSecurityContext(final Principal userPrincipal,
056            final FedoraAuthorizationDelegate fad) {
057        this.fad = fad;
058        this.userPrincipal = userPrincipal;
059
060        if (this.fad == null) {
061            LOGGER.warn("This security context must have a FAD injected");
062            throw new IllegalArgumentException(
063                    "This security context must have a FAD injected");
064        }
065    }
066
067    /**
068     * {@inheritDoc}
069     *
070     * @see org.modeshape.jcr.security.SecurityContext#isAnonymous()
071     */
072    @Override
073    public boolean isAnonymous() {
074        return this.userPrincipal == null;
075    }
076
077    /**
078     * {@inheritDoc}
079     *
080     * @see SecurityContext#getUserName()
081     */
082    @Override
083    public final String getUserName() {
084        return getEffectiveUserPrincipal().getName();
085    }
086
087    /**
088     * {@inheritDoc}
089     *
090     * @see SecurityContext#hasRole(String)
091     */
092    @Override
093    public final boolean hasRole(final String roleName) {
094        // Under this custom PEP regime, all users have modeshape read and write
095        // roles.
096        if ("read".equals(roleName)) {
097            return true;
098        } else if ("write".equals(roleName)) {
099            return true;
100        } else if ("admin".equals(roleName)) {
101            return true;
102        }
103        return false;
104    }
105
106    /**
107     * Get the user principal associated with this context.
108     *
109     * @return the user principal associated with this security context
110     */
111    public Principal getEffectiveUserPrincipal() {
112        if (this.loggedIn && this.userPrincipal != null) {
113            return this.userPrincipal;
114        }
115        return EVERYONE;
116    }
117
118    /**
119     * {@inheritDoc}
120     *
121     * @see org.modeshape.jcr.security.SecurityContext#logout()
122     */
123    @Override
124    public void logout() {
125        this.loggedIn = false;
126    }
127
128    /*
129     * (non-Javadoc)
130     * @see
131     * org.modeshape.jcr.security.AdvancedAuthorizationProvider#hasPermission
132     * (org.modeshape.jcr.security.AdvancedAuthorizationProvider.Context,
133     * org.modeshape.jcr.value.Path, java.lang.String[])
134     */
135    @Override
136    public boolean hasPermission(final Context context, final Path absPath,
137            final String... actions) {
138        if (!this.loggedIn) {
139            return false;
140        }
141
142        // this permission is required for login
143        if (absPath == null) {
144            return actions.length == 1 && "read".equals(actions[0]);
145        }
146
147        // delegate
148        if (fad != null) {
149            return fad.hasPermission(context.getSession(), absPath, actions);
150        }
151        return false;
152    }
153}