1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.action;
24  
25  import com.liferay.portal.DuplicateUserEmailAddressException;
26  import com.liferay.portal.NoSuchUserException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.servlet.SessionErrors;
30  import com.liferay.portal.kernel.servlet.SessionMessages;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.User;
35  import com.liferay.portal.service.UserLocalServiceUtil;
36  import com.liferay.portal.theme.ThemeDisplay;
37  import com.liferay.portal.util.OpenIdUtil;
38  import com.liferay.portal.util.PortalUtil;
39  import com.liferay.portal.util.WebKeys;
40  import com.liferay.util.PwdGenerator;
41  
42  import java.util.Calendar;
43  import java.util.List;
44  import java.util.Locale;
45  
46  import javax.portlet.PortletURL;
47  
48  import javax.servlet.http.HttpServletRequest;
49  import javax.servlet.http.HttpServletResponse;
50  import javax.servlet.http.HttpSession;
51  
52  import org.apache.struts.action.Action;
53  import org.apache.struts.action.ActionForm;
54  import org.apache.struts.action.ActionForward;
55  import org.apache.struts.action.ActionMapping;
56  
57  import org.openid4java.association.AssociationException;
58  import org.openid4java.consumer.ConsumerException;
59  import org.openid4java.consumer.ConsumerManager;
60  import org.openid4java.consumer.VerificationResult;
61  import org.openid4java.discovery.DiscoveryException;
62  import org.openid4java.discovery.DiscoveryInformation;
63  import org.openid4java.discovery.Identifier;
64  import org.openid4java.message.AuthSuccess;
65  import org.openid4java.message.MessageException;
66  import org.openid4java.message.MessageExtension;
67  import org.openid4java.message.ParameterList;
68  import org.openid4java.message.ax.AxMessage;
69  import org.openid4java.message.ax.FetchResponse;
70  import org.openid4java.message.sreg.SRegMessage;
71  import org.openid4java.message.sreg.SRegResponse;
72  
73  /**
74   * <a href="OpenIdResponseAction.java.html"><b><i>View Source</i></b></a>
75   *
76   * @author Jorge Ferrer
77   */
78  public class OpenIdResponseAction extends Action {
79  
80      public ActionForward execute(
81              ActionMapping mapping, ActionForm form, HttpServletRequest request,
82              HttpServletResponse response)
83          throws Exception {
84  
85          ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
86              WebKeys.THEME_DISPLAY);
87  
88          if (!OpenIdUtil.isEnabled(themeDisplay.getCompanyId())) {
89              return null;
90          }
91  
92          String redirect = null;
93  
94          try {
95              redirect = readResponse(themeDisplay, request);
96          }
97          catch (Exception e) {
98              if (e instanceof AssociationException ||
99                  e instanceof ConsumerException ||
100                 e instanceof DiscoveryException ||
101                 e instanceof DuplicateUserEmailAddressException ||
102                 e instanceof MessageException) {
103 
104                 SessionErrors.add(request, e.getClass().getName());
105 
106                 return mapping.findForward("portal.login");
107             }
108             else {
109                 _log.error("Error processing OpenID response", e);
110 
111                 PortalUtil.sendError(e, request, response);
112 
113                 return null;
114             }
115         }
116 
117         if (Validator.isNull(redirect)) {
118             redirect =
119                 PortalUtil.getPortalURL(request) + themeDisplay.getURLSignIn();
120         }
121 
122         response.sendRedirect(redirect);
123 
124         return null;
125     }
126 
127     protected User addUser(
128             long companyId, String firstName, String lastName,
129             String emailAddress, String openId, Locale locale)
130         throws Exception {
131 
132         long creatorUserId = 0;
133         boolean autoPassword = false;
134         String password1 = PwdGenerator.getPassword();
135         String password2 = password1;
136         boolean autoScreenName = true;
137         String screenName = StringPool.BLANK;
138         String middleName = StringPool.BLANK;
139         int prefixId = 0;
140         int suffixId = 0;
141         boolean male = true;
142         int birthdayMonth = Calendar.JANUARY;
143         int birthdayDay = 1;
144         int birthdayYear = 1970;
145         String jobTitle = StringPool.BLANK;
146         long[] organizationIds = new long[0];
147         boolean sendEmail = false;
148 
149         User user = UserLocalServiceUtil.addUser(
150             creatorUserId, companyId, autoPassword, password1, password2,
151             autoScreenName, screenName, emailAddress, locale, firstName,
152             middleName, lastName, prefixId, suffixId, male, birthdayMonth,
153             birthdayDay, birthdayYear, jobTitle, organizationIds, sendEmail);
154 
155         UserLocalServiceUtil.updateOpenId(user.getUserId(), openId);
156 
157         return user;
158     }
159 
160     protected String getFirstValue(List<String> values) {
161         if ((values == null) || (values.size() < 1)) {
162             return null;
163         }
164 
165         return values.get(0);
166     }
167 
168     protected String readResponse(
169             ThemeDisplay themeDisplay, HttpServletRequest request)
170         throws Exception {
171 
172         HttpSession session = request.getSession();
173 
174         ConsumerManager manager = OpenIdUtil.getConsumerManager();
175 
176         ParameterList params = new ParameterList(request.getParameterMap());
177 
178         DiscoveryInformation discovered =
179             (DiscoveryInformation)session.getAttribute(WebKeys.OPEN_ID_DISCO);
180 
181         if (discovered == null) {
182             return null;
183         }
184 
185         StringBuffer receivingURL = request.getRequestURL();
186         String queryString = request.getQueryString();
187 
188         if ((queryString != null) && (queryString.length() > 0)) {
189             receivingURL.append(StringPool.QUESTION);
190             receivingURL.append(request.getQueryString());
191         }
192 
193         VerificationResult verification = manager.verify(
194             receivingURL.toString(), params, discovered);
195 
196         Identifier verified = verification.getVerifiedId();
197 
198         if (verified == null) {
199             return null;
200         }
201 
202         AuthSuccess authSuccess = (AuthSuccess)verification.getAuthResponse();
203 
204         String firstName = null;
205         String lastName = null;
206         String emailAddress = null;
207 
208         if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) {
209             MessageExtension ext = authSuccess.getExtension(
210                 SRegMessage.OPENID_NS_SREG);
211 
212             if (ext instanceof SRegResponse) {
213                 SRegResponse sregResp = (SRegResponse)ext;
214 
215                 String fullName = GetterUtil.getString(
216                     sregResp.getAttributeValue("fullname"));
217 
218                 int pos = fullName.indexOf(StringPool.SPACE);
219 
220                 if ((pos != -1) && ((pos + 1) < fullName.length())) {
221                     firstName = fullName.substring(0, pos);
222                     lastName = fullName.substring(pos + 1);
223                 }
224 
225                 emailAddress = sregResp.getAttributeValue("email");
226             }
227         }
228 
229         if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
230             MessageExtension ext = authSuccess.getExtension(
231                 AxMessage.OPENID_NS_AX);
232 
233             if (ext instanceof FetchResponse) {
234                 FetchResponse fetchResp = (FetchResponse)ext;
235 
236                 if (Validator.isNull(firstName)) {
237                     firstName = getFirstValue(
238                         fetchResp.getAttributeValues("firstName"));
239                 }
240 
241                 if (Validator.isNull(lastName)) {
242                     lastName = getFirstValue(
243                         fetchResp.getAttributeValues("lastName"));
244                 }
245 
246                 if (Validator.isNull(emailAddress)) {
247                     emailAddress = getFirstValue(
248                         fetchResp.getAttributeValues("email"));
249                 }
250             }
251         }
252 
253         String openId = OpenIdUtil.normalize(authSuccess.getIdentity());
254 
255         User user = null;
256 
257         try {
258             user = UserLocalServiceUtil.getUserByOpenId(openId);
259         }
260         catch (NoSuchUserException nsue) {
261             if (Validator.isNull(firstName) || Validator.isNull(lastName) ||
262                 Validator.isNull(emailAddress)) {
263 
264                 SessionMessages.add(request, "missingOpenIdUserInformation");
265 
266                 if (_log.isInfoEnabled()) {
267                     _log.info(
268                         "The OpenID provider did not send the required " +
269                             "attributes to create an account");
270                 }
271 
272                 PortletURL createAccountURL =
273                     themeDisplay.getURLCreateAccount();
274 
275                 createAccountURL.setParameter("openId", openId);
276 
277                 session.setAttribute(
278                     WebKeys.OPEN_ID_LOGIN_PENDING, Boolean.TRUE);
279 
280                 return createAccountURL.toString();
281             }
282 
283             user = addUser(
284                 themeDisplay.getCompanyId(), firstName, lastName, emailAddress,
285                 openId, themeDisplay.getLocale());
286         }
287 
288         session.setAttribute(WebKeys.OPEN_ID_LOGIN, new Long(user.getUserId()));
289 
290         return null;
291     }
292 
293     private static Log _log = LogFactoryUtil.getLog(OpenIdResponseAction.class);
294 
295 }