001
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.configuration.Filter;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.servlet.SessionErrors;
023 import com.liferay.portal.kernel.servlet.SessionMessages;
024 import com.liferay.portal.kernel.util.CharPool;
025 import com.liferay.portal.kernel.util.Constants;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.HttpUtil;
028 import com.liferay.portal.kernel.util.ParamUtil;
029 import com.liferay.portal.kernel.util.PropsKeys;
030 import com.liferay.portal.kernel.util.StringPool;
031 import com.liferay.portal.kernel.util.Validator;
032 import com.liferay.portal.model.User;
033 import com.liferay.portal.security.auth.PrincipalException;
034 import com.liferay.portal.service.ServiceContext;
035 import com.liferay.portal.service.UserLocalServiceUtil;
036 import com.liferay.portal.struts.PortletAction;
037 import com.liferay.portal.theme.ThemeDisplay;
038 import com.liferay.portal.util.OpenIdUtil;
039 import com.liferay.portal.util.PortalUtil;
040 import com.liferay.portal.util.PropsUtil;
041 import com.liferay.portal.util.PropsValues;
042 import com.liferay.portal.util.WebKeys;
043 import com.liferay.portlet.ActionResponseImpl;
044 import com.liferay.util.PwdGenerator;
045
046 import java.net.URL;
047
048 import java.util.Calendar;
049 import java.util.List;
050 import java.util.Locale;
051
052 import javax.portlet.ActionRequest;
053 import javax.portlet.ActionResponse;
054 import javax.portlet.PortletConfig;
055 import javax.portlet.PortletURL;
056 import javax.portlet.RenderRequest;
057 import javax.portlet.RenderResponse;
058
059 import javax.servlet.http.HttpServletRequest;
060 import javax.servlet.http.HttpServletResponse;
061 import javax.servlet.http.HttpSession;
062
063 import org.apache.struts.action.ActionForm;
064 import org.apache.struts.action.ActionForward;
065 import org.apache.struts.action.ActionMapping;
066
067 import org.openid4java.OpenIDException;
068 import org.openid4java.consumer.ConsumerManager;
069 import org.openid4java.consumer.VerificationResult;
070 import org.openid4java.discovery.DiscoveryInformation;
071 import org.openid4java.discovery.Identifier;
072 import org.openid4java.message.AuthRequest;
073 import org.openid4java.message.AuthSuccess;
074 import org.openid4java.message.MessageExtension;
075 import org.openid4java.message.ParameterList;
076 import org.openid4java.message.ax.AxMessage;
077 import org.openid4java.message.ax.FetchRequest;
078 import org.openid4java.message.ax.FetchResponse;
079 import org.openid4java.message.sreg.SRegMessage;
080 import org.openid4java.message.sreg.SRegRequest;
081 import org.openid4java.message.sreg.SRegResponse;
082
083
087 public class OpenIdAction extends PortletAction {
088
089 @Override
090 public void processAction(
091 ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
092 ActionRequest actionRequest, ActionResponse actionResponse)
093 throws Exception {
094
095 ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
096 WebKeys.THEME_DISPLAY);
097
098 if (!OpenIdUtil.isEnabled(themeDisplay.getCompanyId())) {
099 throw new PrincipalException();
100 }
101
102 if (actionRequest.getRemoteUser() != null) {
103 actionResponse.sendRedirect(themeDisplay.getPathMain());
104
105 return;
106 }
107
108 String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
109
110 try {
111 if (cmd.equals(Constants.READ)) {
112 String redirect = readOpenIdResponse(
113 themeDisplay, actionRequest, actionResponse);
114
115 if (Validator.isNull(redirect)) {
116 redirect =
117 PortalUtil.getPortalURL(actionRequest) +
118 themeDisplay.getURLSignIn();
119 }
120
121 sendRedirect(actionRequest, actionResponse, redirect);
122 }
123 else {
124 sendOpenIdRequest(themeDisplay, actionRequest, actionResponse);
125 }
126 }
127 catch (Exception e) {
128 if (e instanceof DuplicateUserEmailAddressException) {
129 SessionErrors.add(actionRequest, e.getClass());
130 }
131 else if (e instanceof OpenIDException) {
132 if (_log.isInfoEnabled()) {
133 _log.info(
134 "Error communicating with OpenID provider: " +
135 e.getMessage());
136 }
137
138 SessionErrors.add(actionRequest, e.getClass());
139 }
140 else {
141 _log.error("Error processing the OpenID login", e);
142
143 PortalUtil.sendError(e, actionRequest, actionResponse);
144 }
145 }
146 }
147
148 @Override
149 public ActionForward render(
150 ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
151 RenderRequest renderRequest, RenderResponse renderResponse)
152 throws Exception {
153
154 ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
155 WebKeys.THEME_DISPLAY);
156
157 if (!OpenIdUtil.isEnabled(themeDisplay.getCompanyId())) {
158 return mapping.findForward("portlet.login.login");
159 }
160
161 renderResponse.setTitle(themeDisplay.translate("open-id"));
162
163 return mapping.findForward("portlet.login.open_id");
164 }
165
166 protected String getFirstValue(List<String> values) {
167 if ((values == null) || (values.size() < 1)) {
168 return null;
169 }
170
171 return values.get(0);
172 }
173
174 protected String getOpenIdProvider(URL endpointURL) {
175 String hostName = endpointURL.getHost();
176
177 for (String openIdProvider : PropsValues.OPEN_ID_PROVIDERS) {
178 String openIdURLString = PropsUtil.get(
179 PropsKeys.OPEN_ID_URL, new Filter(openIdProvider));
180
181 if (hostName.equals(openIdURLString)) {
182 return openIdProvider;
183 }
184 }
185
186 return _OPEN_ID_PROVIDER_DEFAULT;
187 }
188
189 @Override
190 protected boolean isCheckMethodOnProcessAction() {
191 return _CHECK_METHOD_ON_PROCESS_ACTION;
192 }
193
194 protected String readOpenIdResponse(
195 ThemeDisplay themeDisplay, ActionRequest actionRequest,
196 ActionResponse actionResponse)
197 throws Exception {
198
199 HttpServletRequest request = PortalUtil.getHttpServletRequest(
200 actionRequest);
201 HttpSession session = request.getSession();
202
203 ConsumerManager consumerManager = OpenIdUtil.getConsumerManager();
204
205 ParameterList parameterList = new ParameterList(
206 actionRequest.getParameterMap());
207
208 DiscoveryInformation discoveryInformation =
209 (DiscoveryInformation)session.getAttribute(WebKeys.OPEN_ID_DISCO);
210
211 if (discoveryInformation == null) {
212 return null;
213 }
214
215 String receivingURL = ParamUtil.getString(
216 actionRequest, "openid.return_to");
217
218 VerificationResult verificationResult = consumerManager.verify(
219 receivingURL, parameterList, discoveryInformation);
220
221 Identifier identifier = verificationResult.getVerifiedId();
222
223 if (identifier == null) {
224 return null;
225 }
226
227 AuthSuccess authSuccess =
228 (AuthSuccess)verificationResult.getAuthResponse();
229
230 String firstName = null;
231 String lastName = null;
232 String emailAddress = null;
233
234 if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) {
235 MessageExtension messageExtension = authSuccess.getExtension(
236 SRegMessage.OPENID_NS_SREG);
237
238 if (messageExtension instanceof SRegResponse) {
239 SRegResponse sregResp = (SRegResponse)messageExtension;
240
241 String fullName = GetterUtil.getString(
242 sregResp.getAttributeValue(_OPEN_ID_SREG_ATTR_FULLNAME));
243
244 String[] names = splitFullName(fullName);
245
246 if (names != null) {
247 firstName = names[0];
248 lastName = names[1];
249 }
250
251 emailAddress = sregResp.getAttributeValue(
252 _OPEN_ID_SREG_ATTR_EMAIL);
253 }
254 }
255
256 if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
257 MessageExtension messageExtension = authSuccess.getExtension(
258 AxMessage.OPENID_NS_AX);
259
260 if (messageExtension instanceof FetchResponse) {
261 FetchResponse fetchResponse = (FetchResponse)messageExtension;
262
263 String openIdProvider = getOpenIdProvider(
264 discoveryInformation.getOPEndpoint());
265
266 String[] openIdAXTypes = PropsUtil.getArray(
267 PropsKeys.OPEN_ID_AX_SCHEMA, new Filter(openIdProvider));
268
269 for (String openIdAXType : openIdAXTypes) {
270 if (openIdAXType.equals(_OPEN_ID_AX_ATTR_EMAIL)) {
271 if (Validator.isNull(emailAddress)) {
272 emailAddress = getFirstValue(
273 fetchResponse.getAttributeValues(
274 _OPEN_ID_AX_ATTR_EMAIL));
275 }
276 }
277 else if (openIdAXType.equals(_OPEN_ID_AX_ATTR_FIRST_NAME)) {
278 if (Validator.isNull(firstName)) {
279 firstName = getFirstValue(
280 fetchResponse.getAttributeValues(
281 _OPEN_ID_AX_ATTR_FIRST_NAME));
282 }
283 }
284 else if (openIdAXType.equals(_OPEN_ID_AX_ATTR_FULL_NAME)) {
285 String fullName = fetchResponse.getAttributeValue(
286 _OPEN_ID_AX_ATTR_FULL_NAME);
287
288 String[] names = splitFullName(fullName);
289
290 if (names != null) {
291 if (Validator.isNull(firstName)) {
292 firstName = names[0];
293 }
294
295 if (Validator.isNull(lastName)) {
296 lastName = names[1];
297 }
298 }
299 }
300 else if (openIdAXType.equals(_OPEN_ID_AX_ATTR_LAST_NAME)) {
301 if (Validator.isNull(lastName)) {
302 lastName = getFirstValue(
303 fetchResponse.getAttributeValues(
304 _OPEN_ID_AX_ATTR_LAST_NAME));
305 }
306 }
307 }
308 }
309 }
310
311 String openId = OpenIdUtil.normalize(authSuccess.getIdentity());
312
313 User user = null;
314
315 try {
316 user = UserLocalServiceUtil.getUserByOpenId(
317 themeDisplay.getCompanyId(), openId);
318 }
319 catch (NoSuchUserException nsue) {
320 if (Validator.isNull(firstName) || Validator.isNull(lastName) ||
321 Validator.isNull(emailAddress)) {
322
323 SessionMessages.add(request, "missingOpenIdUserInformation");
324
325 if (_log.isInfoEnabled()) {
326 _log.info(
327 "The OpenID provider did not send the required " +
328 "attributes to create an account");
329 }
330
331 String createAccountURL = PortalUtil.getCreateAccountURL(
332 request, themeDisplay);
333
334 createAccountURL = HttpUtil.setParameter(
335 createAccountURL, "openId", openId);
336
337 session.setAttribute(
338 WebKeys.OPEN_ID_LOGIN_PENDING, Boolean.TRUE);
339
340 return createAccountURL;
341 }
342
343 long creatorUserId = 0;
344 long companyId = themeDisplay.getCompanyId();
345 boolean autoPassword = false;
346 String password1 = PwdGenerator.getPassword();
347 String password2 = password1;
348 boolean autoScreenName = true;
349 String screenName = StringPool.BLANK;
350 long facebookId = 0;
351 Locale locale = themeDisplay.getLocale();
352 String middleName = StringPool.BLANK;
353 int prefixId = 0;
354 int suffixId = 0;
355 boolean male = true;
356 int birthdayMonth = Calendar.JANUARY;
357 int birthdayDay = 1;
358 int birthdayYear = 1970;
359 String jobTitle = StringPool.BLANK;
360 long[] groupIds = null;
361 long[] organizationIds = null;
362 long[] roleIds = null;
363 long[] userGroupIds = null;
364 boolean sendEmail = false;
365
366 ServiceContext serviceContext = new ServiceContext();
367
368 user = UserLocalServiceUtil.addUser(
369 creatorUserId, companyId, autoPassword, password1, password2,
370 autoScreenName, screenName, emailAddress, facebookId, openId,
371 locale, firstName, middleName, lastName, prefixId, suffixId,
372 male, birthdayMonth, birthdayDay, birthdayYear, jobTitle,
373 groupIds, organizationIds, roleIds, userGroupIds, sendEmail,
374 serviceContext);
375 }
376
377 session.setAttribute(WebKeys.OPEN_ID_LOGIN, new Long(user.getUserId()));
378
379 return null;
380 }
381
382 protected void sendOpenIdRequest(
383 ThemeDisplay themeDisplay, ActionRequest actionRequest,
384 ActionResponse actionResponse)
385 throws Exception {
386
387 HttpServletRequest request = PortalUtil.getHttpServletRequest(
388 actionRequest);
389 HttpServletResponse response = PortalUtil.getHttpServletResponse(
390 actionResponse);
391 HttpSession session = request.getSession();
392
393 ActionResponseImpl actionResponseImpl =
394 (ActionResponseImpl)actionResponse;
395
396 String openId = ParamUtil.getString(actionRequest, "openId");
397
398 PortletURL portletURL = actionResponseImpl.createActionURL();
399
400 portletURL.setParameter("saveLastPath", Boolean.FALSE.toString());
401 portletURL.setParameter(Constants.CMD, Constants.READ);
402 portletURL.setParameter("struts_action", "/login/open_id");
403
404 ConsumerManager manager = OpenIdUtil.getConsumerManager();
405
406 List<DiscoveryInformation> discoveries = manager.discover(openId);
407
408 DiscoveryInformation discovered = manager.associate(discoveries);
409
410 session.setAttribute(WebKeys.OPEN_ID_DISCO, discovered);
411
412 AuthRequest authRequest = manager.authenticate(
413 discovered, portletURL.toString(), themeDisplay.getPortalURL());
414
415 try {
416 UserLocalServiceUtil.getUserByOpenId(
417 themeDisplay.getCompanyId(), openId);
418 }
419 catch (NoSuchUserException nsue) {
420 String screenName = OpenIdUtil.getScreenName(openId);
421
422 try {
423 User user = UserLocalServiceUtil.getUserByScreenName(
424 themeDisplay.getCompanyId(), screenName);
425
426 UserLocalServiceUtil.updateOpenId(user.getUserId(), openId);
427 }
428 catch (NoSuchUserException nsue2) {
429 FetchRequest fetchRequest = FetchRequest.createFetchRequest();
430
431 String openIdProvider = getOpenIdProvider(
432 discovered.getOPEndpoint());
433
434 String[] openIdAXTypes = PropsUtil.getArray(
435 PropsKeys.OPEN_ID_AX_SCHEMA, new Filter(openIdProvider));
436
437 for (String openIdAXType : openIdAXTypes) {
438 fetchRequest.addAttribute(
439 openIdAXType,
440 PropsUtil.get(
441 _OPEN_ID_AX_TYPE.concat(openIdAXType),
442 new Filter(openIdProvider)), true);
443 }
444
445 authRequest.addExtension(fetchRequest);
446
447 SRegRequest sRegRequest = SRegRequest.createFetchRequest();
448
449 sRegRequest.addAttribute(_OPEN_ID_SREG_ATTR_EMAIL, true);
450 sRegRequest.addAttribute(_OPEN_ID_SREG_ATTR_FULLNAME, true);
451
452 authRequest.addExtension(sRegRequest);
453 }
454 }
455
456 response.sendRedirect(authRequest.getDestinationUrl(true));
457 }
458
459 protected String[] splitFullName(String fullName) {
460 if (Validator.isNull(fullName)) {
461 return null;
462 }
463
464 int pos = fullName.indexOf(CharPool.SPACE);
465
466 if ((pos != -1) && ((pos + 1) < fullName.length())) {
467 String[] names = new String[2];
468
469 names[0] = fullName.substring(0, pos);
470 names[1] = fullName.substring(pos + 1);
471
472 return names;
473 }
474
475 return null;
476 }
477
478 private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
479
480 private static final String _OPEN_ID_AX_ATTR_EMAIL = "email";
481
482 private static final String _OPEN_ID_AX_ATTR_FIRST_NAME = "firstname";
483
484 private static final String _OPEN_ID_AX_ATTR_FULL_NAME = "fullname";
485
486 private static final String _OPEN_ID_AX_ATTR_LAST_NAME = "lastname";
487
488 private static final String _OPEN_ID_AX_TYPE = "open.id.ax.type.";
489
490 private static final String _OPEN_ID_PROVIDER_DEFAULT = "default";
491
492 private static final String _OPEN_ID_SREG_ATTR_EMAIL = "email";
493
494 private static final String _OPEN_ID_SREG_ATTR_FULLNAME = "fullname";
495
496 private static Log _log = LogFactoryUtil.getLog(OpenIdAction.class);
497
498 }