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.http;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.security.auth.http.HttpAuthManager;
019    import com.liferay.portal.kernel.security.auth.http.HttpAuthManagerUtil;
020    import com.liferay.portal.kernel.security.auth.http.HttpAuthorizationHeader;
021    import com.liferay.portal.kernel.security.auth.session.AuthenticatedSessionManagerUtil;
022    import com.liferay.portal.kernel.servlet.HttpHeaders;
023    import com.liferay.portal.kernel.util.Base64;
024    import com.liferay.portal.kernel.util.CharPool;
025    import com.liferay.portal.kernel.util.HttpUtil;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.UnicodeProperties;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.security.auth.AuthException;
030    import com.liferay.portal.service.UserLocalServiceUtil;
031    import com.liferay.portal.servlet.filters.secure.NonceUtil;
032    import com.liferay.portal.util.Portal;
033    import com.liferay.portal.util.PortalInstances;
034    
035    import java.util.Map;
036    
037    import javax.servlet.http.HttpServletRequest;
038    import javax.servlet.http.HttpServletResponse;
039    
040    /**
041     * @author Tomas Polesovsky
042     */
043    public class HttpAuthManagerImpl implements HttpAuthManager {
044    
045            @Override
046            public void generateChallenge(
047                    HttpServletRequest httpServletRequest,
048                    HttpServletResponse httpServletResponse,
049                    HttpAuthorizationHeader httpAuthorizationHeader) {
050    
051                    if (httpServletRequest == null) {
052                            throw new IllegalArgumentException("HTTP servlet request is null");
053                    }
054    
055                    if (httpServletResponse == null) {
056                            throw new IllegalArgumentException("HTTP servlet response is null");
057                    }
058    
059                    if ((httpAuthorizationHeader == null) ||
060                            Validator.isBlank(httpAuthorizationHeader.getScheme())) {
061    
062                            throw new IllegalArgumentException(
063                                    "HTTP authorization header scheme is null");
064                    }
065    
066                    String realm = httpAuthorizationHeader.getAuthParameter(
067                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_REALM);
068    
069                    if (Validator.isBlank(realm)) {
070                            httpAuthorizationHeader.setAuthParameter(
071                                    HttpAuthorizationHeader.AUTH_PARAMETER_NAME_REALM,
072                                    Portal.PORTAL_REALM);
073                    }
074    
075                    String scheme = httpAuthorizationHeader.getScheme();
076    
077                    if (StringUtil.equalsIgnoreCase(
078                                    scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
079    
080                            generateBasicChallenge(
081                                    httpServletRequest, httpServletResponse,
082                                    httpAuthorizationHeader);
083                    }
084                    else if (StringUtil.equalsIgnoreCase(
085                                            scheme, HttpAuthorizationHeader.SCHEME_DIGEST)) {
086    
087                            generateDigestChallenge(
088                                    httpServletRequest, httpServletResponse,
089                                    httpAuthorizationHeader);
090                    }
091                    else {
092                            throw new UnsupportedOperationException("Scheme " + scheme);
093                    }
094            }
095    
096            @Override
097            public long getBasicUserId(HttpServletRequest httpServletRequest)
098                    throws PortalException {
099    
100                    HttpAuthorizationHeader httpAuthorizationHeader =
101                            HttpAuthManagerUtil.parse(httpServletRequest);
102    
103                    if (httpAuthorizationHeader == null) {
104                            return 0;
105                    }
106    
107                    String scheme = httpAuthorizationHeader.getScheme();
108    
109                    if (!StringUtil.equalsIgnoreCase(
110                                    scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
111    
112                            return 0;
113                    }
114    
115                    return getUserId(httpServletRequest, httpAuthorizationHeader);
116            }
117    
118            @Override
119            public long getDigestUserId(HttpServletRequest httpServletRequest)
120                    throws PortalException {
121    
122                    HttpAuthorizationHeader httpAuthorizationHeader =
123                            HttpAuthManagerUtil.parse(httpServletRequest);
124    
125                    if (httpAuthorizationHeader == null) {
126                            return 0;
127                    }
128    
129                    String scheme = httpAuthorizationHeader.getScheme();
130    
131                    if (!StringUtil.equalsIgnoreCase(
132                                    scheme, HttpAuthorizationHeader.SCHEME_DIGEST)) {
133    
134                            return 0;
135                    }
136    
137                    return getUserId(httpServletRequest, httpAuthorizationHeader);
138            }
139    
140            @Override
141            public long getUserId(
142                            HttpServletRequest httpServletRequest,
143                            HttpAuthorizationHeader httpAuthorizationHeader)
144                    throws PortalException {
145    
146                    if (httpServletRequest == null) {
147                            throw new IllegalArgumentException("HTTP servlet request is null");
148                    }
149    
150                    if ((httpAuthorizationHeader == null) ||
151                            Validator.isBlank(httpAuthorizationHeader.getScheme())) {
152    
153                            throw new IllegalArgumentException(
154                                    "HTTP authorization header scheme is null");
155                    }
156    
157                    String scheme = httpAuthorizationHeader.getScheme();
158    
159                    if (StringUtil.equalsIgnoreCase(
160                                    scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
161    
162                            return getBasicUserId(httpServletRequest, httpAuthorizationHeader);
163                    }
164                    else if (StringUtil.equalsIgnoreCase(
165                                            scheme, HttpAuthorizationHeader.SCHEME_DIGEST)) {
166    
167                            return getDigestUserId(httpServletRequest, httpAuthorizationHeader);
168                    }
169                    else {
170                            throw new UnsupportedOperationException("Scheme " + scheme);
171                    }
172            }
173    
174            @Override
175            public HttpAuthorizationHeader parse(
176                    HttpServletRequest httpServletRequest) {
177    
178                    if (httpServletRequest == null) {
179                            throw new IllegalArgumentException("HTTP servlet request is null");
180                    }
181    
182                    String authorization = httpServletRequest.getHeader(
183                            HttpHeaders.AUTHORIZATION);
184    
185                    if (Validator.isBlank(authorization)) {
186                            return null;
187                    }
188    
189                    String[] authorizationParts = authorization.split("\\s");
190    
191                    String scheme = authorizationParts[0];
192    
193                    if (StringUtil.equalsIgnoreCase(
194                                    scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
195    
196                            return parseBasic(
197                                    httpServletRequest, authorization, authorizationParts);
198                    }
199                    else if (StringUtil.equalsIgnoreCase(
200                                            scheme, HttpAuthorizationHeader.SCHEME_DIGEST)) {
201    
202                            return parseDigest(
203                                    httpServletRequest, authorization, authorizationParts);
204                    }
205                    else {
206                            throw new UnsupportedOperationException("Scheme " + scheme);
207                    }
208            }
209    
210            protected void generateBasicChallenge(
211                    HttpServletRequest httpServletRequest,
212                    HttpServletResponse httpServletResponse,
213                    HttpAuthorizationHeader httpAuthorizationHeader) {
214    
215                    httpServletResponse.setHeader(
216                            HttpHeaders.WWW_AUTHENTICATE, httpAuthorizationHeader.toString());
217    
218                    httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
219            }
220    
221            protected void generateDigestChallenge(
222                    HttpServletRequest httpServletRequest,
223                    HttpServletResponse httpServletResponse,
224                    HttpAuthorizationHeader httpAuthorizationHeader) {
225    
226                    // Must generate a new nonce for each 401 (RFC2617, 3.2.1)
227    
228                    long companyId = PortalInstances.getCompanyId(httpServletRequest);
229    
230                    String remoteAddress = httpServletRequest.getRemoteAddr();
231    
232                    String nonce = NonceUtil.generate(companyId, remoteAddress);
233    
234                    httpAuthorizationHeader.setAuthParameter(
235                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_NONCE, nonce);
236    
237                    httpServletResponse.setHeader(
238                            HttpHeaders.WWW_AUTHENTICATE, httpAuthorizationHeader.toString());
239    
240                    httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
241            }
242    
243            protected long getBasicUserId(
244                            HttpServletRequest httpServletRequest,
245                            HttpAuthorizationHeader httpAuthorizationHeader)
246                    throws PortalException {
247    
248                    String login = httpAuthorizationHeader.getAuthParameter(
249                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME);
250                    String password = httpAuthorizationHeader.getAuthParameter(
251                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD);
252    
253                    // Strip @uid and @sn for backwards compatibility
254    
255                    if (login.endsWith("@uid")) {
256                            int pos = login.indexOf("@uid");
257    
258                            login = login.substring(0, pos);
259                    }
260                    else if (login.endsWith("@sn")) {
261                            int pos = login.indexOf("@sn");
262    
263                            login = login.substring(0, pos);
264                    }
265    
266                    try {
267                            return AuthenticatedSessionManagerUtil.getAuthenticatedUserId(
268                                    httpServletRequest, login, password, null);
269                    }
270                    catch (AuthException ae) {
271                    }
272    
273                    return 0;
274            }
275    
276            protected long getDigestUserId(
277                            HttpServletRequest httpServletRequest,
278                            HttpAuthorizationHeader httpAuthorizationHeader)
279                    throws PortalException {
280    
281                    long userId = 0;
282    
283                    String username = httpAuthorizationHeader.getAuthParameter(
284                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME);
285                    String realm = httpAuthorizationHeader.getAuthParameter(
286                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_REALM);
287                    String nonce = httpAuthorizationHeader.getAuthParameter(
288                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_NONCE);
289                    String uri = httpAuthorizationHeader.getAuthParameter(
290                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_URI);
291                    String response = httpAuthorizationHeader.getAuthParameter(
292                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_RESPONSE);
293    
294                    if (Validator.isNull(username) || Validator.isNull(realm) ||
295                            Validator.isNull(nonce) || Validator.isNull(uri) ||
296                            Validator.isNull(response)) {
297    
298                            return userId;
299                    }
300    
301                    if (!realm.equals(Portal.PORTAL_REALM) ||
302                            !uri.equals(httpServletRequest.getRequestURI())) {
303    
304                            return userId;
305                    }
306    
307                    if (!NonceUtil.verify(nonce)) {
308                            return userId;
309                    }
310    
311                    long companyId = PortalInstances.getCompanyId(httpServletRequest);
312    
313                    userId = UserLocalServiceUtil.authenticateForDigest(
314                            companyId, username, realm, nonce, httpServletRequest.getMethod(),
315                            uri, response);
316    
317                    return userId;
318            }
319    
320            protected HttpAuthorizationHeader parseBasic(
321                    HttpServletRequest httpServletRequest, String authorization,
322                    String[] authorizationParts) {
323    
324                    String credentials = new String(Base64.decode(authorizationParts[1]));
325    
326                    String[] loginAndPassword = StringUtil.split(
327                            credentials, CharPool.COLON);
328    
329                    String login = HttpUtil.decodeURL(loginAndPassword[0].trim());
330    
331                    String password = null;
332    
333                    if (loginAndPassword.length > 1) {
334                            password = loginAndPassword[1].trim();
335                    }
336    
337                    HttpAuthorizationHeader httpAuthorizationHeader =
338                            new HttpAuthorizationHeader(HttpAuthorizationHeader.SCHEME_BASIC);
339    
340                    httpAuthorizationHeader.setAuthParameter(
341                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME, login);
342    
343                    httpAuthorizationHeader.setAuthParameter(
344                            HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD, password);
345    
346                    return httpAuthorizationHeader;
347            }
348    
349            protected HttpAuthorizationHeader parseDigest(
350                    HttpServletRequest httpServletRequest, String authorization,
351                    String[] authorizationHeaderParts) {
352    
353                    HttpAuthorizationHeader httpAuthorizationHeader =
354                            new HttpAuthorizationHeader(HttpAuthorizationHeader.SCHEME_DIGEST);
355    
356                    authorization = authorization.substring(
357                            HttpAuthorizationHeader.SCHEME_DIGEST.length() + 1);
358    
359                    authorization = StringUtil.replace(
360                            authorization, CharPool.COMMA, CharPool.NEW_LINE);
361    
362                    UnicodeProperties authorizationProperties = new UnicodeProperties();
363    
364                    authorizationProperties.fastLoad(authorization);
365    
366                    for (Map.Entry<String, String> authorizationProperty :
367                                    authorizationProperties.entrySet()) {
368    
369                            String key = authorizationProperty.getKey();
370                            String value = StringUtil.unquote(
371                                    authorizationProperties.getProperty(key));
372    
373                            httpAuthorizationHeader.setAuthParameter(key, value);
374                    }
375    
376                    return httpAuthorizationHeader;
377            }
378    
379    }