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