/**
* 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.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.granite.context.GraniteContext;
import org.granite.messaging.webapp.HttpGraniteContext;
import org.granite.messaging.webapp.ServletGraniteContext;
/**
* @author William DRAI
*/
public class Jetty8SecurityService extends AbstractSecurityService {
public void configure(Map<String, String> params) {
}
@Override
public void prelogin(HttpSession session, Object httpRequest, String servletName) {
if (session == null) // Cannot prelogin() without a session
return;
if (session.getAttribute(AuthenticationContext.class.getName()) instanceof Jetty8AuthenticationContext)
return;
Request request = (Request)httpRequest;
Authentication authentication = request.getAuthentication();
UserIdentity.Scope scope = request.getUserIdentityScope();
Jetty8AuthenticationContext authorizationContext = new Jetty8AuthenticationContext(scope, authentication);
session.setAttribute(AuthenticationContext.class.getName(), authorizationContext);
}
public Principal login(Object credentials, String charset) throws SecurityServiceException {
String[] decoded = decodeBase64Credentials(credentials, charset);
ServletGraniteContext graniteContext = (ServletGraniteContext)GraniteContext.getCurrentInstance();
Principal principal = null;
if (graniteContext instanceof HttpGraniteContext) {
HttpServletRequest httpRequest = graniteContext.getRequest();
Request request = (Request)httpRequest;
Authentication authentication = request.getAuthentication();
UserIdentity.Scope scope = request.getUserIdentityScope();
Jetty8AuthenticationContext authenticationContext = new Jetty8AuthenticationContext(scope, authentication);
principal = authenticationContext.authenticate(decoded[0], decoded[1]);
if (principal != null)
graniteContext.getSession().setAttribute(AuthenticationContext.class.getName(), authenticationContext);
}
else {
AuthenticationContext authenticationContext = (AuthenticationContext)graniteContext.getSession().getAttribute(AuthenticationContext.class.getName());
if (authenticationContext != null)
principal = authenticationContext.authenticate(decoded[0], decoded[1]);
else
return null;
}
if (principal == null)
throw SecurityServiceException.newInvalidCredentialsException("Wrong username or password");
graniteContext.setPrincipal(principal);
endLogin(credentials, charset);
return principal;
}
public Object authorize(AbstractSecurityContext context) throws Exception {
startAuthorization(context);
ServletGraniteContext graniteContext = (ServletGraniteContext)GraniteContext.getCurrentInstance();
HttpServletRequest httpRequest = null;
AuthenticationContext authenticationContext = null;
Principal principal = null;
if (graniteContext instanceof HttpGraniteContext) {
httpRequest = graniteContext.getRequest();
HttpSession session = httpRequest.getSession(false);
if (session != null) {
authenticationContext = (AuthenticationContext)session.getAttribute(AuthenticationContext.class.getName());
if (authenticationContext != null) {
principal = authenticationContext.getPrincipal();
((Request)httpRequest).setAuthentication(((Jetty8AuthenticationContext)authenticationContext).getAuthentication());
}
if (principal == null && tryRelogin()) {
Request request = (Request)httpRequest;
Authentication authentication = request.getAuthentication();
if (authentication instanceof Authentication.User)
principal = ((Authentication.User)authentication).getUserIdentity().getUserPrincipal();
}
}
}
else {
HttpSession session = graniteContext.getSession(false);
if (session != null) {
authenticationContext = (AuthenticationContext)session.getAttribute(AuthenticationContext.class.getName());
if (authenticationContext != null)
principal = authenticationContext.getPrincipal();
}
}
graniteContext.setPrincipal(principal);
if (context.getDestination().isSecured()) {
if (principal == null) {
if (httpRequest != null && httpRequest.getRequestedSessionId() != null) {
HttpSession httpSession = httpRequest.getSession(false);
if (httpSession == null || !httpRequest.getRequestedSessionId().equals(httpSession.getId()))
throw SecurityServiceException.newSessionExpiredException("Session expired");
}
throw SecurityServiceException.newNotLoggedInException("User not logged in");
}
if (httpRequest == null && authenticationContext == null)
throw SecurityServiceException.newNotLoggedInException("No authorization context");
boolean accessDenied = true;
for (String role : context.getDestination().getRoles()) {
if (httpRequest != null && httpRequest.isUserInRole(role)) {
accessDenied = false;
break;
}
if (authenticationContext != null && authenticationContext.isUserInRole(role)) {
accessDenied = false;
break;
}
}
if (accessDenied)
throw SecurityServiceException.newAccessDeniedException("User not in required role");
}
try {
return endAuthorization(context);
} catch (InvocationTargetException e) {
for (Throwable t = e; t != null; t = t.getCause()) {
if (t instanceof SecurityException)
throw SecurityServiceException.newAccessDeniedException(t.getMessage());
}
throw e;
}
}
public void logout() throws SecurityServiceException {
ServletGraniteContext graniteContext = (ServletGraniteContext)GraniteContext.getCurrentInstance();
if (graniteContext instanceof HttpGraniteContext) {
Request request = (Request)graniteContext.getRequest();
Authentication authentication = request.getAuthentication();
if (authentication instanceof Authentication.User)
((Authentication.User)authentication).logout();
if (request.getSession(false) != null) {
endLogout();
try {
request.getSession(false).invalidate();
}
catch (IllegalStateException e) {
// Session already invalid
}
}
}
else {
HttpSession session = graniteContext.getSession();
if (session != null) {
AuthenticationContext authenticationContext = (AuthenticationContext)session.getAttribute(AuthenticationContext.class.getName());
authenticationContext.logout();
try {
session.removeAttribute(AuthenticationContext.class.getName());
}
catch (IllegalStateException e) {
// Session already invalid
}
endLogout();
try {
session.invalidate();
}
catch (IllegalStateException e) {
// Session already invalid
}
}
}
}
public static class Jetty8AuthenticationContext implements AuthenticationContext {
private static final long serialVersionUID = 1L;
private transient final UserIdentity.Scope scope;
private transient Authentication authentication;
private transient Principal principal;
public Jetty8AuthenticationContext(UserIdentity.Scope scope, Authentication authentication) {
this.scope = scope;
this.authentication = authentication;
}
public Principal authenticate(String username, String password) {
if (authentication == null)
throw SecurityServiceException.newAuthenticationFailedException("Invalid authentication");
if (authentication instanceof Authentication.Deferred)
authentication = ((Authentication.Deferred)authentication).login(username, password, ((ServletGraniteContext)GraniteContext.getCurrentInstance()).getRequest());
if (authentication instanceof Authentication.User)
principal = ((Authentication.User)authentication).getUserIdentity().getUserPrincipal();
return principal;
}
public boolean isValid() {
return principal != null;
}
public Principal getPrincipal() {
return principal;
}
public Authentication getAuthentication() {
return authentication;
}
public boolean isUserInRole(String role) {
if (authentication instanceof Authentication.User)
return ((Authentication.User)authentication).isUserInRole(scope, role);
return false;
}
public void logout() {
if (authentication instanceof Authentication.User)
((Authentication.User)authentication).logout();
}
}
}