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