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 java.security.Principal; 019import java.util.Collections; 020import java.util.HashSet; 021import java.util.Map; 022import java.util.Set; 023 024import javax.jcr.Credentials; 025import javax.servlet.http.HttpServletRequest; 026 027import org.modeshape.jcr.ExecutionContext; 028import org.modeshape.jcr.api.ServletCredentials; 029import org.modeshape.jcr.security.AuthenticationProvider; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * Authenticates ModeShape logins where JAX-RS credentials are supplied. Capable 035 * of authenticating whether or not container has performed user authentication. 036 * This is a singleton with an injected policy enforcement point. The singleton 037 * pattern allows ModeShape to obtain this instance via classname configuration. 038 * 039 * @author Gregory Jansen 040 */ 041public final class ServletContainerAuthenticationProvider implements 042 AuthenticationProvider { 043 044 private static ServletContainerAuthenticationProvider instance = null; 045 046 private ServletContainerAuthenticationProvider() { 047 instance = this; 048 } 049 050 public static final String EVERYONE_NAME = "EVERYONE"; 051 052 /** 053 * The security principal for every request. 054 */ 055 public static final Principal EVERYONE = new Principal() { 056 057 @Override 058 public String getName() { 059 return ServletContainerAuthenticationProvider.EVERYONE_NAME; 060 } 061 062 @Override 063 public String toString() { 064 return getName(); 065 } 066 067 }; 068 069 /** 070 * User role for Fedora's admin users 071 */ 072 public static final String FEDORA_ADMIN_ROLE = "fedoraAdmin"; 073 074 /** 075 * User role for Fedora's ordinary users 076 */ 077 public static final String FEDORA_USER_ROLE = "fedoraUser"; 078 079 private static final Logger LOGGER = LoggerFactory 080 .getLogger(ServletContainerAuthenticationProvider.class); 081 082 private Set<PrincipalProvider> principalProviders = Collections.emptySet(); 083 084 private FedoraAuthorizationDelegate fad; 085 086 /** 087 * Provides the singleton bean to ModeShape via reflection based on class 088 * name. 089 * 090 * @return a AuthenticationProvider 091 */ 092 public static synchronized AuthenticationProvider getInstance() { 093 if (instance != null) { 094 return instance; 095 } 096 instance = new ServletContainerAuthenticationProvider(); 097 LOGGER.warn("Security is MINIMAL, no Policy Enforcement Point configured."); 098 return instance; 099 } 100 101 /** 102 * @return the principalProviders 103 */ 104 public Set<PrincipalProvider> getPrincipalProviders() { 105 return principalProviders; 106 } 107 108 /** 109 * @param principalProviders the principalProviders to set 110 */ 111 public void setPrincipalProviders( 112 final Set<PrincipalProvider> principalProviders) { 113 this.principalProviders = principalProviders; 114 } 115 116 /** 117 * Authenticate the user that is using the supplied credentials. 118 * <p> 119 * If the credentials given establish that the authenticated user has the 120 * fedoraAdmin role, construct an ExecutionContext with 121 * FedoraAdminSecurityContext as the SecurityContext. Otherwise, construct 122 * an ExecutionContext with FedoraUserSecurityContext as the 123 * SecurityContext. 124 * </p> 125 * <p> 126 * If the authenticated user does not have the fedoraAdmin role, session 127 * attributes will be assigned in the sessionAttributes map: 128 * </p> 129 * <ul> 130 * <li>FEDORA_SERVLET_REQUEST will be assigned the ServletRequest instance 131 * associated with credentials.</li> 132 * <li>FEDORA_ALL_PRINCIPALS will be assigned the union of all principals 133 * obtained from configured PrincipalProvider instances plus the 134 * authenticated user's principal; FEDORA_ALL_PRINCIPALS will be assigned 135 * the singleton set containing the EVERYONE principal otherwise.</li> 136 * </ul> 137 */ 138 @Override 139 public ExecutionContext authenticate(final Credentials credentials, 140 final String repositoryName, final String workspaceName, 141 final ExecutionContext repositoryContext, 142 final Map<String, Object> sessionAttributes) { 143 LOGGER.debug("Trying to authenticate: {}; FAD: {}", credentials, fad); 144 145 if (!(credentials instanceof ServletCredentials)) { 146 return null; 147 } 148 149 final HttpServletRequest servletRequest = 150 ((ServletCredentials) credentials).getRequest(); 151 final Principal userPrincipal = servletRequest.getUserPrincipal(); 152 153 if (userPrincipal != null && 154 servletRequest.isUserInRole(FEDORA_ADMIN_ROLE)) { 155 return repositoryContext.with(new FedoraAdminSecurityContext( 156 userPrincipal.getName())); 157 } 158 159 if (userPrincipal != null) { 160 161 sessionAttributes.put( 162 FedoraAuthorizationDelegate.FEDORA_SERVLET_REQUEST, 163 servletRequest); 164 165 sessionAttributes.put( 166 FedoraAuthorizationDelegate.FEDORA_USER_PRINCIPAL, 167 userPrincipal); 168 169 final Set<Principal> principals = collectPrincipals(credentials); 170 principals.add(userPrincipal); 171 principals.add(EVERYONE); 172 173 sessionAttributes.put( 174 FedoraAuthorizationDelegate.FEDORA_ALL_PRINCIPALS, 175 principals); 176 177 } else { 178 179 sessionAttributes 180 .put(FedoraAuthorizationDelegate.FEDORA_USER_PRINCIPAL, 181 EVERYONE); 182 183 sessionAttributes.put( 184 FedoraAuthorizationDelegate.FEDORA_ALL_PRINCIPALS, 185 Collections.singleton(EVERYONE)); 186 187 } 188 189 return repositoryContext.with(new FedoraUserSecurityContext( 190 userPrincipal, fad)); 191 } 192 193 /** 194 * @return the authorization delegate 195 */ 196 public FedoraAuthorizationDelegate getFad() { 197 return fad; 198 } 199 200 /** 201 * @param fad the authorization delegate to set 202 */ 203 public void setFad(final FedoraAuthorizationDelegate fad) { 204 this.fad = fad; 205 } 206 207 private Set<Principal> collectPrincipals(final Credentials credentials) { 208 final Set<Principal> principals = new HashSet<>(); 209 210 // TODO add exception handling for principal providers 211 for (final PrincipalProvider p : this.getPrincipalProviders()) { 212 final Set<Principal> ps = p.getPrincipals(credentials); 213 214 if (ps != null) { 215 principals.addAll(p.getPrincipals(credentials)); 216 } 217 } 218 219 return principals; 220 } 221}