/*
* Licensed to DuraSpace under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* DuraSpace 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.fcrepo.auth.common;
import static org.modeshape.jcr.ModeShapePermissions.READ;
import static org.modeshape.jcr.ModeShapePermissions.REGISTER_NAMESPACE;
import static org.modeshape.jcr.ModeShapePermissions.REGISTER_TYPE;
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import java.security.Principal;
import java.util.Set;
import org.modeshape.jcr.security.AdvancedAuthorizationProvider;
import org.modeshape.jcr.security.SecurityContext;
import org.modeshape.jcr.value.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
/**
* The security context for Fedora servlet users. These users are not
* necessarily authenticated by the container, i.e. users may include the
* general public. This security context delegates all access decisions to the
* configured authorization delegate.
*
* @author Gregory Jansen
*/
public class FedoraUserSecurityContext implements SecurityContext,
AdvancedAuthorizationProvider {
private static final Logger LOGGER = LoggerFactory
.getLogger(FedoraUserSecurityContext.class);
private Principal userPrincipal = null;
private FedoraAuthorizationDelegate fad = null;
private boolean loggedIn = true;
/**
* Constructs a new security context.
*
* @param userPrincipal the user principal associated with this security
* context
* @param fad the authorization delegate
*/
protected FedoraUserSecurityContext(final Principal userPrincipal,
final FedoraAuthorizationDelegate fad) {
this.fad = fad;
this.userPrincipal = userPrincipal;
if (this.fad == null) {
LOGGER.warn("This security context must have a FAD injected");
throw new IllegalArgumentException(
"This security context must have a FAD injected");
}
}
/**
* {@inheritDoc}
*
* @see org.modeshape.jcr.security.SecurityContext#isAnonymous()
*/
@Override
public boolean isAnonymous() {
return this.userPrincipal == null;
}
/**
* {@inheritDoc}
*
* @see SecurityContext#getUserName()
*/
@Override
public final String getUserName() {
return getEffectiveUserPrincipal().getName();
}
/**
* {@inheritDoc}
*
* @see SecurityContext#hasRole(String)
*/
@Override
public final boolean hasRole(final String roleName) {
// Under this custom PEP regime, all users have modeshape read and write
// roles.
if ("read".equals(roleName)) {
return true;
} else if ("write".equals(roleName)) {
return true;
} else if ("admin".equals(roleName)) {
return true;
}
return false;
}
/**
* Get the user principal associated with this context.
*
* @return the user principal associated with this security context
*/
public Principal getEffectiveUserPrincipal() {
if (this.loggedIn && this.userPrincipal != null) {
return this.userPrincipal;
}
return fad.getEveryonePrincipal();
}
/**
* {@inheritDoc}
*
* @see org.modeshape.jcr.security.SecurityContext#logout()
*/
@Override
public void logout() {
this.loggedIn = false;
}
/*
* (non-Javadoc)
* @see
* org.modeshape.jcr.security.AdvancedAuthorizationProvider#hasPermission
* (org.modeshape.jcr.security.AdvancedAuthorizationProvider.Context,
* org.modeshape.jcr.value.Path, java.lang.String[])
*/
@Override
public boolean hasPermission(final Context context, final Path absPath,
final String... actions) {
if (!this.loggedIn) {
return false;
}
if (absPath == null) {
// this permission is required for login
if (actions.length == 1 && READ.equals(actions[0])) {
return true;
}
// The REGISTER_NAMESPACE action and the REGISTER_TYPE action don't include
// a path and are allowed for all users. The fedora 4 code base doesn't expose
// any endpoint that *JUST* registers a namespace or type, so the operations
// that perform these actions will have to be authorized in context (for instance
// setting a property).
final Set<String> filteredActions = Sets.newHashSet(actions);
filteredActions.remove(REGISTER_NAMESPACE);
filteredActions.remove(REGISTER_TYPE);
return filteredActions.isEmpty();
}
// Trim jcr:content from paths, if necessary
final Path path;
if (null != absPath.getLastSegment() && absPath.getLastSegment().getString().equals(JCR_CONTENT)) {
path = absPath.subpath(0, absPath.size() - 1);
LOGGER.debug("..new path to be verified: {}", path);
} else {
path = absPath;
}
// delegate
if (fad != null) {
return fad.hasPermission(context.getSession(), path, actions);
}
return false;
}
}