/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.sync.security.auth.verifier; import com.google.common.collect.Lists; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.security.auth.AccessControlContext; import com.liferay.portal.kernel.security.auth.AuthException; import com.liferay.portal.kernel.security.auth.http.HttpAuthManagerUtil; import com.liferay.portal.kernel.security.auth.http.HttpAuthorizationHeader; import com.liferay.portal.kernel.security.auth.verifier.AuthVerifier; import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierResult; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.PwdGenerator; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.oauth.jsontoken.Checker; import net.oauth.jsontoken.JsonToken; import net.oauth.jsontoken.JsonTokenParser; import net.oauth.jsontoken.crypto.HmacSHA256Signer; import net.oauth.jsontoken.crypto.HmacSHA256Verifier; import net.oauth.jsontoken.crypto.SignatureAlgorithm; import net.oauth.jsontoken.crypto.Signer; import net.oauth.jsontoken.crypto.Verifier; import net.oauth.jsontoken.discovery.VerifierProvider; import net.oauth.jsontoken.discovery.VerifierProviders; import org.joda.time.Instant; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; /** * @author Michael Young * @author Dennis Ju */ @Component( immediate = true, property = { "auth.verifier.SyncAuthVerifier.urls.includes=/api/jsonws/sync.syncdevice/*,/api/jsonws/sync.syncdlobject/*" } ) public class SyncAuthVerifier implements AuthVerifier { @Override public String getAuthType() { return SyncAuthVerifier.class.getSimpleName(); } public String getUserId(String tokenString) { try { JsonTokenParser jsonTokenParser = getJsonTokenParser(); JsonToken jsonToken = jsonTokenParser.verifyAndDeserialize( tokenString); JsonPrimitive userIdJsonPrimitive = jsonToken.getParamAsPrimitive( "userId"); if (userIdJsonPrimitive == null) { return null; } long userId = userIdJsonPrimitive.getAsLong(); User user = _userLocalService.fetchUser(userId); Date passwordModifiedDate = user.getPasswordModifiedDate(); if (passwordModifiedDate != null) { Instant instant = jsonToken.getIssuedAt(); if (instant.isBefore(passwordModifiedDate.getTime())) { return null; } } return String.valueOf(userId); } catch (Exception e) { return null; } } @Override public AuthVerifierResult verify( AccessControlContext accessControlContext, Properties properties) throws AuthException { AuthVerifierResult authVerifierResult = new AuthVerifierResult(); HttpServletRequest request = accessControlContext.getRequest(); String uri = (String)request.getAttribute(WebKeys.INVOKER_FILTER_URI); if (uri.startsWith("/download/")) { String contextPath = request.getContextPath(); if (!contextPath.equals("/o/sync")) { return authVerifierResult; } } String token = request.getHeader(_TOKEN_HEADER); if (Validator.isNotNull(token)) { String userIdString = getUserId(token); if (userIdString != null) { authVerifierResult.setState(AuthVerifierResult.State.SUCCESS); authVerifierResult.setUserId(Long.valueOf(userIdString)); return authVerifierResult; } } HttpAuthorizationHeader httpAuthorizationHeader = HttpAuthManagerUtil.parse(request); if (httpAuthorizationHeader == null) { // SYNC-1463 Map<String, Object> settings = accessControlContext.getSettings(); settings.remove("basic_auth"); return authVerifierResult; } String scheme = httpAuthorizationHeader.getScheme(); if (!StringUtil.equalsIgnoreCase( scheme, HttpAuthorizationHeader.SCHEME_BASIC)) { return authVerifierResult; } try { long userId = HttpAuthManagerUtil.getBasicUserId(request); if (userId > 0) { token = createToken(userId); if (token != null) { HttpServletResponse response = accessControlContext.getResponse(); response.addHeader(_TOKEN_HEADER, token); } } else { userId = _userLocalService.getDefaultUserId( _portal.getCompanyId(request)); } authVerifierResult.setState(AuthVerifierResult.State.SUCCESS); authVerifierResult.setUserId(userId); return authVerifierResult; } catch (Exception e) { throw new AuthException(e); } } protected String createToken(long userId) { Signer signer = null; try { signer = getSigner(); } catch (Exception e) { return null; } JsonToken jsonToken = new JsonToken(signer); Instant instant = new Instant(); jsonToken.setExpiration(instant.plus(_EXPIRATION)); jsonToken.setIssuedAt(instant); JsonObject payloadJsonObject = jsonToken.getPayloadAsJsonObject(); payloadJsonObject.addProperty("userId", userId); try { return jsonToken.serializeAndSign(); } catch (Exception e) { return null; } } protected JsonTokenParser getJsonTokenParser() throws Exception { if (_jsonTokenParser != null) { return _jsonTokenParser; } final Verifier verifier = new HmacSHA256Verifier(_SECRET.getBytes()); VerifierProvider verifierProvider = new VerifierProvider() { @Override public List<Verifier> findVerifier(String signerId, String keyId) { return Lists.newArrayList(verifier); } }; VerifierProviders verifyProviders = new VerifierProviders(); verifyProviders.setVerifierProvider( SignatureAlgorithm.HS256, verifierProvider); Checker checker = new Checker() { @Override public void check(JsonObject jsonObject) { } }; _jsonTokenParser = new JsonTokenParser(verifyProviders, checker); return _jsonTokenParser; } protected Signer getSigner() { if (_signer != null) { return _signer; } try { _signer = new HmacSHA256Signer(null, null, _SECRET.getBytes()); return _signer; } catch (Exception e) { return null; } } @Reference(unbind = "-") protected void setUserLocalService(UserLocalService userLocalService) { _userLocalService = userLocalService; } private static final long _EXPIRATION = 3600000; private static final String _SECRET = PwdGenerator.getPassword(); private static final String _TOKEN_HEADER = "Sync-JWT"; private static JsonTokenParser _jsonTokenParser; private static Signer _signer; @Reference private Portal _portal; private UserLocalService _userLocalService; }