/** * 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.portal.security.sso.openid.internal; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.portlet.LiferayPortletResponse; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.servlet.SessionMessages; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.Constants; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.Http; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.PwdGenerator; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.security.sso.openid.OpenIdProvider; import com.liferay.portal.security.sso.openid.OpenIdProviderRegistry; import com.liferay.portal.security.sso.openid.OpenIdServiceException; import com.liferay.portal.security.sso.openid.OpenIdServiceHandler; import com.liferay.portal.security.sso.openid.constants.OpenIdWebKeys; import java.io.IOException; import java.util.Calendar; import java.util.List; import java.util.Locale; import java.util.Map; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.PortletURL; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.openid4java.association.AssociationException; import org.openid4java.consumer.ConsumerException; import org.openid4java.consumer.ConsumerManager; import org.openid4java.consumer.InMemoryConsumerAssociationStore; import org.openid4java.consumer.InMemoryNonceVerifier; import org.openid4java.consumer.VerificationResult; import org.openid4java.discovery.DiscoveryException; import org.openid4java.discovery.DiscoveryInformation; import org.openid4java.discovery.Identifier; import org.openid4java.message.AuthRequest; import org.openid4java.message.AuthSuccess; import org.openid4java.message.MessageException; import org.openid4java.message.MessageExtension; import org.openid4java.message.ParameterList; import org.openid4java.message.ax.AxMessage; import org.openid4java.message.ax.FetchRequest; import org.openid4java.message.ax.FetchResponse; import org.openid4java.message.sreg.SRegMessage; import org.openid4java.message.sreg.SRegRequest; import org.openid4java.message.sreg.SRegResponse; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; /** * @author Michael C. Han */ @Component(immediate = true, service = OpenIdServiceHandler.class) public class OpenIdServiceHandlerImpl implements OpenIdServiceHandler { @Override public String readResponse( ThemeDisplay themeDisplay, ActionRequest actionRequest) throws PortalException { HttpServletRequest request = _portal.getHttpServletRequest( actionRequest); request = _portal.getOriginalServletRequest(request); String receivingURL = ParamUtil.getString(request, "openid.return_to"); ParameterList parameterList = new ParameterList( request.getParameterMap()); HttpSession session = request.getSession(); DiscoveryInformation discoveryInformation = (DiscoveryInformation)session.getAttribute( OpenIdWebKeys.OPEN_ID_DISCO); if (discoveryInformation == null) { return null; } AuthSuccess authSuccess = null; String firstName = null; String lastName = null; String emailAddress = null; try { VerificationResult verificationResult = _consumerManager.verify( receivingURL, parameterList, discoveryInformation); Identifier identifier = verificationResult.getVerifiedId(); if (identifier == null) { return null; } authSuccess = (AuthSuccess)verificationResult.getAuthResponse(); firstName = null; lastName = null; emailAddress = null; if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) { MessageExtension messageExtension = authSuccess.getExtension( SRegMessage.OPENID_NS_SREG); if (messageExtension instanceof SRegResponse) { SRegResponse sregResp = (SRegResponse)messageExtension; String fullName = GetterUtil.getString( sregResp.getAttributeValue( _OPEN_ID_SREG_ATTR_FULLNAME)); String[] names = splitFullName(fullName); if (names != null) { firstName = names[0]; lastName = names[1]; } emailAddress = sregResp.getAttributeValue( _OPEN_ID_SREG_ATTR_EMAIL); } } if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) { MessageExtension messageExtension = authSuccess.getExtension( AxMessage.OPENID_NS_AX); if (messageExtension instanceof FetchResponse) { FetchResponse fetchResponse = (FetchResponse)messageExtension; OpenIdProvider openIdProvider = _openIdProviderRegistry.getOpenIdProvider( discoveryInformation.getOPEndpoint()); String[] openIdAXTypes = openIdProvider.getAxSchema(); for (String openIdAXType : openIdAXTypes) { if (openIdAXType.equals(_OPEN_ID_AX_ATTR_EMAIL)) { if (Validator.isNull(emailAddress)) { emailAddress = getFirstValue( fetchResponse.getAttributeValues( _OPEN_ID_AX_ATTR_EMAIL)); } } else if (openIdAXType.equals( _OPEN_ID_AX_ATTR_FIRST_NAME)) { if (Validator.isNull(firstName)) { firstName = getFirstValue( fetchResponse.getAttributeValues( _OPEN_ID_AX_ATTR_FIRST_NAME)); } } else if (openIdAXType.equals( _OPEN_ID_AX_ATTR_FULL_NAME)) { String fullName = fetchResponse.getAttributeValue( _OPEN_ID_AX_ATTR_FULL_NAME); String[] names = splitFullName(fullName); if (names != null) { if (Validator.isNull(firstName)) { firstName = names[0]; } if (Validator.isNull(lastName)) { lastName = names[1]; } } } else if (openIdAXType.equals( _OPEN_ID_AX_ATTR_LAST_NAME)) { if (Validator.isNull(lastName)) { lastName = getFirstValue( fetchResponse.getAttributeValues( _OPEN_ID_AX_ATTR_LAST_NAME)); } } } } } } catch (AssociationException ae) { throw new OpenIdServiceException.AssociationException( ae.getMessage(), ae); } catch (DiscoveryException de) { throw new OpenIdServiceException.DiscoveryException( de.getMessage(), de); } catch (MessageException me) { throw new OpenIdServiceException.MessageException( me.getMessage(), me); } String openId = normalize(authSuccess.getIdentity()); User user = _userLocalService.fetchUserByOpenId( themeDisplay.getCompanyId(), openId); if (user != null) { session.setAttribute(WebKeys.OPEN_ID_LOGIN, user.getUserId()); return null; } try { if (Validator.isNull(firstName) || Validator.isNull(lastName) || Validator.isNull(emailAddress)) { SessionMessages.add(request, "openIdUserInformationMissing"); if (_log.isInfoEnabled()) { _log.info( "The OpenID provider did not send the required " + "attributes to create an account"); } String createAccountURL = _portal.getCreateAccountURL( request, themeDisplay); String portletId = _http.getParameter( createAccountURL, "p_p_id", false); String portletNamespace = _portal.getPortletNamespace( portletId); createAccountURL = _http.setParameter( createAccountURL, portletNamespace + "openId", openId); session.setAttribute( WebKeys.OPEN_ID_LOGIN_PENDING, Boolean.TRUE); return createAccountURL; } } catch (Exception e) { throw new PortalException(e); } long creatorUserId = 0; long companyId = themeDisplay.getCompanyId(); boolean autoPassword = false; String password1 = PwdGenerator.getPassword(); String password2 = password1; boolean autoScreenName = true; String screenName = StringPool.BLANK; long facebookId = 0; Locale locale = themeDisplay.getLocale(); String middleName = StringPool.BLANK; long prefixId = 0; long suffixId = 0; boolean male = true; int birthdayMonth = Calendar.JANUARY; int birthdayDay = 1; int birthdayYear = 1970; String jobTitle = StringPool.BLANK; long[] groupIds = null; long[] organizationIds = null; long[] roleIds = null; long[] userGroupIds = null; boolean sendEmail = false; ServiceContext serviceContext = new ServiceContext(); user = _userLocalService.addUser( creatorUserId, companyId, autoPassword, password1, password2, autoScreenName, screenName, emailAddress, facebookId, openId, locale, firstName, middleName, lastName, prefixId, suffixId, male, birthdayMonth, birthdayDay, birthdayYear, jobTitle, groupIds, organizationIds, roleIds, userGroupIds, sendEmail, serviceContext); session.setAttribute(WebKeys.OPEN_ID_LOGIN, user.getUserId()); return null; } @Override public void sendRequest( ThemeDisplay themeDisplay, ActionRequest actionRequest, ActionResponse actionResponse) throws PortalException { HttpServletRequest request = _portal.getHttpServletRequest( actionRequest); request = _portal.getOriginalServletRequest(request); HttpServletResponse response = _portal.getHttpServletResponse( actionResponse); HttpSession session = request.getSession(); LiferayPortletResponse liferayPortletResponse = _portal.getLiferayPortletResponse(actionResponse); String openId = ParamUtil.getString(actionRequest, "openId"); PortletURL portletURL = liferayPortletResponse.createActionURL(); portletURL.setParameter(ActionRequest.ACTION_NAME, "/login/openid"); portletURL.setParameter("saveLastPath", Boolean.FALSE.toString()); portletURL.setParameter("mvcRenderCommandName", "/login/openid"); portletURL.setParameter(Constants.CMD, Constants.READ); try { List<DiscoveryInformation> discoveryInformationList = _consumerManager.discover(openId); DiscoveryInformation discoveryInformation = _consumerManager.associate(discoveryInformationList); session.setAttribute( OpenIdWebKeys.OPEN_ID_DISCO, discoveryInformation); AuthRequest authRequest = _consumerManager.authenticate( discoveryInformation, portletURL.toString(), themeDisplay.getPortalURL()); if (_userLocalService.fetchUserByOpenId( themeDisplay.getCompanyId(), openId) != null) { response.sendRedirect(authRequest.getDestinationUrl(true)); return; } String screenName = getScreenName(openId); User user = _userLocalService.fetchUserByScreenName( themeDisplay.getCompanyId(), screenName); if (user != null) { _userLocalService.updateOpenId(user.getUserId(), openId); response.sendRedirect(authRequest.getDestinationUrl(true)); return; } FetchRequest fetchRequest = FetchRequest.createFetchRequest(); OpenIdProvider openIdProvider = _openIdProviderRegistry.getOpenIdProvider( discoveryInformation.getOPEndpoint()); Map<String, String> openIdAXTypes = openIdProvider.getAxTypes(); for (Map.Entry<String, String> entry : openIdAXTypes.entrySet()) { fetchRequest.addAttribute( entry.getKey(), entry.getValue(), true); } authRequest.addExtension(fetchRequest); SRegRequest sRegRequest = SRegRequest.createFetchRequest(); sRegRequest.addAttribute(_OPEN_ID_SREG_ATTR_EMAIL, true); sRegRequest.addAttribute(_OPEN_ID_SREG_ATTR_FULLNAME, true); authRequest.addExtension(sRegRequest); response.sendRedirect(authRequest.getDestinationUrl(true)); } catch (ConsumerException ce) { throw new OpenIdServiceException.ConsumerException( ce.getMessage(), ce); } catch (DiscoveryException de) { throw new OpenIdServiceException.DiscoveryException( de.getMessage(), de); } catch (MessageException me) { throw new OpenIdServiceException.MessageException( me.getMessage(), me); } catch (IOException ioe) { throw new SystemException( "Unable to communicate with OpenId provider", ioe); } } @Activate @Modified protected void activate() { try { _consumerManager = new ConsumerManager(); _consumerManager.setAssociations( new InMemoryConsumerAssociationStore()); _consumerManager.setNonceVerifier(new InMemoryNonceVerifier(5000)); } catch (Exception e) { throw new IllegalStateException( "Unable to start consumer manager", e); } } protected String getFirstValue(List<String> values) { if ((values == null) || values.isEmpty()) { return null; } return values.get(0); } protected String getScreenName(String openId) { String screenName = normalize(openId); if (screenName.startsWith(Http.HTTP_WITH_SLASH)) { screenName = screenName.substring(Http.HTTP_WITH_SLASH.length()); } if (screenName.startsWith(Http.HTTPS_WITH_SLASH)) { screenName = screenName.substring(Http.HTTPS_WITH_SLASH.length()); } screenName = StringUtil.replace( screenName, new char[] {CharPool.SLASH, CharPool.UNDERLINE}, new char[] {CharPool.PERIOD, CharPool.PERIOD}); return screenName; } protected String normalize(String identity) { if (identity.endsWith(StringPool.SLASH)) { return identity.substring(0, identity.length() - 1); } return identity; } @Reference(unbind = "-") protected void setOpenIdProviderRegistry( OpenIdProviderRegistry openIdProviderRegistry) { _openIdProviderRegistry = openIdProviderRegistry; } @Reference(unbind = "-") protected void setUserLocalService(UserLocalService userLocalService) { _userLocalService = userLocalService; } protected String[] splitFullName(String fullName) { if (Validator.isNull(fullName)) { return null; } int pos = fullName.indexOf(CharPool.SPACE); if ((pos != -1) && ((pos + 1) < fullName.length())) { String[] names = new String[2]; names[0] = fullName.substring(0, pos); names[1] = fullName.substring(pos + 1); return names; } return null; } private static final String _OPEN_ID_AX_ATTR_EMAIL = "email"; private static final String _OPEN_ID_AX_ATTR_FIRST_NAME = "firstname"; private static final String _OPEN_ID_AX_ATTR_FULL_NAME = "fullname"; private static final String _OPEN_ID_AX_ATTR_LAST_NAME = "lastname"; private static final String _OPEN_ID_SREG_ATTR_EMAIL = "email"; private static final String _OPEN_ID_SREG_ATTR_FULLNAME = "fullname"; private static final Log _log = LogFactoryUtil.getLog( OpenIdServiceHandlerImpl.class); private ConsumerManager _consumerManager; @Reference private Http _http; private OpenIdProviderRegistry _openIdProviderRegistry; @Reference private Portal _portal; private UserLocalService _userLocalService; }