001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.ecm.webengine.jaxrs.login; 020 021import java.io.IOException; 022import java.security.Principal; 023import java.util.Set; 024 025import javax.security.auth.login.LoginContext; 026import javax.security.auth.login.LoginException; 027import javax.servlet.FilterChain; 028import javax.servlet.FilterConfig; 029import javax.servlet.ServletException; 030import javax.servlet.http.HttpServletRequest; 031import javax.servlet.http.HttpServletRequestWrapper; 032import javax.servlet.http.HttpServletResponse; 033 034import org.apache.commons.codec.binary.Base64; 035import org.nuxeo.common.utils.StringUtils; 036import org.nuxeo.ecm.core.api.local.ClientLoginModule; 037import org.nuxeo.ecm.webengine.jaxrs.HttpFilter; 038import org.nuxeo.runtime.api.Framework; 039 040/** 041 * Filter using the {@link SimpleLoginModule} to authenticate a request. 042 * 043 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 044 */ 045public class AuthenticationFilter extends HttpFilter { 046 047 public static final String DEFAULT_SECURITY_DOMAIN = "nuxeo-client-login"; 048 049 protected String domain = DEFAULT_SECURITY_DOMAIN; 050 051 protected boolean autoPrompt = true; 052 053 protected String realmName = "Nuxeo"; 054 055 @Override 056 public void init(FilterConfig filterConfig) throws ServletException { 057 String v = filterConfig.getInitParameter("securityDomain"); 058 if (v != null) { 059 domain = v; 060 } 061 v = filterConfig.getInitParameter("realmName"); 062 if (v != null) { 063 realmName = v; 064 } 065 } 066 067 @Override 068 public void run(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, 069 ServletException { 070 071 LoginContext lc = null; 072 if (request.getUserPrincipal() == null) { 073 try { 074 lc = doLogin(request, response); 075 request = wrapRequest(request, lc); 076 } catch (LoginException e) { 077 // login failed 078 handleLoginFailure(request, response, e); 079 return; 080 } 081 } 082 083 try { 084 chain.doFilter(request, response); 085 } finally { 086 ClientLoginModule.getThreadLocalLogin().clear(); 087 if (lc != null) { 088 // a null lc may indicate an anonymous login 089 try { 090 lc.logout(); 091 } catch (LoginException e) { 092 throw new RuntimeException(e); 093 } 094 } 095 } 096 } 097 098 @Override 099 public void destroy() { 100 } 101 102 protected String[] retrieveBasicLogin(HttpServletRequest httpRequest) { 103 String auth = httpRequest.getHeader("authorization"); 104 if (auth != null && auth.toLowerCase().startsWith("basic")) { 105 int idx = auth.indexOf(' '); 106 String b64userpassword = auth.substring(idx + 1); 107 byte[] clearUp = Base64.decodeBase64(b64userpassword); 108 String userpassword = new String(clearUp); 109 String[] up = StringUtils.split(userpassword, ':', false); 110 if (up.length != 2) { 111 return null; 112 } 113 return up; 114 } 115 return null; 116 } 117 118 protected LoginContext doLogin(HttpServletRequest request, HttpServletResponse response) throws LoginException { 119 String[] login = retrieveBasicLogin(request); 120 if (login != null) { 121 return Framework.login(login[0], login[1]); 122 } 123 // TODO no login provided - use anonymous ? 124 // for now no anonymous user supported - we require a login 125 throw new LoginException("User must login"); 126 // return null; 127 } 128 129 protected void handleLoginFailure(HttpServletRequest request, HttpServletResponse response, LoginException e) { 130 String s = "Basic realm=\"" + realmName + "\""; 131 response.setHeader("WWW-Authenticate", s); 132 response.setStatus(401); 133 } 134 135 protected HttpServletRequest wrapRequest(HttpServletRequest request, LoginContext lc) { 136 Set<Principal> set = lc.getSubject().getPrincipals(); 137 if (!set.isEmpty()) { 138 final Principal principal = set.iterator().next(); 139 return new HttpServletRequestWrapper(request) { 140 @Override 141 public Principal getUserPrincipal() { 142 return principal; 143 } 144 }; 145 } 146 return request; 147 } 148}