Commit 34317a70 authored by igoshin's avatar igoshin Committed by Matija Obreza
Browse files

Finish google account integration (+2 squashed commits)

Squashed commits:
[0dcbc98] First version of user story "Login with google"
[66df377] First version of user story "Login with google"
parent 0940539f
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
<spring.security.oauth2.version>1.0.5.RELEASE</spring.security.oauth2.version> <spring.security.oauth2.version>1.0.5.RELEASE</spring.security.oauth2.version>
<spring.data.core.version>1.5.1.RELEASE</spring.data.core.version> <spring.data.core.version>1.5.1.RELEASE</spring.data.core.version>
<spring.data.jpa.version>1.3.5.RELEASE</spring.data.jpa.version> <spring.data.jpa.version>1.3.5.RELEASE</spring.data.jpa.version>
<org.springframework.social-version>1.0.3.RELEASE</org.springframework.social-version>
<org.springframework.social-google-version>1.0.0.M3</org.springframework.social-google-version>
<mysql.version>5.1.25</mysql.version> <mysql.version>5.1.25</mysql.version>
...@@ -67,7 +69,22 @@ ...@@ -67,7 +69,22 @@
<name>ibiblio.mirrors</name> <name>ibiblio.mirrors</name>
<url>http://mirrors.ibiblio.org/pub/mirrors/maven2</url> <url>http://mirrors.ibiblio.org/pub/mirrors/maven2</url>
</repository> </repository>
<!-- <repository> <repository>
<id>spring-social-google</id>
<name>Spring Social Google</name>
<url>http://gabiaxel.github.io/maven/</url>
</repository>
<repository>
<id>sonatype-oss</id>
<url>https://oss.sonatype.org/content/groups/public</url>
</repository>
<repository>
<id>releases</id>
<name>Releases</name>
<url>https://oss.sonatype.org/content/repositories/releases</url>
</repository>
<!-- <repository>
<id>sonatype mirror</id> <id>sonatype mirror</id>
<url>http://search.maven.org/remotecontent?filepath=</url> <url>http://search.maven.org/remotecontent?filepath=</url>
</repository> --> </repository> -->
...@@ -242,6 +259,60 @@ ...@@ -242,6 +259,60 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-google</artifactId>
<version>${org.springframework.social-google-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>${org.springframework.social-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<version>${org.springframework.social-version}</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-servlet</artifactId>
<version>1.17.0-rc</version>
</dependency>
<dependency>
<groupId>com.googlecode.googleplus</groupId>
<artifactId>google-plus-java-api</artifactId>
<exclusions>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</exclusion>
</exclusions>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.api.client</groupId>
<artifactId>google-api-client</artifactId>
<exclusions>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</exclusion>
</exclusions>
<version>1.3.1-alpha</version>
</dependency>
<!-- Hibernate dependencies --> <!-- Hibernate dependencies -->
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
...@@ -286,11 +357,11 @@ ...@@ -286,11 +357,11 @@
<version>${oval.version}</version> <version>${oval.version}</version>
</dependency> </dependency>
<dependency> <!--<dependency>-->
<groupId>com.fasterxml.jackson.core</groupId> <!--<groupId>com.fasterxml.jackson.core</groupId>-->
<artifactId>jackson-databind</artifactId> <!--<artifactId>jackson-databind</artifactId>-->
<version>${jackson.version}</version> <!--<version>${jackson.version}</version>-->
</dependency> <!--</dependency>-->
<!--Jetty --> <!--Jetty -->
...@@ -357,6 +428,16 @@ ...@@ -357,6 +428,16 @@
<artifactId>mail</artifactId> <artifactId>mail</artifactId>
<version>1.5.0-b01</version> <version>1.5.0-b01</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.fernandospr</groupId>
<artifactId>javapns-jdk16</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.17.0-rc</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -22,6 +22,7 @@ import org.genesys2.server.model.wrapper.UserWrapper; ...@@ -22,6 +22,7 @@ import org.genesys2.server.model.wrapper.UserWrapper;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.social.google.api.userinfo.GoogleUserInfo;
public interface UserService { public interface UserService {
...@@ -71,4 +72,6 @@ public interface UserService { ...@@ -71,4 +72,6 @@ public interface UserService {
void setAccountLockLocal(String uuid, boolean locked); void setAccountLockLocal(String uuid, boolean locked);
void userEmailValidated(String uuid) throws UserException; void userEmailValidated(String uuid) throws UserException;
void googleAuthentication(GoogleUserInfo userInfo) throws UserException;
} }
...@@ -16,12 +16,6 @@ ...@@ -16,12 +16,6 @@
package org.genesys2.server.service.impl; package org.genesys2.server.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.genesys2.server.exception.NoUserFoundException; import org.genesys2.server.exception.NoUserFoundException;
...@@ -49,9 +43,12 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; ...@@ -49,9 +43,12 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.social.google.api.userinfo.GoogleUserInfo;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.*;
@Service @Service
@Transactional(readOnly = true) @Transactional(readOnly = true)
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
...@@ -350,6 +347,23 @@ public class UserServiceImpl implements UserService { ...@@ -350,6 +347,23 @@ public class UserServiceImpl implements UserService {
LOG.info("Ensured VALIDATEDUSER role for user " + user); LOG.info("Ensured VALIDATEDUSER role for user " + user);
} }
@Override
public void googleAuthentication(GoogleUserInfo userInfo) throws UserException {
User user=getUserByEmail(userInfo.getEmail());
userEmailValidated(user.getUuid());
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("USER"));
grantedAuthorities.add(new SimpleGrantedAuthority("VALIDATEDUSER"));
AuthUserDetails userDetails = new AuthUserDetails(user.getUuid(), user.getPassword() , grantedAuthorities);
userDetails.setUser(user);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
private void addRoleToCurrentUser(User user, String role) { private void addRoleToCurrentUser(User user, String role) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
......
package org.genesys2.server.servlet.controller;
import org.apache.commons.lang.RandomStringUtils;
import org.genesys2.server.exception.UserException;
import org.genesys2.server.model.impl.User;
import org.genesys2.server.service.EMailVerificationService;
import org.genesys2.server.service.UserService;
import org.genesys2.server.servlet.util.GoogleOAuthUtil;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.social.google.api.Google;
import org.springframework.social.google.api.impl.GoogleTemplate;
import org.springframework.social.google.api.userinfo.GoogleUserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
@RequestMapping("/g")
public class GoogleSocialController extends BaseController {
@Value("${google.auth.url}")
private String url;
@Autowired
private UserService userService;
@Autowired
private EMailVerificationService emailService;
@Autowired
private GoogleOAuthUtil oAuth;
@RequestMapping("/login")
public void redirectToGoogle(HttpServletResponse response) throws IOException {
response.sendRedirect(url);
}
@RequestMapping("/auth")
public String googleAuth(Model model, HttpServletRequest request) throws IOException, JSONException, UserException {
String accessToken = oAuth.exchangeForAccessToken(request);
if (accessToken == null) {
model.addAttribute("error", true);
return "/login";
}
Google google = new GoogleTemplate(accessToken);
GoogleUserInfo userInfo = google.userOperations().getUserInfo();
if (!userService.exists(userInfo.getEmail())) {
String pwd = RandomStringUtils.randomAlphanumeric(10);
User user = userService.createAccount(userInfo.getEmail(), pwd, userInfo.getName());
emailService.sendPasswordForGenesysAccount(user, pwd);
}
userService.googleAuthentication(userInfo);
return "redirect:/profile";
}
}
...@@ -19,6 +19,7 @@ package org.genesys2.server.servlet.controller; ...@@ -19,6 +19,7 @@ package org.genesys2.server.servlet.controller;
import org.genesys2.server.model.Permissions; import org.genesys2.server.model.Permissions;
import org.genesys2.server.model.UserRole; import org.genesys2.server.model.UserRole;
import org.genesys2.server.model.impl.User; import org.genesys2.server.model.impl.User;
import org.genesys2.server.security.lockout.AccountLockoutManager;
import org.genesys2.server.service.ContentService; import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.CropService; import org.genesys2.server.service.CropService;
import org.genesys2.server.service.EMailVerificationService; import org.genesys2.server.service.EMailVerificationService;
...@@ -26,7 +27,6 @@ import org.genesys2.server.service.UserService; ...@@ -26,7 +27,6 @@ import org.genesys2.server.service.UserService;
import org.genesys2.util.ReCaptchaUtil; import org.genesys2.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
...@@ -40,6 +40,10 @@ import javax.servlet.http.HttpServletRequest; ...@@ -40,6 +40,10 @@ import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
/** /**
* Controller which simply handles *.html requests * Controller which simply handles *.html requests
*/ */
...@@ -64,6 +68,9 @@ public class HtmlController extends BaseController { ...@@ -64,6 +68,9 @@ public class HtmlController extends BaseController {
@Autowired @Autowired
private ContentService contentService; private ContentService contentService;
@Autowired
private AccountLockoutManager lockoutManager;
@Value("${captcha.privateKey}") @Value("${captcha.privateKey}")
private String captchaPrivateKey; private String captchaPrivateKey;
......
package org.genesys2.server.servlet.util;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class GoogleOAuthUtil {
private String clientId;
private String secret;
private String redirectUrl;
public String exchangeForAccessToken(HttpServletRequest request) throws IOException, JSONException {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://accounts.google.com/o/oauth2/token");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("code", request.getParameter("code")));
params.add(new BasicNameValuePair("client_id", clientId));
params.add(new BasicNameValuePair("client_secret", secret));
params.add(new BasicNameValuePair("redirect_uri", redirectUrl));
params.add(new BasicNameValuePair("grant_type", "authorization_code"));
params.add(new BasicNameValuePair("scope", ""));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpResponse response = httpclient.execute(httppost);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null; ) {
builder.append(line).append("\n");
}
JSONObject jsonObject = new JSONObject(builder.toString());
return jsonObject.getString("access_token") != null ? jsonObject.getString("access_token") : null;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setSecret(String secret) {
this.secret = secret;
}
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
}
...@@ -428,3 +428,4 @@ userprofile.email.send=Send email ...@@ -428,3 +428,4 @@ userprofile.email.send=Send email
verification.invalid-key=Token key is not valid. verification.invalid-key=Token key is not valid.
verification.token-key=Validation key verification.token-key=Validation key
login.invalid-token=Invalid access token
{
"en": {
"title": "Password for genesys account",
"body": "<h2><small>Genesys account</small><br/>Password for you genesys account</h2><p></p><h2>New password: {0}</h2><p>Thanks,<br/ >Genesys team</p>"
}
}
\ No newline at end of file
...@@ -31,5 +31,6 @@ ...@@ -31,5 +31,6 @@
<import resource="spring-security-acl.xml" /> <import resource="spring-security-acl.xml" />
<import resource="spring-security.xml" /> <import resource="spring-security.xml" />
<import resource="spring-mail.xml" /> <import resource="spring-mail.xml" />
<import resource="spring-social.xml" />
</beans> </beans>
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<aop:aspectj-autoproxy /> <aop:aspectj-autoproxy />
<context:property-placeholder ignore-resource-not-found="true" location="classpath:/application.properties,classpath:/spring/spring.properties,classpath:/genesys.properties"/> <context:property-placeholder ignore-resource-not-found="true" location="classpath:/*.properties,classpath:/spring/*.properties"/>
<context:component-scan base-package="org.genesys2.server"> <context:component-scan base-package="org.genesys2.server">
<!--Include @Entity for scanning of Acl Classes purposes--> <!--Include @Entity for scanning of Acl Classes purposes-->
......
...@@ -54,6 +54,9 @@ ...@@ -54,6 +54,9 @@
<prop key="hibernate.hbm2ddl.auto">${db.hbm2ddl}</prop> <prop key="hibernate.hbm2ddl.auto">${db.hbm2ddl}</prop>
<prop key="hibernate.search.default.indexBase">${lucene.indexDir}</prop> <prop key="hibernate.search.default.indexBase">${lucene.indexDir}</prop>
<prop key="hibernate.search.default.exclusive_index_use">false</prop> <prop key="hibernate.search.default.exclusive_index_use">false</prop>
<prop key="hibernate.connection.CharSet">utf8</prop>
<prop key="hibernate.connection.characterEncoding">utf8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
</props> </props>
</property> </property>
<property name="packagesToScan"> <property name="packagesToScan">
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013 Global Crop Diversity Trust
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd"
default-autowire="no">
<context:component-scan base-package="org.genesys2.server"/>
<context:property-placeholder ignore-resource-not-found="true" location="classpath:/spring/spring.properties"/>
<bean name="googleOAuthUtil" class="org.genesys2.server.servlet.util.GoogleOAuthUtil">
<property name="clientId" value="${google.consumerKey}"/>
<property name="secret" value="${google.consumerSecret}"/>
<property name="redirectUrl" value="${google.redirect.url}"/>
</bean>
</beans>
\ No newline at end of file
...@@ -16,12 +16,12 @@ ...@@ -16,12 +16,12 @@
base.url=http://localhost:8080 base.url=http://localhost:8080
db.url=jdbc:mysql://localhost/genesys4?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false db.url=jdbc:mysql://localhost/genesys2
db.driverClassName = com.mysql.jdbc.Driver db.driverClassName = com.mysql.jdbc.Driver
db.username = root db.username = root
db.password = 1 db.password = 1
db.showSql=false db.showSql=false
db.hbm2ddl=do-nothing db.hbm2ddl=update
c3p0.acquireIncrement=1 c3p0.acquireIncrement=1
c3p0.minPoolSize=1 c3p0.minPoolSize=1
...@@ -60,7 +60,6 @@ mail.user.from=test@example.com ...@@ -60,7 +60,6 @@ mail.user.from=test@example.com
mail.user.password= mail.user.password=
mail.user.name= mail.user.name=
mail.smtp.ssl.enable=true mail.smtp.ssl.enable=true
mail.smtp.auth=true mail.smtp.auth=true
mail.transport.protocol=smtp mail.transport.protocol=smtp
...@@ -75,4 +74,9 @@ mail.debug.message= Email has been sent succesfully\n\ ...@@ -75,4 +74,9 @@ mail.debug.message= Email has been sent succesfully\n\
%s\ %s\
\n\n================================== \n\n==================================
#google properties
google.consumerKey=534251255050-3o55n707i6fare7kcad32u6gs7r7t8h8.apps.googleusercontent.com
google.consumerSecret=tjbSs5iDFVeoNB7_mXX0M1dO
google.redirect.url=http://localhost:8080/g/auth
google.auth.url=https://accounts.google.com/o/oauth2/auth?redirect_uri=http://localhost:8080/g/auth&response_type=code&client_id=534251255050-3o55n707i6fare7kcad32u6gs7r7t8h8.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.me+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&approval_prompt=auto&access_type=online&include_granted_scopes=true
<%@include file="/WEB-INF/jsp/init.jsp"%> <%@include file="/WEB-INF/jsp/init.jsp" %>
<header id="header"> <header id="header">
<div class="container"> <div class="container">
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
<spring:message code="login.remember-me"/> <spring:message code="login.remember-me"/>
</label> </label>
</div> </div>
<button type="submit" class="btn btn-green"><spring:message code="login.login-button" /></button> <button type="submit" class="btn btn-green"><spring:message
code="login.login-button"/></button>
<a href="<c:url value="/g/login" />" class="btn btn-danger">Google+</a>
<span class="or"></span> <span class="or"></span>
<a href="<c:url value="/registration" />" class="btn btn-default"><spring:message code="login.register-now"/></a> <a href="<c:url value="/registration" />" class="btn btn-default"><spring:message code="login.register-now"/></a>
</form> </form>
...@@ -52,8 +54,11 @@ ...@@ -52,8 +54,11 @@
<li><a href="<c:url value="/profile/list" />"><spring:message code="user.pulldown.users" /></a></li> <li><a href="<c:url value="/profile/list" />"><spring:message code="user.pulldown.users" /></a></li>
<li><a href="<c:url value="/team" />"><spring:message code="user.pulldown.teams" /></a></li> <li><a href="<c:url value="/team" />"><spring:message code="user.pulldown.teams" /></a></li>
</security:authorize> </security:authorize>
<li><a href="<c:url value="/profile/${user.username}" />"><spring:message code="user.pulldown.profile" /></a></li> <li><a href="<c:url value="/profile/${user.username}" />"><spring:message
<li><a href="<c:url value="/logout" />"><spring:message code="user.pulldown.logout" /></a></li>