001    /**
002     * Copyright (c) 2000-2013 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.kernel.util.StringUtil;
025    import com.liferay.portal.util.Portal;
026    import com.liferay.portlet.login.util.LoginUtil;
027    
028    import java.util.Properties;
029    import java.util.StringTokenizer;
030    
031    import javax.servlet.http.HttpServletRequest;
032    import javax.servlet.http.HttpServletResponse;
033    
034    /**
035     * <p>
036     * 1. Install Firefox. These instructions assume you have Firefox 2.0.0.1.
037     * Previous version of Firefox have been tested and are known to work.
038     * </p>
039     *
040     * <p>
041     * 2. Install the Modify Headers 0.5.4 Add-on. Tools > Add Ons. Click the get
042     * extensions link at the bottom of the window. Type in "Modify Headers" in the
043     * Search box. Find Modify Headers in the results page and click on it. Then
044     * click the install now link.
045     * </p>
046     *
047     * <p>
048     * 3. Configure Modify Headers to add a basic authentication header. Tools >
049     * Modify Headers. In the Modify Headers window select the Add drop down. Type
050     * in "Authorization" in the next box. Type in "Basic bGlmZXJheS5jb20uMTp0ZXN0"
051     * in the next box. Click the Add button.
052     * </p>
053     *
054     * <p>
055     * 4. Make sure your header modification is enabled and point your browser to
056     * the Liferay portal.
057     * </p>
058     *
059     * <p>
060     * 5. You should now be authenticated as Joe Bloggs.
061     * </p>
062     *
063     * @author Britt Courtney
064     * @author Brian Wing Shun Chan
065     * @author Tomas Polesovsky
066     */
067    public class BasicAuthHeaderAutoLogin
068            extends BaseAutoLogin implements AuthVerifier {
069    
070            @Override
071            public String getAuthType() {
072                    return HttpServletRequest.BASIC_AUTH;
073            }
074    
075            @Override
076            public AuthVerifierResult verify(
077                            AccessControlContext accessControlContext, Properties properties)
078                    throws AuthException {
079    
080                    try {
081                            AuthVerifierResult authVerifierResult = new AuthVerifierResult();
082    
083                            String[] credentials = login(
084                                    accessControlContext.getRequest(),
085                                    accessControlContext.getResponse());
086    
087                            if (credentials != null) {
088                                    authVerifierResult.setPassword(credentials[1]);
089                                    authVerifierResult.setState(AuthVerifierResult.State.SUCCESS);
090                                    authVerifierResult.setUserId(Long.valueOf(credentials[0]));
091                            }
092                            else {
093    
094                                    // Deprecated
095    
096                                    boolean forcedBasicAuth = MapUtil.getBoolean(
097                                            accessControlContext.getSettings(), "basic_auth");
098    
099                                    if (forcedBasicAuth) {
100                                            HttpServletResponse response =
101                                                    accessControlContext.getResponse();
102    
103                                            response.setHeader(
104                                                    HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
105    
106                                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
107    
108                                            authVerifierResult.setState(
109                                                    AuthVerifierResult.State.INVALID_CREDENTIALS);
110                                    }
111                            }
112    
113                            return authVerifierResult;
114                    }
115                    catch (AutoLoginException ale) {
116                            throw new AuthException(ale);
117                    }
118            }
119    
120            @Override
121            protected String[] doLogin(
122                            HttpServletRequest request, HttpServletResponse response)
123                    throws Exception {
124    
125                    // Get the Authorization header, if one was supplied
126    
127                    String authorization = request.getHeader("Authorization");
128    
129                    if (authorization == null) {
130                            return null;
131                    }
132    
133                    StringTokenizer st = new StringTokenizer(authorization);
134    
135                    if (!st.hasMoreTokens()) {
136                            return null;
137                    }
138    
139                    String basic = st.nextToken();
140    
141                    // We only handle HTTP Basic authentication
142    
143                    if (!StringUtil.equalsIgnoreCase(
144                                    basic, HttpServletRequest.BASIC_AUTH)) {
145    
146                            return null;
147                    }
148    
149                    String encodedCredentials = st.nextToken();
150    
151                    if (_log.isDebugEnabled()) {
152                            _log.debug("Encoded credentials are " + encodedCredentials);
153                    }
154    
155                    String decodedCredentials = new String(
156                            Base64.decode(encodedCredentials));
157    
158                    if (_log.isDebugEnabled()) {
159                            _log.debug("Decoded credentials are " + decodedCredentials);
160                    }
161    
162                    int pos = decodedCredentials.indexOf(CharPool.COLON);
163    
164                    if (pos == -1) {
165                            return null;
166                    }
167    
168                    String login = GetterUtil.getString(
169                            decodedCredentials.substring(0, pos));
170                    String password = decodedCredentials.substring(pos + 1);
171    
172                    long userId = LoginUtil.getAuthenticatedUserId(
173                            request, login, password, null);
174    
175                    String[] credentials = new String[3];
176    
177                    credentials[0] = String.valueOf(userId);
178                    credentials[1] = password;
179                    credentials[2] = Boolean.TRUE.toString();
180    
181                    return credentials;
182            }
183    
184            private static final String _BASIC_REALM =
185                    "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
186    
187            private static Log _log = LogFactoryUtil.getLog(
188                    BasicAuthHeaderAutoLogin.class);
189    
190    }