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