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