/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.sso.google.internal;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.oauth2.Oauth2;
import com.google.api.services.oauth2.model.Userinfoplus;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.model.Contact;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.model.UserGroupRole;
import com.liferay.portal.kernel.module.configuration.ConfigurationException;
import com.liferay.portal.kernel.module.configuration.ConfigurationProvider;
import com.liferay.portal.kernel.security.auth.PrincipalException;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.settings.CompanyServiceSettingsLocator;
import com.liferay.portal.kernel.util.CalendarFactoryUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.ServiceBeanMethodInvocationFactoryUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.security.sso.google.GoogleAuthorization;
import com.liferay.portal.security.sso.google.configuration.GoogleAuthorizationConfiguration;
import com.liferay.portal.security.sso.google.constants.GoogleConstants;
import com.liferay.portal.security.sso.google.constants.GoogleWebKeys;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import javax.servlet.http.HttpSession;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* Serves as the core implementation of the Google protocol.
*
* @author Stian Sigvartsen
*/
@Component(
configurationPid = "com.liferay.portal.security.sso.google.configuration.GoogleAuthorizationConfiguration",
immediate = true, service = GoogleAuthorization.class
)
public class GoogleAuthorizationImpl implements GoogleAuthorization {
public GoogleAuthorizationImpl() {
try {
Class<?> clazz = getClass();
_doAddOrUpdateUser = clazz.getDeclaredMethod(
"doAddOrUpdateUser", HttpSession.class, long.class,
Userinfoplus.class);
}
catch (Exception e) {
throw new SystemException(e);
}
}
@Override
public User addOrUpdateUser(
HttpSession session, long companyId, String authorizationCode,
String returnRequestUri, List<String> scopes)
throws Exception {
GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow =
getGoogleAuthorizationCodeFlow(companyId, scopes);
GoogleAuthorizationCodeTokenRequest
googleAuthorizationCodeTokenRequest =
googleAuthorizationCodeFlow.newTokenRequest(authorizationCode);
googleAuthorizationCodeTokenRequest.setRedirectUri(returnRequestUri);
GoogleTokenResponse googleTokenResponse =
googleAuthorizationCodeTokenRequest.execute();
Credential credential =
googleAuthorizationCodeFlow.createAndStoreCredential(
googleTokenResponse, null);
Userinfoplus userinfoplus = getUserinfoplus(credential);
if (userinfoplus == null) {
return null;
}
ServiceBeanMethodInvocationFactoryUtil.proceed(
this, GoogleAuthorizationImpl.class, _doAddOrUpdateUser,
new Object[] {session, companyId, userinfoplus},
new String[] {"transactionAdvice"});
return doAddOrUpdateUser(session, companyId, userinfoplus);
}
@Override
public String getLoginRedirect(
long companyId, String returnRequestUri, List<String> scopes)
throws Exception {
GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow =
getGoogleAuthorizationCodeFlow(companyId, scopes);
GoogleAuthorizationCodeRequestUrl googleAuthorizationCodeRequestUrl =
googleAuthorizationCodeFlow.newAuthorizationUrl();
googleAuthorizationCodeRequestUrl =
googleAuthorizationCodeRequestUrl.setRedirectUri(returnRequestUri);
return googleAuthorizationCodeRequestUrl.build();
}
@Override
public boolean isEnabled(long companyId) {
GoogleAuthorizationConfiguration googleConfiguration =
getGoogleConfiguration(companyId);
if (Validator.isNull(googleConfiguration.clientId()) ||
Validator.isNull(googleConfiguration.clientSecret())) {
return false;
}
return googleConfiguration.enabled();
}
protected User addUser(long companyId, Userinfoplus userinfoplus)
throws Exception {
long creatorUserId = 0;
boolean autoPassword = true;
String password1 = StringPool.BLANK;
String password2 = StringPool.BLANK;
boolean autoScreenName = true;
String screenName = StringPool.BLANK;
String emailAddress = userinfoplus.getEmail();
String googleUserId = userinfoplus.getId();
String openId = StringPool.BLANK;
Locale locale = LocaleUtil.getDefault();
String firstName = userinfoplus.getGivenName();
String middleName = StringPool.BLANK;
String lastName = userinfoplus.getFamilyName();
long prefixId = 0;
long suffixId = 0;
boolean male = Objects.equals(userinfoplus.getGender(), "male");
int birthdayMonth = Calendar.JANUARY;
int birthdayDay = 1;
int birthdayYear = 1970;
String jobTitle = StringPool.BLANK;
long[] groupIds = null;
long[] organizationIds = null;
long[] roleIds = null;
long[] userGroupIds = null;
boolean sendEmail = true;
ServiceContext serviceContext = new ServiceContext();
User user = _userLocalService.addUser(
creatorUserId, companyId, autoPassword, password1, password2,
autoScreenName, screenName, emailAddress, 0, openId, locale,
firstName, middleName, lastName, prefixId, suffixId, male,
birthdayMonth, birthdayDay, birthdayYear, jobTitle, groupIds,
organizationIds, roleIds, userGroupIds, sendEmail, serviceContext);
user = _userLocalService.updateGoogleUserId(
user.getUserId(), googleUserId);
user = _userLocalService.updateLastLogin(
user.getUserId(), user.getLoginIP());
user = _userLocalService.updatePasswordReset(user.getUserId(), false);
user = _userLocalService.updateEmailAddressVerified(
user.getUserId(), true);
return user;
}
protected User doAddOrUpdateUser(
HttpSession session, long companyId, Userinfoplus userinfoplus)
throws Exception {
User user = null;
String googleUserId = userinfoplus.getId();
if (Validator.isNotNull(googleUserId)) {
user = _userLocalService.fetchUserByGoogleUserId(
companyId, googleUserId);
if ((user != null) &&
(user.getStatus() != WorkflowConstants.STATUS_INCOMPLETE)) {
session.setAttribute(
GoogleWebKeys.GOOGLE_USER_ID, String.valueOf(googleUserId));
}
}
String emailAddress = userinfoplus.getEmail();
if ((user == null) && Validator.isNotNull(emailAddress)) {
user = _userLocalService.fetchUserByEmailAddress(
companyId, emailAddress);
if ((user != null) &&
(user.getStatus() != WorkflowConstants.STATUS_INCOMPLETE)) {
session.setAttribute(
GoogleWebKeys.GOOGLE_USER_EMAIL_ADDRESS, emailAddress);
}
}
if (user != null) {
if (user.getStatus() == WorkflowConstants.STATUS_INCOMPLETE) {
session.setAttribute(
WebKeys.GOOGLE_INCOMPLETE_USER_ID, userinfoplus.getId());
user.setEmailAddress(userinfoplus.getEmail());
user.setFirstName(userinfoplus.getGivenName());
user.setLastName(userinfoplus.getFamilyName());
return user;
}
user = updateUser(user, userinfoplus);
}
else {
user = addUser(companyId, userinfoplus);
session.setAttribute(
GoogleWebKeys.GOOGLE_USER_EMAIL_ADDRESS, emailAddress);
}
return user;
}
protected GoogleAuthorizationCodeFlow getGoogleAuthorizationCodeFlow(
long companyId, List<String> scopes)
throws Exception {
GoogleAuthorizationConfiguration googleAuthorizationConfiguration =
getGoogleConfiguration(companyId);
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleAuthorizationCodeFlow.Builder googleAuthorizationCodeFlowBuilder =
new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory,
googleAuthorizationConfiguration.clientId(),
googleAuthorizationConfiguration.clientSecret(), scopes);
googleAuthorizationCodeFlowBuilder =
googleAuthorizationCodeFlowBuilder.setAccessType(
_ONLINE_ACCESS_TYPE);
return googleAuthorizationCodeFlowBuilder.build();
}
protected GoogleAuthorizationConfiguration getGoogleConfiguration(
long companyId) {
try {
return _configurationProvider.getConfiguration(
GoogleAuthorizationConfiguration.class,
new CompanyServiceSettingsLocator(
companyId, GoogleConstants.SERVICE_NAME));
}
catch (ConfigurationException ce) {
throw new SystemException(ce);
}
}
protected Userinfoplus getUserinfoplus(Credential credentials)
throws Exception {
Oauth2.Builder builder = new Oauth2.Builder(
new NetHttpTransport(), new JacksonFactory(), credentials);
Oauth2 oauth2 = builder.build();
Oauth2.Userinfo oAuth2Userinfo = oauth2.userinfo();
Oauth2.Userinfo.Get oAuth2UserinfoGet = oAuth2Userinfo.get();
Userinfoplus userinfoplus = oAuth2UserinfoGet.execute();
if ((userinfoplus == null) || (userinfoplus.getId() == null)) {
throw new PrincipalException();
}
return userinfoplus;
}
protected User updateUser(User user, Userinfoplus userinfoplus)
throws Exception {
String emailAddress = userinfoplus.getEmail();
String googleUserId = userinfoplus.getId();
String firstName = userinfoplus.getGivenName();
String lastName = userinfoplus.getFamilyName();
boolean male = Objects.equals(userinfoplus.getGender(), "male");
if (emailAddress.equals(user.getEmailAddress()) &&
firstName.equals(user.getFirstName()) &&
lastName.equals(user.getLastName()) && (male == user.isMale())) {
return user;
}
Contact contact = user.getContact();
Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
birthdayCal.setTime(contact.getBirthday());
int birthdayMonth = birthdayCal.get(Calendar.MONTH);
int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
int birthdayYear = birthdayCal.get(Calendar.YEAR);
long[] groupIds = null;
long[] organizationIds = null;
long[] roleIds = null;
List<UserGroupRole> userGroupRoles = null;
long[] userGroupIds = null;
ServiceContext serviceContext = new ServiceContext();
if (!StringUtil.equalsIgnoreCase(
googleUserId, user.getGoogleUserId())) {
_userLocalService.updateGoogleUserId(
user.getUserId(), googleUserId);
}
if (!StringUtil.equalsIgnoreCase(
emailAddress, user.getEmailAddress())) {
_userLocalService.updateEmailAddress(
user.getUserId(), StringPool.BLANK, emailAddress, emailAddress);
}
_userLocalService.updateEmailAddressVerified(user.getUserId(), true);
return _userLocalService.updateUser(
user.getUserId(), StringPool.BLANK, StringPool.BLANK,
StringPool.BLANK, false, user.getReminderQueryQuestion(),
user.getReminderQueryAnswer(), user.getScreenName(), emailAddress,
0, user.getOpenId(), true, null, user.getLanguageId(),
user.getTimeZoneId(), user.getGreeting(), user.getComments(),
firstName, user.getMiddleName(), lastName, contact.getPrefixId(),
contact.getSuffixId(), male, birthdayMonth, birthdayDay,
birthdayYear, contact.getSmsSn(), contact.getFacebookSn(),
contact.getJabberSn(), contact.getSkypeSn(), contact.getTwitterSn(),
contact.getJobTitle(), groupIds, organizationIds, roleIds,
userGroupRoles, userGroupIds, serviceContext);
}
private static final String _ONLINE_ACCESS_TYPE = "online";
@Reference
private ConfigurationProvider _configurationProvider;
private final Method _doAddOrUpdateUser;
@Reference
private UserLocalService _userLocalService;
}