1   /**
2    * Copyright (c) 2000-2008 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.servlet.SessionErrors;
28  import com.liferay.portal.kernel.servlet.SessionMessages;
29  import com.liferay.portal.kernel.util.GetterUtil;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.Validator;
32  import com.liferay.portal.model.User;
33  import com.liferay.portal.service.UserLocalServiceUtil;
34  import com.liferay.portal.theme.ThemeDisplay;
35  import com.liferay.portal.util.OpenIdUtil;
36  import com.liferay.portal.util.PortalUtil;
37  import com.liferay.portal.util.WebKeys;
38  import com.liferay.util.PwdGenerator;
39  
40  import java.util.Calendar;
41  import java.util.List;
42  import java.util.Locale;
43  
44  import javax.portlet.PortletURL;
45  
46  import javax.servlet.http.HttpServletRequest;
47  import javax.servlet.http.HttpServletResponse;
48  import javax.servlet.http.HttpSession;
49  
50  import org.apache.commons.logging.Log;
51  import org.apache.commons.logging.LogFactory;
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   */
79  public class OpenIdResponseAction extends Action {
80  
81      public ActionForward execute(
82              ActionMapping mapping, ActionForm form, HttpServletRequest request,
83              HttpServletResponse response)
84          throws Exception {
85  
86          ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
87              WebKeys.THEME_DISPLAY);
88  
89          if (!OpenIdUtil.isEnabled(themeDisplay.getCompanyId())) {
90              return null;
91          }
92  
93          String redirect = null;
94  
95          try {
96              redirect = readResponse(themeDisplay, request);
97          }
98          catch (Exception e) {
99              if (e instanceof AssociationException ||
100                 e instanceof ConsumerException ||
101                 e instanceof DiscoveryException ||
102                 e instanceof DuplicateUserEmailAddressException ||
103                 e instanceof MessageException) {
104 
105                 SessionErrors.add(request, e.getClass().getName());
106 
107                 return mapping.findForward("portal.login");
108             }
109             else {
110                 _log.error("Error processing OpenID response", e);
111 
112                 PortalUtil.sendError(e, request, response);
113 
114                 return null;
115             }
116         }
117 
118         if (Validator.isNull(redirect)) {
119             redirect =
120                 PortalUtil.getPortalURL(request) + themeDisplay.getURLSignIn();
121         }
122 
123         response.sendRedirect(redirect);
124 
125         return null;
126     }
127 
128     protected User addUser(
129             long companyId, String firstName, String lastName,
130             String emailAddress, String openId, Locale locale)
131         throws Exception {
132 
133         long creatorUserId = 0;
134         boolean autoPassword = false;
135         String password1 = PwdGenerator.getPassword();
136         String password2 = password1;
137         boolean autoScreenName = true;
138         String screenName = StringPool.BLANK;
139         String middleName = StringPool.BLANK;
140         int prefixId = 0;
141         int suffixId = 0;
142         boolean male = true;
143         int birthdayMonth = Calendar.JANUARY;
144         int birthdayDay = 1;
145         int birthdayYear = 1970;
146         String jobTitle = StringPool.BLANK;
147         long[] organizationIds = new long[0];
148         boolean sendEmail = false;
149 
150         User user = UserLocalServiceUtil.addUser(
151             creatorUserId, companyId, autoPassword, password1, password2,
152             autoScreenName, screenName, emailAddress, locale, firstName,
153             middleName, lastName, prefixId, suffixId, male, birthdayMonth,
154             birthdayDay, birthdayYear, jobTitle, organizationIds, sendEmail);
155 
156         UserLocalServiceUtil.updateOpenId(user.getUserId(), openId);
157 
158         return user;
159     }
160 
161     protected String getFirstValue(List<String> values) {
162         if ((values == null) || (values.size() < 1)) {
163             return null;
164         }
165 
166         return values.get(0);
167     }
168 
169     protected String readResponse(
170             ThemeDisplay themeDisplay, HttpServletRequest request)
171         throws Exception {
172 
173         HttpSession session = request.getSession();
174 
175         ConsumerManager manager = OpenIdUtil.getConsumerManager();
176 
177         ParameterList params = new ParameterList(request.getParameterMap());
178 
179         DiscoveryInformation discovered =
180             (DiscoveryInformation)session.getAttribute(WebKeys.OPEN_ID_DISCO);
181 
182         if (discovered == null) {
183             return null;
184         }
185 
186         StringBuffer receivingURL = request.getRequestURL();
187         String queryString = request.getQueryString();
188 
189         if ((queryString != null) && (queryString.length() > 0)) {
190             receivingURL.append(StringPool.QUESTION);
191             receivingURL.append(request.getQueryString());
192         }
193 
194         VerificationResult verification = manager.verify(
195             receivingURL.toString(), params, discovered);
196 
197         Identifier verified = verification.getVerifiedId();
198 
199         if (verified == null) {
200             return null;
201         }
202 
203         AuthSuccess authSuccess = (AuthSuccess)verification.getAuthResponse();
204 
205         String firstName = null;
206         String lastName = null;
207         String emailAddress = null;
208 
209         if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) {
210             MessageExtension ext = authSuccess.getExtension(
211                 SRegMessage.OPENID_NS_SREG);
212 
213             if (ext instanceof SRegResponse) {
214                 SRegResponse sregResp = (SRegResponse)ext;
215 
216                 String fullName = GetterUtil.getString(
217                     sregResp.getAttributeValue("fullname"));
218 
219                 int pos = fullName.indexOf(StringPool.SPACE);
220 
221                 if ((pos != -1) && ((pos + 1) < fullName.length())) {
222                     firstName = fullName.substring(0, pos);
223                     lastName = fullName.substring(pos + 1);
224                 }
225 
226                 emailAddress = sregResp.getAttributeValue("email");
227             }
228         }
229 
230         if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
231             MessageExtension ext = authSuccess.getExtension(
232                 AxMessage.OPENID_NS_AX);
233 
234             if (ext instanceof FetchResponse) {
235                 FetchResponse fetchResp = (FetchResponse)ext;
236 
237                 if (Validator.isNull(firstName)) {
238                     firstName = getFirstValue(
239                         fetchResp.getAttributeValues("firstName"));
240                 }
241 
242                 if (Validator.isNull(lastName)) {
243                     lastName = getFirstValue(
244                         fetchResp.getAttributeValues("lastName"));
245                 }
246 
247                 if (Validator.isNull(emailAddress)) {
248                     emailAddress = getFirstValue(
249                         fetchResp.getAttributeValues("email"));
250                 }
251             }
252         }
253 
254         String openId = OpenIdUtil.normalize(authSuccess.getIdentity());
255 
256         User user = null;
257 
258         try {
259             user = UserLocalServiceUtil.getUserByOpenId(openId);
260         }
261         catch (NoSuchUserException nsue) {
262             if (Validator.isNull(firstName) || Validator.isNull(lastName) ||
263                 Validator.isNull(emailAddress)) {
264 
265                 SessionMessages.add(request, "missingOpenIdUserInformation");
266 
267                 if (_log.isInfoEnabled()) {
268                     _log.info(
269                         "The OpenID provider did not send the required " +
270                             "attributes to create an account");
271                 }
272 
273                 PortletURL createAccountURL =
274                     themeDisplay.getURLCreateAccount();
275 
276                 createAccountURL.setParameter("openId", openId);
277 
278                 session.setAttribute(
279                     WebKeys.OPEN_ID_LOGIN_PENDING, Boolean.TRUE);
280 
281                 return createAccountURL.toString();
282             }
283 
284             user = addUser(
285                 themeDisplay.getCompanyId(), firstName, lastName, emailAddress,
286                 openId, themeDisplay.getLocale());
287         }
288 
289         session.setAttribute(WebKeys.OPEN_ID_LOGIN, new Long(user.getUserId()));
290 
291         return null;
292     }
293 
294     private static Log _log = LogFactory.getLog(OpenIdResponseAction.class);
295 
296 }