/** * GRANITE DATA SERVICES * Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S. * * This file is part of the Granite Data Services Platform. * * Granite Data Services is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Granite Data Services 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA, or see <http://www.gnu.org/licenses/>. */ package org.granite.messaging.service.security; import java.lang.reflect.InvocationTargetException; import java.security.Principal; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.acegisecurity.AbstractAuthenticationManager; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.userdetails.UsernameNotFoundException; import org.granite.context.GraniteContext; import org.granite.logging.Logger; import org.granite.messaging.webapp.HttpGraniteContext; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * @author Francisco PEREDO */ public class AcegiSecurityService extends AbstractSecurityService { private static final Logger log = Logger.getLogger(AcegiSecurityService.class); private static final String SPRING_AUTHENTICATION_TOKEN = AcegiSecurityService.class.getName() + ".SPRING_AUTHENTICATION_TOKEN"; public AcegiSecurityService() { log.debug("Starting Service!"); } public void configure(Map<String, String> params) { log.debug("Configuring with parameters (NOOP) %s: ", params); } public Principal login(Object credentials, String charset) { List<String> decodedCredentials = Arrays.asList(decodeBase64Credentials(credentials, charset)); HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); HttpServletRequest httpRequest = context.getRequest(); String user = decodedCredentials.get(0); String password = decodedCredentials.get(1); Authentication auth = new UsernamePasswordAuthenticationToken(user, password); Principal principal = null; ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext( httpRequest.getSession().getServletContext() ); if (ctx != null) { AbstractAuthenticationManager authenticationManager = BeanFactoryUtils.beanOfTypeIncludingAncestors(ctx, AbstractAuthenticationManager.class); try { Authentication authentication = authenticationManager.authenticate(auth); SecurityContextHolder.getContext().setAuthentication(authentication); principal = authentication; httpRequest.getSession().setAttribute(SPRING_AUTHENTICATION_TOKEN, authentication); endLogin(credentials, charset); } catch (AuthenticationException e) { handleAuthenticationExceptions(e); } } log.debug("User %s logged in", user); return principal; } protected void handleAuthenticationExceptions(AuthenticationException e) { if (e instanceof BadCredentialsException || e instanceof UsernameNotFoundException) throw SecurityServiceException.newInvalidCredentialsException(e.getMessage()); throw SecurityServiceException.newAuthenticationFailedException(e.getMessage()); } public Object authorize(AbstractSecurityContext context) throws Exception { log.debug("Authorize: %s", context); log.debug("Is %s secured? %b", context.getDestination().getId(), context.getDestination().isSecured()); startAuthorization(context); Authentication authentication = getAuthentication(); if (context.getDestination().isSecured()) { if (!isAuthenticated(authentication)) { log.debug("Is not authenticated!"); throw SecurityServiceException.newNotLoggedInException("User not logged in"); } if (!userCanAccessService(context, authentication)) { log.debug("Access denied for: %s", authentication.getName()); throw SecurityServiceException.newAccessDeniedException("User not in required role"); } } if (isAuthenticated(authentication)) { SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); } try { return endAuthorization(context); } catch (InvocationTargetException e) { handleAuthorizationExceptions(e); throw e; } finally { SecurityContextHolder.clearContext(); } } public void logout() { HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); context.getSession().invalidate(); SecurityContextHolder.getContext().setAuthentication(null); SecurityContextHolder.clearContext(); } protected boolean isUserInRole(Authentication authentication, String role) { for (GrantedAuthority ga : authentication.getAuthorities()) { if (ga.getAuthority().matches(role)) return true; } return false; } protected boolean isAuthenticated(Authentication authentication) { return authentication != null && authentication.isAuthenticated(); } protected boolean userCanAccessService(AbstractSecurityContext context, Authentication authentication) { log.debug("Is authenticated as: %s", authentication.getName()); for (String role : context.getDestination().getRoles()) { if (isUserInRole(authentication, role)) { log.debug("Allowed access to %s in role %s", authentication.getName(), role); return true; } log.debug("Access denied for %s not in role %s", authentication.getName(), role); } return false; } protected Authentication getAuthentication() { HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance(); HttpServletRequest httpRequest = context.getRequest(); Authentication authentication = (Authentication) httpRequest.getSession().getAttribute(SPRING_AUTHENTICATION_TOKEN); return authentication; } protected void handleAuthorizationExceptions(InvocationTargetException e) { for (Throwable t = e; t != null; t = t.getCause()) { // Don't create a dependency to javax.ejb in SecurityService... if (t instanceof SecurityException || t instanceof AccessDeniedException || "javax.ejb.EJBAccessException".equals(t.getClass().getName())) throw SecurityServiceException.newAccessDeniedException(t.getMessage()); } } }