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