001    /**
002     * Copyright (c) 2000-2011 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.portlet.login.action;
016    
017    import com.liferay.portal.DuplicateUserEmailAddressException;
018    import com.liferay.portal.NoSuchUserException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.servlet.SessionErrors;
022    import com.liferay.portal.kernel.servlet.SessionMessages;
023    import com.liferay.portal.kernel.util.CharPool;
024    import com.liferay.portal.kernel.util.Constants;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.HttpUtil;
027    import com.liferay.portal.kernel.util.ParamUtil;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.model.User;
031    import com.liferay.portal.service.ServiceContext;
032    import com.liferay.portal.service.UserLocalServiceUtil;
033    import com.liferay.portal.struts.PortletAction;
034    import com.liferay.portal.theme.ThemeDisplay;
035    import com.liferay.portal.util.OpenIdUtil;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.WebKeys;
038    import com.liferay.portlet.ActionResponseImpl;
039    import com.liferay.util.PwdGenerator;
040    
041    import java.util.Calendar;
042    import java.util.List;
043    import java.util.Locale;
044    
045    import javax.portlet.ActionRequest;
046    import javax.portlet.ActionResponse;
047    import javax.portlet.PortletConfig;
048    import javax.portlet.PortletURL;
049    import javax.portlet.RenderRequest;
050    import javax.portlet.RenderResponse;
051    
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpServletResponse;
054    import javax.servlet.http.HttpSession;
055    
056    import org.apache.struts.action.ActionForm;
057    import org.apache.struts.action.ActionForward;
058    import org.apache.struts.action.ActionMapping;
059    
060    import org.openid4java.OpenIDException;
061    import org.openid4java.consumer.ConsumerManager;
062    import org.openid4java.consumer.VerificationResult;
063    import org.openid4java.discovery.DiscoveryInformation;
064    import org.openid4java.discovery.Identifier;
065    import org.openid4java.message.AuthRequest;
066    import org.openid4java.message.AuthSuccess;
067    import org.openid4java.message.MessageExtension;
068    import org.openid4java.message.ParameterList;
069    import org.openid4java.message.ax.AxMessage;
070    import org.openid4java.message.ax.FetchRequest;
071    import org.openid4java.message.ax.FetchResponse;
072    import org.openid4java.message.sreg.SRegMessage;
073    import org.openid4java.message.sreg.SRegRequest;
074    import org.openid4java.message.sreg.SRegResponse;
075    
076    /**
077     * @author Brian Wing Shun Chan
078     * @author Jorge Ferrer
079     */
080    public class OpenIdAction extends PortletAction {
081    
082            @Override
083            public void processAction(
084                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
085                            ActionRequest actionRequest, ActionResponse actionResponse)
086                    throws Exception {
087    
088                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
089                            WebKeys.THEME_DISPLAY);
090    
091                    if (actionRequest.getRemoteUser() != null) {
092                            actionResponse.sendRedirect(themeDisplay.getPathMain());
093    
094                            return;
095                    }
096    
097                    String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
098    
099                    try {
100                            if (cmd.equals(Constants.READ)) {
101                                    String redirect = readOpenIdResponse(
102                                            themeDisplay, actionRequest, actionResponse);
103    
104                                    if (Validator.isNull(redirect)) {
105                                            redirect =
106                                                    PortalUtil.getPortalURL(actionRequest) +
107                                                            themeDisplay.getURLSignIn();
108                                    }
109    
110                                    sendRedirect(actionRequest, actionResponse, redirect);
111                            }
112                            else {
113                                    sendOpenIdRequest(themeDisplay, actionRequest, actionResponse);
114                            }
115                    }
116                    catch (Exception e) {
117                            if (e instanceof DuplicateUserEmailAddressException) {
118                                    SessionErrors.add(actionRequest, e.getClass().getName());
119                            }
120                            else if (e instanceof OpenIDException) {
121                                    if (_log.isInfoEnabled()) {
122                                            _log.info(
123                                                    "Error communicating with OpenID provider: " +
124                                                            e.getMessage());
125                                    }
126    
127                                    SessionErrors.add(actionRequest, e.getClass().getName());
128                            }
129                            else {
130                                    _log.error("Error processing the OpenID login", e);
131    
132                                    PortalUtil.sendError(e, actionRequest, actionResponse);
133                            }
134                    }
135            }
136    
137            @Override
138            public ActionForward render(
139                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
140                            RenderRequest renderRequest, RenderResponse renderResponse)
141                    throws Exception {
142    
143                    ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
144                            WebKeys.THEME_DISPLAY);
145    
146                    renderResponse.setTitle(themeDisplay.translate("open-id"));
147    
148                    return mapping.findForward("portlet.login.open_id");
149            }
150    
151            protected String getFirstValue(List<String> values) {
152                    if ((values == null) || (values.size() < 1)) {
153                            return null;
154                    }
155    
156                    return values.get(0);
157            }
158    
159            @Override
160            protected boolean isCheckMethodOnProcessAction() {
161                    return _CHECK_METHOD_ON_PROCESS_ACTION;
162            }
163    
164            protected String readOpenIdResponse(
165                            ThemeDisplay themeDisplay, ActionRequest actionRequest,
166                            ActionResponse actionResponse)
167                    throws Exception {
168    
169                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
170                            actionRequest);
171                    HttpSession session = request.getSession();
172    
173                    ConsumerManager manager = OpenIdUtil.getConsumerManager();
174    
175                    ParameterList params = new ParameterList(
176                            actionRequest.getParameterMap());
177    
178                    DiscoveryInformation discovered =
179                            (DiscoveryInformation)session.getAttribute(WebKeys.OPEN_ID_DISCO);
180    
181                    if (discovered == null) {
182                            return null;
183                    }
184    
185                    String receivingUrl = ParamUtil.getString(
186                            actionRequest, "openid.return_to");
187    
188                    VerificationResult verification = manager.verify(
189                            receivingUrl, params, discovered);
190    
191                    Identifier verified = verification.getVerifiedId();
192    
193                    if (verified == null) {
194                            return null;
195                    }
196    
197                    AuthSuccess authSuccess = (AuthSuccess)verification.getAuthResponse();
198    
199                    String firstName = null;
200                    String lastName = null;
201                    String emailAddress = null;
202    
203                    if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) {
204                            MessageExtension ext = authSuccess.getExtension(
205                                    SRegMessage.OPENID_NS_SREG);
206    
207                            if (ext instanceof SRegResponse) {
208                                    SRegResponse sregResp = (SRegResponse)ext;
209    
210                                    String fullName = GetterUtil.getString(
211                                            sregResp.getAttributeValue("fullname"));
212    
213                                    int pos = fullName.indexOf(CharPool.SPACE);
214    
215                                    if ((pos != -1) && ((pos + 1) < fullName.length())) {
216                                            firstName = fullName.substring(0, pos);
217                                            lastName = fullName.substring(pos + 1);
218                                    }
219    
220                                    emailAddress = sregResp.getAttributeValue("email");
221                            }
222                    }
223    
224                    if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
225                            MessageExtension ext = authSuccess.getExtension(
226                                    AxMessage.OPENID_NS_AX);
227    
228                            if (ext instanceof FetchResponse) {
229                                    FetchResponse fetchResp = (FetchResponse)ext;
230    
231                                    if (Validator.isNull(firstName)) {
232                                            firstName = getFirstValue(
233                                                    fetchResp.getAttributeValues("firstName"));
234                                    }
235    
236                                    if (Validator.isNull(lastName)) {
237                                            lastName = getFirstValue(
238                                                    fetchResp.getAttributeValues("lastName"));
239                                    }
240    
241                                    if (Validator.isNull(emailAddress)) {
242                                            emailAddress = getFirstValue(
243                                                    fetchResp.getAttributeValues("email"));
244                                    }
245                            }
246                    }
247    
248                    String openId = OpenIdUtil.normalize(authSuccess.getIdentity());
249    
250                    User user = null;
251    
252                    try {
253                            user = UserLocalServiceUtil.getUserByOpenId(
254                                    themeDisplay.getCompanyId(), openId);
255                    }
256                    catch (NoSuchUserException nsue) {
257                            if (Validator.isNull(firstName) || Validator.isNull(lastName) ||
258                                    Validator.isNull(emailAddress)) {
259    
260                                    SessionMessages.add(request, "missingOpenIdUserInformation");
261    
262                                    if (_log.isInfoEnabled()) {
263                                            _log.info(
264                                                    "The OpenID provider did not send the required " +
265                                                            "attributes to create an account");
266                                    }
267    
268                                    String createAccountURL = PortalUtil.getCreateAccountURL(
269                                            request, themeDisplay);
270    
271                                    createAccountURL = HttpUtil.setParameter(
272                                            createAccountURL, "openId", openId);
273    
274                                    session.setAttribute(
275                                            WebKeys.OPEN_ID_LOGIN_PENDING, Boolean.TRUE);
276    
277                                    return createAccountURL;
278                            }
279    
280                            long creatorUserId = 0;
281                            long companyId = themeDisplay.getCompanyId();
282                            boolean autoPassword = false;
283                            String password1 = PwdGenerator.getPassword();
284                            String password2 = password1;
285                            boolean autoScreenName = true;
286                            String screenName = StringPool.BLANK;
287                            long facebookId = 0;
288                            Locale locale = themeDisplay.getLocale();
289                            String middleName = StringPool.BLANK;
290                            int prefixId = 0;
291                            int suffixId = 0;
292                            boolean male = true;
293                            int birthdayMonth = Calendar.JANUARY;
294                            int birthdayDay = 1;
295                            int birthdayYear = 1970;
296                            String jobTitle = StringPool.BLANK;
297                            long[] groupIds = null;
298                            long[] organizationIds = null;
299                            long[] roleIds = null;
300                            long[] userGroupIds = null;
301                            boolean sendEmail = false;
302    
303                            ServiceContext serviceContext = new ServiceContext();
304    
305                            user = UserLocalServiceUtil.addUser(
306                                    creatorUserId, companyId, autoPassword, password1, password2,
307                                    autoScreenName, screenName, emailAddress, facebookId, openId,
308                                    locale, firstName, middleName, lastName, prefixId, suffixId,
309                                    male, birthdayMonth, birthdayDay, birthdayYear, jobTitle,
310                                    groupIds, organizationIds, roleIds, userGroupIds, sendEmail,
311                                    serviceContext);
312                    }
313    
314                    session.setAttribute(WebKeys.OPEN_ID_LOGIN, new Long(user.getUserId()));
315    
316                    return null;
317            }
318    
319            protected void sendOpenIdRequest(
320                            ThemeDisplay themeDisplay, ActionRequest actionRequest,
321                            ActionResponse actionResponse)
322                    throws Exception {
323    
324                    if (!OpenIdUtil.isEnabled(themeDisplay.getCompanyId())) {
325                            return;
326                    }
327    
328                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
329                            actionRequest);
330                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
331                            actionResponse);
332                    HttpSession session = request.getSession();
333    
334                    ActionResponseImpl actionResponseImpl =
335                            (ActionResponseImpl)actionResponse;
336    
337                    String openId = ParamUtil.getString(actionRequest, "openId");
338    
339                    PortletURL portletURL = actionResponseImpl.createActionURL();
340    
341                    portletURL.setParameter("struts_action", "/login/open_id");
342                    portletURL.setParameter(Constants.CMD, Constants.READ);
343                    portletURL.setParameter("saveLastPath", "0");
344    
345                    ConsumerManager manager = OpenIdUtil.getConsumerManager();
346    
347                    List<DiscoveryInformation> discoveries = manager.discover(openId);
348    
349                    DiscoveryInformation discovered = manager.associate(discoveries);
350    
351                    session.setAttribute(WebKeys.OPEN_ID_DISCO, discovered);
352    
353                    AuthRequest authRequest = manager.authenticate(
354                            discovered, portletURL.toString(), themeDisplay.getPortalURL());
355    
356                    try {
357                            UserLocalServiceUtil.getUserByOpenId(
358                                    themeDisplay.getCompanyId(), openId);
359                    }
360                    catch (NoSuchUserException nsue) {
361                            String screenName = OpenIdUtil.getScreenName(openId);
362    
363                            try {
364                                    User user = UserLocalServiceUtil.getUserByScreenName(
365                                            themeDisplay.getCompanyId(), screenName);
366    
367                                    UserLocalServiceUtil.updateOpenId(user.getUserId(), openId);
368                            }
369                            catch (NoSuchUserException nsue2) {
370                                    FetchRequest fetch = FetchRequest.createFetchRequest();
371    
372                                    fetch.addAttribute(
373                                            "email", "http://schema.openid.net/contact/email", true);
374                                    fetch.addAttribute(
375                                            "firstName", "http://schema.openid.net/namePerson/first",
376                                            true);
377                                    fetch.addAttribute(
378                                            "lastName", "http://schema.openid.net/namePerson/last",
379                                            true);
380    
381                                    authRequest.addExtension(fetch);
382    
383                                    SRegRequest sregRequest = SRegRequest.createFetchRequest();
384    
385                                    sregRequest.addAttribute("fullname", true);
386                                    sregRequest.addAttribute("email", true);
387    
388                                    authRequest.addExtension(sregRequest);
389                            }
390                    }
391    
392                    response.sendRedirect(authRequest.getDestinationUrl(true));
393            }
394    
395            private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
396    
397            private static Log _log = LogFactoryUtil.getLog(OpenIdAction.class);
398    
399    }