001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.auth;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.HttpHeaders;
020    import com.liferay.portal.kernel.util.Base64;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.MapUtil;
024    import com.liferay.portal.util.Portal;
025    import com.liferay.portlet.login.util.LoginUtil;
026    
027    import java.util.Properties;
028    import java.util.StringTokenizer;
029    
030    import javax.servlet.http.HttpServletRequest;
031    import javax.servlet.http.HttpServletResponse;
032    
033    /**
034     * <p>
035     * 1. Install Firefox. These instructions assume you have Firefox 2.0.0.1.
036     * Previous version of Firefox have been tested and are known to work.
037     * </p>
038     *
039     * <p>
040     * 2. Install the Modify Headers 0.5.4 Add-on. Tools > Add Ons. Click the get
041     * extensions link at the bottom of the window. Type in "Modify Headers" in the
042     * Search box. Find Modify Headers in the results page and click on it. Then
043     * click the install now link.
044     * </p>
045     *
046     * <p>
047     * 3. Configure Modify Headers to add a basic authentication header. Tools >
048     * Modify Headers. In the Modify Headers window select the Add drop down. Type
049     * in "Authorization" in the next box. Type in "Basic bGlmZXJheS5jb20uMTp0ZXN0"
050     * in the next box. Click the Add button.
051     * </p>
052     *
053     * <p>
054     * 4. Make sure your header modification is enabled and point your browser to
055     * the Liferay portal.
056     * </p>
057     *
058     * <p>
059     * 5. You should now be authenticated as Joe Bloggs.
060     * </p>
061     *
062     * @author Britt Courtney
063     * @author Brian Wing Shun Chan
064     * @author Tomas Polesovsky
065     */
066    public class BasicAuthHeaderAutoLogin implements AuthVerifier, AutoLogin {
067    
068            public String getAuthType() {
069                    return HttpServletRequest.BASIC_AUTH;
070            }
071    
072            public String[] login(
073                            HttpServletRequest request, HttpServletResponse response)
074                    throws AutoLoginException {
075    
076                    try {
077                            String[] credentials = null;
078    
079                            // Get the Authorization header, if one was supplied
080    
081                            String authorization = request.getHeader("Authorization");
082    
083                            if (authorization == null) {
084                                    return credentials;
085                            }
086    
087                            StringTokenizer st = new StringTokenizer(authorization);
088    
089                            if (!st.hasMoreTokens()) {
090                                    return credentials;
091                            }
092    
093                            String basic = st.nextToken();
094    
095                            // We only handle HTTP Basic authentication
096    
097                            if (!basic.equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
098                                    return credentials;
099                            }
100    
101                            String encodedCredentials = st.nextToken();
102    
103                            if (_log.isDebugEnabled()) {
104                                    _log.debug("Encoded credentials are " + encodedCredentials);
105                            }
106    
107                            String decodedCredentials = new String(
108                                    Base64.decode(encodedCredentials));
109    
110                            if (_log.isDebugEnabled()) {
111                                    _log.debug("Decoded credentials are " + decodedCredentials);
112                            }
113    
114                            int pos = decodedCredentials.indexOf(CharPool.COLON);
115    
116                            if (pos == -1) {
117                                    return credentials;
118                            }
119    
120                            String login = GetterUtil.getString(
121                                    decodedCredentials.substring(0, pos));
122                            String password = decodedCredentials.substring(pos + 1);
123    
124                            try {
125                                    long userId = LoginUtil.getAuthenticatedUserId(
126                                            request, login, password, null);
127    
128                                    credentials = new String[3];
129    
130                                    credentials[0] = String.valueOf(userId);
131                                    credentials[1] = password;
132                                    credentials[2] = Boolean.TRUE.toString();
133                            }
134                            catch (Exception e) {
135                                    if (_log.isWarnEnabled()) {
136                                            _log.warn(login + " is not a valid login", e);
137                                    }
138                            }
139    
140                            return credentials;
141                    }
142                    catch (Exception e) {
143                            throw new AutoLoginException(e);
144                    }
145            }
146    
147            public AuthVerifierResult verify(
148                            AccessControlContext accessControlContext, Properties properties)
149                    throws AuthException {
150    
151                    try {
152                            AuthVerifierResult authVerifierResult = new AuthVerifierResult();
153    
154                            String[] credentials = login(
155                                    accessControlContext.getRequest(),
156                                    accessControlContext.getResponse());
157    
158                            if (credentials != null) {
159                                    authVerifierResult.setPassword(credentials[1]);
160                                    authVerifierResult.setState(AuthVerifierResult.State.SUCCESS);
161                                    authVerifierResult.setUserId(Long.valueOf(credentials[0]));
162                            }
163                            else {
164    
165                                    // Deprecated
166    
167                                    boolean forcedBasicAuth = MapUtil.getBoolean(
168                                            accessControlContext.getSettings(), "basic_auth");
169    
170                                    if (forcedBasicAuth) {
171                                            HttpServletResponse response =
172                                                    accessControlContext.getResponse();
173    
174                                            response.setHeader(
175                                                    HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
176    
177                                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
178    
179                                            authVerifierResult.setState(
180                                                    AuthVerifierResult.State.INVALID_CREDENTIALS);
181                                    }
182                            }
183    
184                            return authVerifierResult;
185                    }
186                    catch (AutoLoginException e) {
187                            throw new AuthException(e);
188                    }
189            }
190    
191            private static final String _BASIC_REALM =
192                    "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
193    
194            private static Log _log = LogFactoryUtil.getLog(
195                    BasicAuthHeaderAutoLogin.class);
196    
197    }