From ca5e8bea23fbed472a7e175fdabac204de4c6d5d Mon Sep 17 00:00:00 2001 From: "panagiota.koltsida" Date: Fri, 2 Jun 2017 13:21:50 +0000 Subject: [PATCH] git-svn-id: https://svn.research-infrastructures.eu/d4science/gcube/branches/portal/google-hook-login/1.2/Google@149300 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 32 ++++ .project | 42 +++++ .settings/.jsdtscope | 13 ++ .settings/org.eclipse.core.resources.prefs | 4 + .settings/org.eclipse.jdt.core.prefs | 8 + .settings/org.eclipse.m2e.core.prefs | 4 + .settings/org.eclipse.wst.common.component | 13 ++ ....eclipse.wst.common.project.facet.core.xml | 8 + ...rg.eclipse.wst.jsdt.ui.superType.container | 1 + .../org.eclipse.wst.jsdt.ui.superType.name | 1 + .settings/org.eclipse.wst.validation.prefs | 11 ++ distro/LICENSE | 1 + distro/README | 66 +++++++ distro/changelog.xml | 11 ++ distro/descriptor.xml | 31 ++++ distro/profile.xml | 25 +++ pom.xml | 149 +++++++++++++++ .../java/gr/cite/google/GoogleAutoLogin.java | 73 ++++++++ src/main/java/gr/cite/google/GoogleOAuth.java | 175 ++++++++++++++++++ .../java/gr/cite/google/model/GoogleJson.java | 42 +++++ .../google/util/GoogleConstantVariables.java | 32 ++++ .../util/LoginHookEssentialMethods.java | 139 ++++++++++++++ .../resources/content/Language.properties | 7 + src/main/resources/portal.properties | 26 +++ src/main/webapp/WEB-INF/liferay-hook.xml | 21 +++ .../WEB-INF/liferay-plugin-package.properties | 9 + src/main/webapp/WEB-INF/web.xml | 4 + .../html/portlet/login/css/google.css | 42 +++++ .../html/portlet/login/navigation/google.jsp | 56 ++++++ .../html/portlet/login/navigation/google.png | Bin 0 -> 661 bytes .../portal_settings/authentication/google.jsp | 25 +++ 31 files changed, 1071 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 .settings/.jsdtscope create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 .settings/org.eclipse.wst.common.component create mode 100644 .settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 .settings/org.eclipse.wst.jsdt.ui.superType.container create mode 100644 .settings/org.eclipse.wst.jsdt.ui.superType.name create mode 100644 .settings/org.eclipse.wst.validation.prefs create mode 100644 distro/LICENSE create mode 100644 distro/README create mode 100644 distro/changelog.xml create mode 100644 distro/descriptor.xml create mode 100644 distro/profile.xml create mode 100644 pom.xml create mode 100644 src/main/java/gr/cite/google/GoogleAutoLogin.java create mode 100644 src/main/java/gr/cite/google/GoogleOAuth.java create mode 100644 src/main/java/gr/cite/google/model/GoogleJson.java create mode 100644 src/main/java/gr/cite/google/util/GoogleConstantVariables.java create mode 100644 src/main/java/gr/cite/google/util/LoginHookEssentialMethods.java create mode 100644 src/main/resources/content/Language.properties create mode 100644 src/main/resources/portal.properties create mode 100644 src/main/webapp/WEB-INF/liferay-hook.xml create mode 100644 src/main/webapp/WEB-INF/liferay-plugin-package.properties create mode 100644 src/main/webapp/WEB-INF/web.xml create mode 100644 src/main/webapp/custom_jsps/html/portlet/login/css/google.css create mode 100644 src/main/webapp/custom_jsps/html/portlet/login/navigation/google.jsp create mode 100644 src/main/webapp/custom_jsps/html/portlet/login/navigation/google.png create mode 100644 src/main/webapp/custom_jsps/html/portlet/portal_settings/authentication/google.jsp diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..91f2707 --- /dev/null +++ b/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..5227a42 --- /dev/null +++ b/.project @@ -0,0 +1,42 @@ + + + Google + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope new file mode 100644 index 0000000..585c967 --- /dev/null +++ b/.settings/.jsdtscope @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..cf6931b --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..c788ee3 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..14b697b --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..398d029 --- /dev/null +++ b/.settings/org.eclipse.wst.common.component @@ -0,0 +1,13 @@ + + + + + + + + uses + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..139c249 --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs new file mode 100644 index 0000000..1ae1e37 --- /dev/null +++ b/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,11 @@ +DELEGATES_PREFERENCE=delegateValidatorList +USER_BUILD_PREFERENCE=enabledBuildValidatorList +USER_MANUAL_PREFERENCE=enabledManualValidatorList +USER_PREFERENCE=overrideGlobalPreferencestruedisableAllValidationfalseversion1.2.700.v201508251749 +disabled=06target +eclipse.preferences.version=1 +override=true +suspend=false +vals/org.eclipse.jst.jsp.core.JSPBatchValidator/groups=0107include01113projectNature131org.eclipse.jdt.core.javanature0107include110111contentType134org.eclipse.jst.jsp.core.jspsourceT111contentType142org.eclipse.jst.jsp.core.jspfragmentsourceT111contentType134org.eclipse.jst.jsp.core.tagsourceT07fileext03jspF07fileext04jspfF07fileext03jsfF07fileext03tagF07fileext04tagfF07fileext03jsvF07fileext04jtplF0107exclude0104file127src/main/webapp/custom_jspsT02 +vals/org.eclipse.jst.jsp.core.JSPContentValidator/groups=0107include09111contentType134org.eclipse.jst.jsp.core.jspsourceT111contentType142org.eclipse.jst.jsp.core.jspfragmentsourceT07fileext03jspF07fileext04jspfF07fileext03jsfF07fileext03tagF07fileext04tagfF07fileext03jsvF07fileext04jtplF0107exclude0104file127src/main/webapp/custom_jspsF02 +vf.version=3 diff --git a/distro/LICENSE b/distro/LICENSE new file mode 100644 index 0000000..2d9616a --- /dev/null +++ b/distro/LICENSE @@ -0,0 +1 @@ +${gcube.license} \ No newline at end of file diff --git a/distro/README b/distro/README new file mode 100644 index 0000000..9ee6673 --- /dev/null +++ b/distro/README @@ -0,0 +1,66 @@ +The gCube System - ${name} +-------------------------------------------------- + +${description} + + +${gcube.description} + +${gcube.funding} + + +Version +-------------------------------------------------- + +${version} (${buildDate}) + +Please see the file named "changelog.xml" in this directory for the release notes. + + +Authors +-------------------------------------------------- + + +* Michalis Nikolopoulos (mnikolopoulos@cite.gr), CITE S.A. + + +Maintainers +----------- + +* Michalis Nikolopoulos (mnikolopoulos@cite.gr), CITE S.A. + + +Download information +-------------------------------------------------- + +Source code is available from SVN: + ${scm.url} + +Binaries can be downloaded from the gCube website: + ${gcube.website} + + +Installation +-------------------------------------------------- + +Use the respective war + + +Documentation +-------------------------------------------------- + +Documentation is available on-line in the gCube Wiki: + ${gcube.wikiRoot} + + +Support +-------------------------------------------------- + +Bugs and support requests can be reported in the gCube issue tracking tool: + ${gcube.issueTracking} + + +Licensing +-------------------------------------------------- + +This software is licensed under the terms you may find in the file named "LICENSE" in this directory. \ No newline at end of file diff --git a/distro/changelog.xml b/distro/changelog.xml new file mode 100644 index 0000000..0e9dea6 --- /dev/null +++ b/distro/changelog.xml @@ -0,0 +1,11 @@ + + + First release of the google authentication hook + + + Updated to work with the multiple email addresses authentication mechanism + + + Fixed a bug concerning users with no google+ available where the authenticated response did not include given and family names + + diff --git a/distro/descriptor.xml b/distro/descriptor.xml new file mode 100644 index 0000000..11561cb --- /dev/null +++ b/distro/descriptor.xml @@ -0,0 +1,31 @@ + + servicearchive + + tar.gz + + / + + + ${distroDirectory} + / + true + + README + LICENSE + changelog.xml + profile.xml + + 755 + true + + + + + target/${build.finalName}.war + /${artifactId} + + + \ No newline at end of file diff --git a/distro/profile.xml b/distro/profile.xml new file mode 100644 index 0000000..8f72674 --- /dev/null +++ b/distro/profile.xml @@ -0,0 +1,25 @@ + + + + Service + + ${description} + Portal + ${artifactId} + 1.0.0 + + + ${artifactId} + ${version} + + ${groupId} + ${artifactId} + ${version} + + + ${build.finalName}.war + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7e07cd0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,149 @@ + + + + 4.0.0 + + + maven-parent + org.gcube.tools + 1.0.0 + + + + + gr.cite.google + Google-login-hook + war + Google Login Hook + + The Google hook allows users to login with their Google credentials to a liferay portal + + 1.2.0-SNAPSHOT + + + scm:svn:http://svn.cite.gr/code-bluebridge/google-hook + scm:http://svn.cite.gr/code-bluebridge/google-hook + http://svn.cite.gr/code-bluebridge/google-hook + + + + 6.2.2 + ${system.CATALINA_HOME}/../deploy + ${project.basedir}/distro + + + + + + + maven-compiler-plugin + 2.5 + + UTF-8 + 1.7 + 1.7 + + + + maven-resources-plugin + 2.5 + + UTF-8 + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.2 + + + ${distroDirectory}/descriptor.xml + + + + + servicearchive + install + + single + + + + + + + + + + org.gcube.distribution + maven-portal-bom + LATEST + pom + import + + + + + + com.liferay.portal + portal-service + provided + + + com.liferay.portal + util-java + provided + + + javax.portlet + portlet-api + provided + + + javax.servlet + servlet-api + 2.4 + provided + + + javax.servlet.jsp + jsp-api + 2.0 + provided + + + + + com.github.scribejava + scribejava-apis + 3.3.0 + + + + + com.google.code.gson + gson + 2.5 + + + + org.gcube.portal + landing-page-library + [1.0.0-SNAPSHOT,) + + + + gr.cite.additionalemailaddresses + checkAdditionalEmails + [1.0.0-SNAPSHOT,2.0.0-SNAPSHOT) + + + + \ No newline at end of file diff --git a/src/main/java/gr/cite/google/GoogleAutoLogin.java b/src/main/java/gr/cite/google/GoogleAutoLogin.java new file mode 100644 index 0000000..5ca9cbb --- /dev/null +++ b/src/main/java/gr/cite/google/GoogleAutoLogin.java @@ -0,0 +1,73 @@ +package gr.cite.google; + +import gr.cite.google.util.GoogleConstantVariables; + +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.exception.SystemException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.util.GetterUtil; +import com.liferay.portal.kernel.util.PrefsPropsUtil; +import com.liferay.portal.kernel.util.Validator; +import com.liferay.portal.model.User; +import com.liferay.portal.security.auth.BaseAutoLogin; +import com.liferay.portal.service.UserLocalServiceUtil; +import com.liferay.portal.util.PortalUtil; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class GoogleAutoLogin extends BaseAutoLogin { + + private static final Log log = LogFactoryUtil.getLog(GoogleOAuth.class); + +@Override +protected String[] doLogin(HttpServletRequest request, HttpServletResponse response) throws Exception { + + long companyId = PortalUtil.getCompanyId(request); + + boolean googleAuthEnabled = PrefsPropsUtil.getBoolean(companyId, GoogleConstantVariables.GOOGLE_LOGIN_ENABLED, true); + + log.debug("Is google enabled: " + googleAuthEnabled); + if (!googleAuthEnabled) { + return null; + } + + User user = getUser(request, companyId); + + if (user == null) { + return null; + } + + String[] credentials = new String[3]; + + credentials[0] = String.valueOf(user.getUserId()); + credentials[1] = user.getPassword(); + credentials[2] = Boolean.TRUE.toString(); + + return credentials; +} + +protected User getUser(HttpServletRequest request, long companyId) throws PortalException, SystemException { + + HttpSession session = request.getSession(); + String emailAddress = GetterUtil.getString(session.getAttribute(GoogleConstantVariables.USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE)); + session.removeAttribute(GoogleConstantVariables.USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE); + + log.debug("User's mail form session: " + emailAddress); + + if (Validator.isNull(emailAddress)) { + return null; + } + + User user = UserLocalServiceUtil.getUserByEmailAddress(companyId, emailAddress); + + return user; +} + +public static Log getLog() { + return log; +} + +} \ No newline at end of file diff --git a/src/main/java/gr/cite/google/GoogleOAuth.java b/src/main/java/gr/cite/google/GoogleOAuth.java new file mode 100644 index 0000000..53b1741 --- /dev/null +++ b/src/main/java/gr/cite/google/GoogleOAuth.java @@ -0,0 +1,175 @@ +package gr.cite.google; + + +import gr.cite.additionalemailaddresses.CheckAdditionalEmailAddresses; +import gr.cite.google.model.GoogleJson; +import gr.cite.google.util.GoogleConstantVariables; +import gr.cite.google.util.LoginHookEssentialMethods; + +import java.io.IOException; + +import javax.security.auth.login.LoginException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.gcube.portal.landingpage.LandingPageManager; + +import com.github.scribejava.apis.GoogleApi20; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import com.google.gson.Gson; +import com.liferay.portal.NoSuchUserException; +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.servlet.SessionErrors; +import com.liferay.portal.kernel.struts.BaseStrutsAction; +import com.liferay.portal.kernel.util.Constants; +import com.liferay.portal.kernel.util.ParamUtil; +import com.liferay.portal.kernel.util.PrefsPropsUtil; +import com.liferay.portal.kernel.util.PropsKeys; +import com.liferay.portal.kernel.util.PropsUtil; +import com.liferay.portal.kernel.util.Validator; +import com.liferay.portal.kernel.util.WebKeys; +import com.liferay.portal.model.User; +import com.liferay.portal.service.UserLocalServiceUtil; +import com.liferay.portal.theme.ThemeDisplay; +import com.liferay.portal.util.PortalUtil; + + +public class GoogleOAuth extends BaseStrutsAction { + + private static final Log log = LogFactoryUtil.getLog(GoogleOAuth.class); + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + + HttpSession session = request.getSession(); + ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY); + + String returnFromGoogleUrl = PortalUtil.getPortalURL(request) + PropsUtil.get(GoogleConstantVariables.RETURN_FROM_GOOGLE_URL); + String googleClientId = PrefsPropsUtil.getString(themeDisplay.getCompanyId(), GoogleConstantVariables.GOOGLE_CLIENT_ID, PropsUtil.get(GoogleConstantVariables.GOOGLE_CLIENT_ID)); + String googleClientSecret = PrefsPropsUtil.getString(themeDisplay.getCompanyId(), GoogleConstantVariables.GOOGLE_CLIENT_SECRET, PropsUtil.get(GoogleConstantVariables.GOOGLE_CLIENT_SECRET)); + Boolean canCreateAccount = PrefsPropsUtil.getBoolean(themeDisplay.getCompanyId(), PropsKeys.COMPANY_SECURITY_STRANGERS); + + User user = null; + String landingPage = ""; + + //Initial call to the hook and redirection to google + if (ParamUtil.getString(request, Constants.CMD).equals("login")){ + + log.debug("Initial call for login..."); + + establishConnectionWithGoogle(session, response, returnFromGoogleUrl, googleClientId, googleClientSecret); + + //Answer from google with the data we need + } else if (ParamUtil.getString(request, Constants.CMD).equals("token")){ + + String oauthCode = ParamUtil.getString(request, GoogleConstantVariables.OAUTH_CODE); + + log.debug("User gave permision to read data..."); + log.debug("google oauthCode -> " + oauthCode); + + if (Validator.isNull(oauthCode)) { + //System.out.println("validator is null for oauthCode"); + return null; + } + + GoogleJson googleUserInfo = retrieveUsersGoogleInfo(oauthCode, returnFromGoogleUrl, googleClientId, googleClientSecret); + + + + if (googleUserInfo == null){ + throw new LoginException(); + } + log.debug("Google's object: " + googleUserInfo.toString()); + + try { + user = CheckAdditionalEmailAddresses.checkInIfAdditionalEmailAndIfVerified(googleUserInfo.getEmail()); + } catch (Exception e) { + log.error("Error occured while searching in additional emails", e); + e.printStackTrace(); + throw e; + } + + if(user != null){ + + log.info("Email " + googleUserInfo.getEmail() + " has been found in additional Email Addresses"); + session.setAttribute(GoogleConstantVariables.USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE, user.getEmailAddress()); + + }else if (canCreateAccount){ + LoginHookEssentialMethods.addUser(session, themeDisplay.getCompanyId(), googleUserInfo); + user = UserLocalServiceUtil.getUserById(UserLocalServiceUtil.getUserByEmailAddress(themeDisplay.getCompanyId(), googleUserInfo.getEmail()).getUserId()); + }else{ + try{ + user = UserLocalServiceUtil.getUserByEmailAddress(themeDisplay.getCompanyId(), googleUserInfo.getEmail()); + log.debug("Login user " + user.getFullName() + " email address " + user.getEmailAddress()); + session.setAttribute(GoogleConstantVariables.USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE, user.getEmailAddress()); + }catch (PortalException e){ + SessionErrors.add(session, NoSuchUserException.class); + } + } + //ensure the user is redirected to the requested page before logging in + if (session.getAttribute("redirectUrlAfterLogin") != null && session.getAttribute("redirectUrlAfterLogin").toString().compareTo("") != 0) { + landingPage = session.getAttribute("redirectUrlAfterLogin").toString(); + session.setAttribute("redirectUrlAfterLogin", null); + } + else { + landingPage = LandingPageManager.getLandingPagePath(request, user); + } + + //landingPage = LandingPageManager.getLandingPagePath(request, user); + response.sendRedirect(landingPage); + } + return null; + } + + + /** + * + * Initial call to google, in order to retrieve authorization code. + * + * @param response + * @param returnFromLinkedInUrl + * @throws IOException + */ + private void establishConnectionWithGoogle(HttpSession session, HttpServletResponse response, String returnFromGoogleUrl, String googleClientId, String googleClientSecret) throws IOException { + + OAuth20Service service = new ServiceBuilder().apiKey(googleClientId).apiSecret(googleClientSecret).callback(returnFromGoogleUrl).scope(GoogleConstantVariables.API_CALL_SCOPE).build(GoogleApi20.instance()); + String googleAuthUrl = service.getAuthorizationUrl(); + log.debug("Google Auth URL -> " + googleAuthUrl); + response.sendRedirect(googleAuthUrl); + } + + /** + * + * Using authorization code, we get access token and make the API call we need to retrieve data + * from google. + * + * @param oauthCode + * @param returnFromGoogleUrl + * @return GoogleJson + * @throws IOException + */ + private GoogleJson retrieveUsersGoogleInfo(String oauthCode, String returnFromGoogleUrl, String googleClientId, String googleClientSecret) throws IOException { + + OAuth20Service service = new ServiceBuilder().apiKey(googleClientId).apiSecret(googleClientSecret).callback(returnFromGoogleUrl).scope(GoogleConstantVariables.API_CALL_SCOPE).build(GoogleApi20.instance()); + + //Verifier verifier = new Verifier(oauthCode); + OAuth2AccessToken accessToken = service.getAccessToken(oauthCode); + + //OAuth2AccessToken accessToken, AbstractRequest request + OAuthRequest authRequest = new OAuthRequest(Verb.GET, GoogleConstantVariables.API_CALL, service); + service.signRequest(accessToken, authRequest); + + String bodyResponse = authRequest.send().getBody(); + log.trace("Google oauth body response -> " + bodyResponse); + GoogleJson googleJson = new Gson().fromJson(bodyResponse, GoogleJson.class); + + return googleJson; + } +} diff --git a/src/main/java/gr/cite/google/model/GoogleJson.java b/src/main/java/gr/cite/google/model/GoogleJson.java new file mode 100644 index 0000000..0d3df3d --- /dev/null +++ b/src/main/java/gr/cite/google/model/GoogleJson.java @@ -0,0 +1,42 @@ +package gr.cite.google.model; + +import com.google.gson.annotations.SerializedName; + +/** + * @author mnikolopoulos + * + * This is the data we deserialize, in case we need more/different data from the google, + * we can check their API and make the appropriate changes here and maybe to the the actual call + * and to the scope as well if needed. + * + */ +public class GoogleJson { + + private String email; + @SerializedName("given_name") + private String givenName; + @SerializedName("family_name") + private String familyName; + + + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + public String getGivenName() { + return givenName; + } + public void setGivenName(String givenName) { + this.givenName = givenName; + } + public String getFamilyName() { + return familyName; + } + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + +} diff --git a/src/main/java/gr/cite/google/util/GoogleConstantVariables.java b/src/main/java/gr/cite/google/util/GoogleConstantVariables.java new file mode 100644 index 0000000..8745c7b --- /dev/null +++ b/src/main/java/gr/cite/google/util/GoogleConstantVariables.java @@ -0,0 +1,32 @@ +package gr.cite.google.util; + + +public class GoogleConstantVariables { + + public final static String REDIRECT_URL_AFTER_LOGIN = "redirectUrlAfterLogin"; + + public final static String USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE = "userEmailAdressGoogle"; + + public final static String GOOGLE_CLIENT_ID = "google.client.id"; + + public final static String GOOGLE_CLIENT_SECRET = "google.client.secret"; + + public final static String OAUTH_CODE = "code"; + + public final static String OAUTH_TOKEN = "oauth_token"; + + public final static String REQUEST_TOKEN_SECRET_GOOGLE = "requestTokenSecretGoogle"; + + public final static String API_CALL = "https://www.googleapis.com/oauth2/v2/userinfo"; + + public final static String RETURN_FROM_GOOGLE_URL = "google.hook.callback.url"; + + public final static String GOOGLE_LOGIN_ENABLED = "google.auth.enabled"; + + //public final static String API_CALL_SCOPE = "https://www.googleapis.com/auth/userinfo.email"; + public final static String API_CALL_SCOPE = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email"; + + public final static String OAUTH_SERVICE_OBJECT = "oAuthService"; +} + + diff --git a/src/main/java/gr/cite/google/util/LoginHookEssentialMethods.java b/src/main/java/gr/cite/google/util/LoginHookEssentialMethods.java new file mode 100644 index 0000000..270fcc7 --- /dev/null +++ b/src/main/java/gr/cite/google/util/LoginHookEssentialMethods.java @@ -0,0 +1,139 @@ +package gr.cite.google.util; + +import gr.cite.google.model.GoogleJson; +import gr.cite.google.util.GoogleConstantVariables; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Locale; + +import javax.portlet.PortletMode; +import javax.portlet.PortletModeException; +import javax.portlet.PortletRequest; +import javax.portlet.PortletURL; +import javax.portlet.WindowStateException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import com.liferay.portal.DuplicateUserEmailAddressException; +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.exception.SystemException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.portlet.LiferayWindowState; +import com.liferay.portal.kernel.util.LocaleUtil; +import com.liferay.portal.kernel.util.StringPool; +import com.liferay.portal.kernel.util.WebKeys; +import com.liferay.portal.model.User; +import com.liferay.portal.service.ServiceContext; +import com.liferay.portal.service.UserLocalServiceUtil; +import com.liferay.portal.theme.ThemeDisplay; +import com.liferay.portal.util.PortletKeys; +import com.liferay.portlet.PortletURLFactoryUtil; + +public class LoginHookEssentialMethods { + + private static final Log log = LogFactoryUtil.getLog(LoginHookEssentialMethods.class); + + /** + * + * Try to add new user to portal, then set user's email address in session. + * + * + * @param session + * @param companyId + * @param googleJson + * @return User + * @throws SystemException, PortalException, EmailAddressException + */ + public static User addUser(HttpSession session, long companyId, GoogleJson googleJson) throws PortalException, SystemException { + + User user = null; + + long creatorUserId = 0; + boolean autoPassword = true; + String password1 = StringPool.BLANK; + String password2 = StringPool.BLANK; + boolean autoScreenName = true; + String screenName = StringPool.BLANK; + String emailAddress = googleJson.getEmail(); + String openId = StringPool.BLANK; + Locale locale = LocaleUtil.getDefault(); + + String givenName = googleJson.getGivenName(); + String firstName = " "; + if (givenName != null) + firstName = givenName; + + String middleName = StringPool.BLANK; + + String familyName = googleJson.getFamilyName(); + String lastName = " "; + if (familyName != null) + lastName = familyName; + + int prefixId = 0; + int suffixId = 0; + boolean male = false; + 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(); + + try{ + user = UserLocalServiceUtil.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 = UserLocalServiceUtil.updateLastLogin(user.getUserId(),user.getLoginIP()); + user = UserLocalServiceUtil.updatePasswordReset(user.getUserId(), false); + user = UserLocalServiceUtil.updateEmailAddressVerified(user.getUserId(), true); + log.info("New user was created. Login new user with current credentials"); + + }catch (DuplicateUserEmailAddressException e){ + log.info("User with the same email address already exists. Login user with said mail."); + } + + session.setAttribute(GoogleConstantVariables.USER_EMAIL_ADDRESS_FOR_SESSION_GOOGLE, emailAddress); + + return user; + } + + /** + * + * Redirects User to appropriate portal page. + * + * @param response + * @param redirectUrlCustom is the portal page user would visit if user was already logged in + * @param redirectUrlDefault is the default landing page of the portal, which is a fall-back in case of empty redirectUrlCustom + * @throws IOException + * @throws SystemException + * @throws PortalException + * @throws WindowStateException + * @throws PortletModeException + */ + public static void reditectUserToHisPage(HttpServletResponse response, HttpServletRequest request, String redirectUrlCustom, String redirectUrlDefault) throws PortletModeException, WindowStateException, IOException { + + ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY); + + PortletURL portletURL = PortletURLFactoryUtil.create(request, PortletKeys.LOGIN, themeDisplay.getPlid(), PortletRequest.RENDER_PHASE); + + portletURL.setPortletMode(PortletMode.VIEW); + portletURL.setWindowState(LiferayWindowState.POP_UP); + portletURL.setParameter("redirect", redirectUrlCustom); + portletURL.setParameter("struts_action", "/login/login_redirect"); + + response.sendRedirect(portletURL.toString()); + } +} diff --git a/src/main/resources/content/Language.properties b/src/main/resources/content/Language.properties new file mode 100644 index 0000000..dd81782 --- /dev/null +++ b/src/main/resources/content/Language.properties @@ -0,0 +1,7 @@ +google=Google +google-client-id=Client Id +google-client-secret=Client Secret +google-client-id-helpMessage=Fill this field with the client id google has provided you with +google-client-secret-helpMessage=Fill this field with client secret google has provided you with +google-enable=Check, if you want to use google login, otherwise uncheck +sign-in-with-google=Sign up with Google \ No newline at end of file diff --git a/src/main/resources/portal.properties b/src/main/resources/portal.properties new file mode 100644 index 0000000..3f8236f --- /dev/null +++ b/src/main/resources/portal.properties @@ -0,0 +1,26 @@ +# Add Google as a tab for configuration +company.settings.form.authentication=google + +# Make this struts path public accessible +auth.public.paths=/portal/google_login + +# Set Google's authentication Class +auto.login.hooks=gr.cite.google.GoogleAutoLogin + +# Add Google to navigation bar at login +# if using the custom login hook then you can safely remove +# this option but you need to concatenate the value 'google' to the login.form.navigation.socials +# option in the login-hook. +# if not using the custom login hook, this option should be enabled in order to have google as a login method. +# login.form.navigation.post=google + +#google initial call to create the login connection +google.hook.call.url=/c/portal/google_login?cmd=login + +# Callback url after logging in to google +google.hook.callback.url=/c/portal/google_login?cmd=token + +# Google Authentication configuration +google.auth.enabled=true +google.client.id= +google.client.secret= \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/liferay-hook.xml b/src/main/webapp/WEB-INF/liferay-hook.xml new file mode 100644 index 0000000..64aa81a --- /dev/null +++ b/src/main/webapp/WEB-INF/liferay-hook.xml @@ -0,0 +1,21 @@ + + + + + + + portal.properties + + + content/Language.properties + + + /custom_jsps + + + + /portal/google_login + gr.cite.google.GoogleOAuth + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/liferay-plugin-package.properties b/src/main/webapp/WEB-INF/liferay-plugin-package.properties new file mode 100644 index 0000000..7c1a0d3 --- /dev/null +++ b/src/main/webapp/WEB-INF/liferay-plugin-package.properties @@ -0,0 +1,9 @@ +name=Google +module-group-id=liferay +module-incremental-version=1 +tags= +short-description= +change-log= +page-url=http://www.liferay.com +author=Liferay, Inc. +licenses=LGPL \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..7d8c082 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/webapp/custom_jsps/html/portlet/login/css/google.css b/src/main/webapp/custom_jsps/html/portlet/login/css/google.css new file mode 100644 index 0000000..b2c61a9 --- /dev/null +++ b/src/main/webapp/custom_jsps/html/portlet/login/css/google.css @@ -0,0 +1,42 @@ +.social-hook div[class*="-hook-icon"] { + display: inline-block; + padding: 0px 6px; + color: white; + margin-right: -5px; + box-shadow: 2px 0px 8px -2px rgba(0,0,0,0.7), -2px 1px 1px 1px rgba(0,0,0,0.3); + z-index: 10; + position: relative; + width: 10% +} + +.social-hook div[class$="-hook-text"] { + display: inline-block; + padding: 0px 10px; + border-radius: 0px 5px 5px 0px; + color: white; + box-shadow: 1px 1px 3px 1.5px rgba(0,0,0,0.3); + width: 50%; +} + +.social-hook a[class$="-hook-link"] { + text-align: center; +} + +.social-hook div[class$="-hook-label-wrapper"]{ + white-space: nowrap; +} + +.social-hook div[class$="-hook-label-wrapper"]:hover{ + opacity : 0.85; +} + +.social-hook .google-hook-text, .social-hook .google-hook-icon{ + background-color: rgb(209, 72, 54); +} + +@media (max-width: 480px) { + .social-hook div[class$="-hook-text"] { + min-width: 50%; + width: inherit; + } +} \ No newline at end of file diff --git a/src/main/webapp/custom_jsps/html/portlet/login/navigation/google.jsp b/src/main/webapp/custom_jsps/html/portlet/login/navigation/google.jsp new file mode 100644 index 0000000..78fd947 --- /dev/null +++ b/src/main/webapp/custom_jsps/html/portlet/login/navigation/google.jsp @@ -0,0 +1,56 @@ +<%@ include file="/html/portlet/login/init.jsp" %> + +<%@ page import="com.liferay.portal.util.PortalUtil" %> + + + + +<% + +boolean isGoogleAuthEnabled = PrefsPropsUtil.getBoolean(company.getCompanyId(), "google.auth.enabled", true); +String googleLoginUrl = PortalUtil.getPathContext().toString() + PropsUtil.get("google.hook.call.url"); +String redirect = ParamUtil.getString(request, "redirect"); +session.setAttribute("redirectUrlAfterLogin", redirect); + +String[] navSocialsArray = PropsUtil.getArray("login.form.navigation.socials"); +String[] navPostsArray = PropsUtil.getArray("login.form.navigation.post"); + +Set navSocialsSet = new HashSet(Arrays.asList(navSocialsArray)); +Set navPostsSet = new HashSet(Arrays.asList(navPostsArray)); + +Boolean inSocials = navSocialsSet.contains("google"); +Boolean inPosts = navPostsSet.contains("google"); + +%> + + + + + + \ No newline at end of file diff --git a/src/main/webapp/custom_jsps/html/portlet/login/navigation/google.png b/src/main/webapp/custom_jsps/html/portlet/login/navigation/google.png new file mode 100644 index 0000000000000000000000000000000000000000..26322347a94bfd8270f52a9a517fcf06100dd06e GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=IjczVPIfn3h)VW1uA&$X#Ud4_?5Hi3ujXx`O?|swTtOf zA7dcnzPy@v;OJ~#H zdzjz&>;K-({B5Sd&t0tlwlg@keg-leTfh9=$pU1o+oIsq{KcX5lT*u=m%DgORs=e= zd~$60vT2)={|Zl&6+w<|U!0mhxz&F#SsrAxBG`CEkk+bD-5bEf{r|u2n@eSF^V;9+O*dm)FyoBa>Z`|YIvzcEQfklS(t}4g z-F9xjew@XBvb_LL>)(kQuQ%?{QNI%V(0uatYOa5t+WkF_DWa;!<3dh4AJpgy2s$OI zwrYx0lC0GE@Zk7-#cc~Ot1emo&F)bGhk}rk+vAfZX7$Q?E2d9#dA>Pn^ZZFWE*>dc kE_=JX{qf71otyr!Mw=_!`p=!V2 + + +<%@ include file="/html/portlet/portal_settings/init.jsp" %> + +<% + +boolean isGoogleAuthEnabled = PrefsPropsUtil.getBoolean(company.getCompanyId(), "google.auth.enabled", true); +String googleClientId = PrefsPropsUtil.getString(company.getCompanyId(), "google.client.id"); +String googleClientSecret = PrefsPropsUtil.getString(company.getCompanyId(), "google.client.secret"); + +%> + + + + + + + + \ No newline at end of file