/* * Copyright (C) 2005-2007 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.security.authentication; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PermissionService; /** * This class implements a simple chaining authentication service. * * It chains together other authentication services so that authentication can happen against more than one authentication service. * * The authentication services it uses are stored as a list. * * Each authentication service must belong to the same domain. This is checked at configuration time. * * Authentication will try each authentication service in order. If any allow authentication given the user name and password then the user will be accepted. * * Additions, deletions and password changes are made to one special authentication service. This service will be tried first for authentication. Users can not be created if they * exist in another authentication service. * * To avoid transactional issues in chaining, the services registered with this service must not have transactional wrappers. If not, errors will mark the transaction for roll back * and we can not chain down the list of authentication services. * * * @author Andy Hind */ public class ChainingAuthenticationServiceImpl extends AbstractAuthenticationService { private List authenticationServices; private AuthenticationService mutableAuthenticationService; public ChainingAuthenticationServiceImpl() { super(); } public List getAuthenticationServices() { return authenticationServices; } public void setAuthenticationServices(List authenticationServices) { this.authenticationServices = authenticationServices; } public AuthenticationService getMutableAuthenticationService() { return mutableAuthenticationService; } public void setMutableAuthenticationService(AuthenticationService mutableAuthenticationService) { this.mutableAuthenticationService = mutableAuthenticationService; } public void createAuthentication(String userName, char[] password) throws AuthenticationException { if (mutableAuthenticationService == null) { throw new AuthenticationException( "Unable to create authentication as there is no suitable authentication service."); } mutableAuthenticationService.createAuthentication(userName, password); } public void updateAuthentication(String userName, char[] oldPassword, char[] newPassword) throws AuthenticationException { if (mutableAuthenticationService == null) { throw new AuthenticationException( "Unable to update authentication as there is no suitable authentication service."); } mutableAuthenticationService.updateAuthentication(userName, oldPassword, newPassword); } public void setAuthentication(String userName, char[] newPassword) throws AuthenticationException { if (mutableAuthenticationService == null) { throw new AuthenticationException( "Unable to set authentication as there is no suitable authentication service."); } mutableAuthenticationService.setAuthentication(userName, newPassword); } public void deleteAuthentication(String userName) throws AuthenticationException { if (mutableAuthenticationService == null) { throw new AuthenticationException( "Unable to delete authentication as there is no suitable authentication service."); } mutableAuthenticationService.deleteAuthentication(userName); } public void setAuthenticationEnabled(String userName, boolean enabled) throws AuthenticationException { if (mutableAuthenticationService == null) { throw new AuthenticationException( "Unable to set authentication enabled as there is no suitable authentication service."); } mutableAuthenticationService.setAuthenticationEnabled(userName, enabled); } public boolean getAuthenticationEnabled(String userName) throws AuthenticationException { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { if (authService.getAuthenticationEnabled(userName)) { return true; } } catch (AuthenticationException e) { // Ignore and chain } } return false; } public void authenticate(String userName, char[] password) throws AuthenticationException { preAuthenticationCheck(userName); for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.authenticate(userName, password); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Failed to authenticate"); } public void authenticateAsGuest() throws AuthenticationException { preAuthenticationCheck(PermissionService.GUEST_AUTHORITY); for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.authenticateAsGuest(); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Guest authentication not supported"); } public boolean guestUserAuthenticationAllowed() { for (AuthenticationService authService : getUsableAuthenticationServices()) { if (authService.guestUserAuthenticationAllowed()) { return true; } } // it isn't allowed in any of the authentication components return false; } public boolean authenticationExists(String userName) { for (AuthenticationService authService : getUsableAuthenticationServices()) { if (authService.authenticationExists(userName)) { return true; } } // it doesn't exist in any of the authentication components return false; } public String getCurrentUserName() throws AuthenticationException { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { return authService.getCurrentUserName(); } catch (AuthenticationException e) { // Ignore and chain } } return null; } public void invalidateUserSession(String userName) throws AuthenticationException { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.invalidateUserSession(userName); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Unable to invalidate user session"); } public void invalidateTicket(String ticket) throws AuthenticationException { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.invalidateTicket(ticket); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Unable to invalidate ticket"); } public void validate(String ticket) throws AuthenticationException { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.validate(ticket); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Unable to validate ticket"); } public String getCurrentTicket() { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { return authService.getCurrentTicket(); } catch (AuthenticationException e) { // Ignore and chain } } return null; } public String getNewTicket() { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { return authService.getNewTicket(); } catch (AuthenticationException e) { // Ignore and chain } } return null; } public void clearCurrentSecurityContext() { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { authService.clearCurrentSecurityContext(); return; } catch (AuthenticationException e) { // Ignore and chain } } throw new AuthenticationException("Failed to clear security context"); } public boolean isCurrentUserTheSystemUser() { for (AuthenticationService authService : getUsableAuthenticationServices()) { try { return authService.isCurrentUserTheSystemUser(); } catch (AuthenticationException e) { // Ignore and chain } } return false; } private List getUsableAuthenticationServices() { if (mutableAuthenticationService == null) { return authenticationServices; } else { ArrayList services = new ArrayList( authenticationServices == null ? 1 : (authenticationServices.size() + 1)); services.add(mutableAuthenticationService); if (authenticationServices != null) { services.addAll(authenticationServices); } return services; } } public Set getDomains() { HashSet domains = new HashSet(); for (AuthenticationService authService : getUsableAuthenticationServices()) { domains.addAll(authService.getDomains()); } return domains; } public Set getDomainsThatAllowUserCreation() { HashSet domains = new HashSet(); if (mutableAuthenticationService != null) { domains.addAll(mutableAuthenticationService.getDomainsThatAllowUserCreation()); } return domains; } public Set getDomainsThatAllowUserDeletion() { HashSet domains = new HashSet(); if (mutableAuthenticationService != null) { domains.addAll(mutableAuthenticationService.getDomainsThatAllowUserDeletion()); } return domains; } public Set getDomiansThatAllowUserPasswordChanges() { HashSet domains = new HashSet(); if (mutableAuthenticationService != null) { domains.addAll(mutableAuthenticationService.getDomiansThatAllowUserPasswordChanges()); } return domains; } @Override public Set getUsersWithTickets(boolean nonExpiredOnly) { HashSet users = new HashSet(); for (AuthenticationService authService : getUsableAuthenticationServices()) { if(authService instanceof AbstractAuthenticationService) { users.addAll( ((AbstractAuthenticationService)authService).getUsersWithTickets(nonExpiredOnly)); } } return users; } @Override public int countTickets(boolean nonExpiredOnly) { int count = 0; for(TicketComponent tc : getTicketComponents()) { count += tc.countTickets(nonExpiredOnly); } return count; } @Override public int invalidateTickets(boolean nonExpiredOnly) { int count = 0; for (AuthenticationService authService : getUsableAuthenticationServices()) { if(authService instanceof AbstractAuthenticationService) { count += ((AbstractAuthenticationService)authService).invalidateTickets(nonExpiredOnly); } } return count; } @Override public Set getTicketComponents() { Set tcs = new HashSet(); for (AuthenticationService authService : getUsableAuthenticationServices()) { if(authService instanceof AbstractAuthenticationService) { tcs.addAll(((AbstractAuthenticationService)authService).getTicketComponents()); } } return tcs; } }