/**
* 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.login.authentication.openid.web.internal.portlet.action;
import com.liferay.portal.kernel.exception.UserEmailAddressException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.openid.OpenId;
import com.liferay.portal.kernel.portlet.bridges.mvc.BaseMVCActionCommand;
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCActionCommand;
import com.liferay.portal.kernel.security.auth.PrincipalException;
import com.liferay.portal.kernel.servlet.SessionErrors;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.Constants;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.Portal;
import com.liferay.portal.kernel.util.PortletKeys;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.security.sso.openid.OpenIdServiceException;
import com.liferay.portal.security.sso.openid.OpenIdServiceHandler;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* Enables the Sign In portlet to process an OpenID login attempt. When invoked,
* the following steps are carried out.
*
* <ol>
* <li>
* Discover the OpenID provider's XRDS document by performing HTTP GET on
* the user's OpenID URL. This document tells Liferay what the URL of the OpenID
* provider is.
* </li>
* <li>
* Retrieve the OpenID provider's authentication URL which is provided by
* the XRDS document and prepare an OpenID authorization request URL. This URL
* includes a return URL parameter (encoded) which points back to this
* MVCActionRequest with an additional parameter <code>cmd = read</code> (used
* in step 7).
* </li>
* <li>
* Search for an existing Liferay Portal user with the user provided OpenID.
* </li>
* <li>
* If found, redirect the browser to the OpenID authentication request URL
* and wait for the browser to be redirected back to Liferay Portal when all
* steps repeat. Otherwise, ...
* </li>
* <li>
* Generate a valid Liferay Portal user screen name based on the OpenID
* and search for an existing Liferay Portal user with a matching screen name.
* If found, then update the Liferay Portal user’s OpenID to match and redirect
* the browser to the OpenID authentication request URL. Otherwise, ...
* </li>
* <li>
* Enrich the OpenID authentication request URL with a request for specific
* attributes (the user's <code>fullname</code> and <code>email</code>). Then
* redirect the browser to the enriched OpenID authentication request URL.
* </li>
* <li>
* Upon returning from the OpenID provider’s authentication process, the
* MVCActionCommand finds the URL parameter <code>cmd</code> set to
* <code>read</code> (see step 2).
* </li>
* <li>
* The request is verified as being from the same OpenID provider.
* </li>
* <li>
* If the attributes requested in step 6 are not found, then the web browser
* is redirected to the Create Account page where the missing information must
* be entered before a Liferay Portal user can be created. Otherwise, ...
* </li>
* <li>
* The attributes are used to create a Liferay Portal user and the HTTP
* session attribute <code>OPEN_ID_LOGIN</code> is set equal to the Liferay
* Portal user's ID.
* </li>
* </ol>
*
* @author Brian Wing Shun Chan
* @author Jorge Ferrer
*/
@Component(
immediate = true,
property = {
"javax.portlet.name=" + PortletKeys.FAST_LOGIN,
"javax.portlet.name=" + PortletKeys.LOGIN,
"mvc.command.name=/login/openid"
},
service = MVCActionCommand.class
)
public class OpenIdLoginMVCActionCommand extends BaseMVCActionCommand {
@Override
public void doProcessAction(
ActionRequest actionRequest, ActionResponse actionResponse)
throws Exception {
ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
WebKeys.THEME_DISPLAY);
if (!_openId.isEnabled(themeDisplay.getCompanyId())) {
throw new PrincipalException.MustBeEnabled(
themeDisplay.getCompanyId(), OpenId.class.getName());
}
if (actionRequest.getRemoteUser() != null) {
actionResponse.sendRedirect(themeDisplay.getPathMain());
return;
}
String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
try {
if (cmd.equals(Constants.READ)) {
String redirect = _openIdServiceHandler.readResponse(
themeDisplay, actionRequest);
if (Validator.isNull(redirect)) {
redirect = themeDisplay.getURLSignIn();
}
redirect = _portal.escapeRedirect(redirect);
actionResponse.sendRedirect(redirect);
}
else {
_openIdServiceHandler.sendRequest(
themeDisplay, actionRequest, actionResponse);
}
}
catch (Exception e) {
if (e instanceof OpenIdServiceException) {
if (_log.isInfoEnabled()) {
_log.info(
"Error communicating with OpenID provider: " +
e.getMessage());
}
SessionErrors.add(actionRequest, e.getClass());
}
else if (e instanceof
UserEmailAddressException.MustNotBeDuplicate) {
SessionErrors.add(actionRequest, e.getClass());
}
else {
_log.error("Error processing the OpenID login", e);
_portal.sendError(e, actionRequest, actionResponse);
}
}
}
@Reference(unbind = "-")
protected void setOpenId(OpenId openId) {
_openId = openId;
}
@Reference(unbind = "-")
protected void setOpenIdServiceHandler(
OpenIdServiceHandler openIdServiceHandler) {
_openIdServiceHandler = openIdServiceHandler;
}
private static final Log _log = LogFactoryUtil.getLog(
OpenIdLoginMVCActionCommand.class);
private OpenId _openId;
private OpenIdServiceHandler _openIdServiceHandler;
@Reference
private Portal _portal;
}