001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022package org.granite.messaging.service.security; 023 024import java.lang.reflect.InvocationTargetException; 025import java.util.Arrays; 026import java.util.List; 027import java.util.Map; 028 029import javax.servlet.http.HttpServletRequest; 030 031import org.acegisecurity.AbstractAuthenticationManager; 032import org.acegisecurity.AccessDeniedException; 033import org.acegisecurity.Authentication; 034import org.acegisecurity.AuthenticationException; 035import org.acegisecurity.BadCredentialsException; 036import org.acegisecurity.GrantedAuthority; 037import org.acegisecurity.context.SecurityContext; 038import org.acegisecurity.context.SecurityContextHolder; 039import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; 040import org.acegisecurity.userdetails.UsernameNotFoundException; 041import org.granite.context.GraniteContext; 042import org.granite.logging.Logger; 043import org.granite.messaging.webapp.HttpGraniteContext; 044import org.springframework.beans.factory.BeanFactoryUtils; 045import org.springframework.context.ApplicationContext; 046import org.springframework.web.context.support.WebApplicationContextUtils; 047 048/** 049 * @author Francisco PEREDO 050 */ 051public class AcegiSecurityService extends AbstractSecurityService { 052 053 private static final Logger log = Logger.getLogger(AcegiSecurityService.class); 054 private static final String SPRING_AUTHENTICATION_TOKEN = AcegiSecurityService.class.getName() + ".SPRING_AUTHENTICATION_TOKEN"; 055 056 public AcegiSecurityService() { 057 log.debug("Starting Service!"); 058 } 059 060 public void configure(Map<String, String> params) { 061 log.debug("Configuring with parameters (NOOP) %s: ", params); 062 } 063 064 public void login(Object credentials, String charset) { 065 List<String> decodedCredentials = Arrays.asList(decodeBase64Credentials(credentials, charset)); 066 067 HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); 068 HttpServletRequest httpRequest = context.getRequest(); 069 070 String user = decodedCredentials.get(0); 071 String password = decodedCredentials.get(1); 072 Authentication auth = new UsernamePasswordAuthenticationToken(user, password); 073 074 ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext( 075 httpRequest.getSession().getServletContext() 076 ); 077 if (ctx != null) { 078 AbstractAuthenticationManager authenticationManager = 079 BeanFactoryUtils.beanOfTypeIncludingAncestors(ctx, AbstractAuthenticationManager.class); 080 try { 081 Authentication authentication = authenticationManager.authenticate(auth); 082 SecurityContextHolder.getContext().setAuthentication(authentication); 083 httpRequest.getSession().setAttribute(SPRING_AUTHENTICATION_TOKEN, authentication); 084 085 endLogin(credentials, charset); 086 } 087 catch (AuthenticationException e) { 088 handleAuthenticationExceptions(e); 089 } 090 } 091 092 log.debug("User %s logged in", user); 093 } 094 095 protected void handleAuthenticationExceptions(AuthenticationException e) { 096 if (e instanceof BadCredentialsException || e instanceof UsernameNotFoundException) 097 throw SecurityServiceException.newInvalidCredentialsException(e.getMessage()); 098 099 throw SecurityServiceException.newAuthenticationFailedException(e.getMessage()); 100 } 101 102 public Object authorize(AbstractSecurityContext context) throws Exception { 103 log.debug("Authorize: %s", context); 104 log.debug("Is %s secured? %b", context.getDestination().getId(), context.getDestination().isSecured()); 105 106 startAuthorization(context); 107 108 Authentication authentication = getAuthentication(); 109 if (context.getDestination().isSecured()) { 110 if (!isAuthenticated(authentication)) { 111 log.debug("Is not authenticated!"); 112 throw SecurityServiceException.newNotLoggedInException("User not logged in"); 113 } 114 if (!userCanAccessService(context, authentication)) { 115 log.debug("Access denied for: %s", authentication.getName()); 116 throw SecurityServiceException.newAccessDeniedException("User not in required role"); 117 } 118 } 119 if (isAuthenticated(authentication)) { 120 SecurityContext securityContext = SecurityContextHolder.getContext(); 121 securityContext.setAuthentication(authentication); 122 } 123 124 try { 125 return endAuthorization(context); 126 } catch (InvocationTargetException e) { 127 handleAuthorizationExceptions(e); 128 throw e; 129 } 130 finally { 131 SecurityContextHolder.clearContext(); 132 } 133 } 134 135 public void logout() { 136 HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); 137 context.getSession().invalidate(); 138 SecurityContextHolder.getContext().setAuthentication(null); 139 SecurityContextHolder.clearContext(); 140 } 141 142 protected boolean isUserInRole(Authentication authentication, String role) { 143 for (GrantedAuthority ga : authentication.getAuthorities()) { 144 if (ga.getAuthority().matches(role)) 145 return true; 146 } 147 return false; 148 } 149 150 protected boolean isAuthenticated(Authentication authentication) { 151 return authentication != null && authentication.isAuthenticated(); 152 } 153 154 protected boolean userCanAccessService(AbstractSecurityContext context, Authentication authentication) { 155 log.debug("Is authenticated as: %s", authentication.getName()); 156 157 for (String role : context.getDestination().getRoles()) { 158 if (isUserInRole(authentication, role)) { 159 log.debug("Allowed access to %s in role %s", authentication.getName(), role); 160 return true; 161 } 162 log.debug("Access denied for %s not in role %s", authentication.getName(), role); 163 } 164 return false; 165 } 166 167 protected Authentication getAuthentication() { 168 HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); 169 HttpServletRequest httpRequest = context.getRequest(); 170 Authentication authentication = 171 (Authentication) httpRequest.getSession().getAttribute(SPRING_AUTHENTICATION_TOKEN); 172 return authentication; 173 } 174 175 protected void handleAuthorizationExceptions(InvocationTargetException e) { 176 for (Throwable t = e; t != null; t = t.getCause()) { 177 // Don't create a dependency to javax.ejb in SecurityService... 178 if (t instanceof SecurityException || 179 t instanceof AccessDeniedException || 180 "javax.ejb.EJBAccessException".equals(t.getClass().getName())) 181 throw SecurityServiceException.newAccessDeniedException(t.getMessage()); 182 } 183 } 184}