001/*
002  GRANITE DATA SERVICES
003  Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005  This file is part of Granite Data Services.
006
007  Granite Data Services is free software; you can redistribute it and/or modify
008  it under the terms of the GNU Library General Public License as published by
009  the Free Software Foundation; either version 2 of the License, or (at your
010  option) any later version.
011
012  Granite Data Services is distributed in the hope that it will be useful, but
013  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015  for more details.
016
017  You should have received a copy of the GNU Library General Public License
018  along with this library; if not, see <http://www.gnu.org/licenses/>.
019*/
020
021package org.granite.messaging.service.security;
022
023import java.lang.reflect.InvocationTargetException;
024import java.security.Principal;
025import java.util.Map;
026
027import javax.servlet.http.HttpServletRequest;
028import javax.servlet.http.HttpSession;
029
030import org.granite.context.GraniteContext;
031import org.granite.messaging.webapp.HttpGraniteContext;
032import org.mortbay.jetty.HttpConnection;
033import org.mortbay.jetty.Request;
034import org.mortbay.jetty.security.UserRealm;
035
036/**
037 * @author William DRAI
038 */
039public class Jetty7SecurityService extends AbstractSecurityService {
040
041    private static final String JETTY7_AUTH = "org.granite.messaging.service.security.Jetty7Auth";
042
043
044    public Jetty7SecurityService() {
045        super();
046    }
047
048
049    public void configure(Map<String, String> params) {
050    }
051
052
053    public void login(Object credentials, String charset) throws SecurityServiceException {
054        String[] decoded = decodeBase64Credentials(credentials, charset);
055
056        HttpGraniteContext graniteContext = (HttpGraniteContext)GraniteContext.getCurrentInstance();
057        HttpServletRequest httpRequest = graniteContext.getRequest();
058        Request request = httpRequest instanceof Request ? (Request)httpRequest : HttpConnection.getCurrentConnection().getRequest();
059        UserRealm realm = request.getUserRealm();
060
061        Principal principal = realm.authenticate(decoded[0], decoded[1], request);
062        if (principal == null) {
063            if (request.getSession(false) != null)
064                request.getSession(false).removeAttribute(JETTY7_AUTH);
065            throw SecurityServiceException.newInvalidCredentialsException("Wrong username or password");
066        }
067
068        request.setAuthType(AUTH_TYPE);
069        request.setUserPrincipal(principal);
070
071        request.getSession().setAttribute(JETTY7_AUTH, principal);
072        
073        endLogin(credentials, charset);
074    }
075
076
077    public Object authorize(AbstractSecurityContext context) throws Exception {
078
079        startAuthorization(context);
080
081        HttpGraniteContext graniteContext = (HttpGraniteContext)GraniteContext.getCurrentInstance();
082        HttpServletRequest httpRequest = graniteContext.getRequest();
083
084        boolean reauth = false;
085        Principal principal = httpRequest.getUserPrincipal();
086        if (principal == null) {
087            HttpSession session = httpRequest.getSession(false);
088            principal = session != null ? (Principal)session.getAttribute(JETTY7_AUTH) : null;
089            reauth = true;
090        }
091
092        if (principal == null && tryRelogin()) {
093                principal = httpRequest.getUserPrincipal();
094                reauth = false;
095        }
096        
097        if (principal == null) {
098            if (httpRequest.getRequestedSessionId() != null) {
099                HttpSession httpSession = httpRequest.getSession(false);
100                if (httpSession == null || httpRequest.getRequestedSessionId().equals(httpSession.getId()))
101                    throw SecurityServiceException.newSessionExpiredException("Session expired");
102            }
103            throw SecurityServiceException.newNotLoggedInException("User not logged in");
104        }
105
106        Request request = httpRequest instanceof Request ? (Request)httpRequest : HttpConnection.getCurrentConnection().getRequest();
107        UserRealm realm = request.getUserRealm();
108        if (reauth)
109            realm.reauthenticate(principal);
110
111        // Check destination access
112        if (context.getDestination().isSecured()) {
113            boolean accessDenied = true;
114            for (String role : context.getDestination().getRoles()) {
115                if (realm.isUserInRole(principal, role)) {
116                    accessDenied = false;
117                    break;
118                }
119            }
120            if (accessDenied)
121                throw SecurityServiceException.newAccessDeniedException("User not in required role");
122
123            request.setAuthType(AUTH_TYPE);
124            request.setUserPrincipal(principal);
125        }
126
127        try {
128            return endAuthorization(context);
129        } catch (InvocationTargetException e) {
130            for (Throwable t = e; t != null; t = t.getCause()) {
131                if (t instanceof SecurityException)
132                    throw SecurityServiceException.newAccessDeniedException(t.getMessage());
133            }
134            throw e;
135        }
136    }
137
138
139    public void logout() throws SecurityServiceException {
140        HttpGraniteContext graniteContext = (HttpGraniteContext)GraniteContext.getCurrentInstance();
141        HttpServletRequest httpRequest = graniteContext.getRequest();
142        Request request = httpRequest instanceof Request ? (Request)httpRequest : HttpConnection.getCurrentConnection().getRequest();
143        UserRealm realm = request.getUserRealm();
144
145        realm.disassociate(httpRequest.getUserPrincipal());
146        
147        endLogout();
148    }
149}