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