From 60b12fe50101d61a613bc010ee2f4c5d7bec4634 Mon Sep 17 00:00:00 2001 From: annabakouli Date: Wed, 10 Jan 2018 18:05:23 +0200 Subject: [PATCH] no message --- dmp-backend/pom.xml | 7 + .../handlers/PrincipalArgumentResolver.java | 13 +- .../loginprovider/LoginProviderUser.java | 54 ++++++ .../validators/TokenValidatorFactoryImpl.java | 11 +- .../facebook/FacebookTokenValidator.java | 79 ++++++++ .../google/FacebookTokenValidator.java | 124 ------------- .../google/GoogleTokenValidator.java | 99 +++------- .../linkedin/LinkedInTokenValidator.java | 53 ++++++ .../java/eu/eudat/services/ApiContext.java | 1 - .../eu/eudat/services/ApiContextImpl.java | 10 - .../eudat/services/AuthenticationService.java | 86 ++++++++- .../src/main/resources/application.properties | 5 + dmp-frontend/src/app/app-routing.module.ts | 4 +- dmp-frontend/src/app/app.constants.ts | 1 + dmp-frontend/src/app/app.module.ts | 22 ++- .../src/app/login/login.component.html | 45 ----- dmp-frontend/src/app/login/login.component.ts | 101 ---------- .../src/app/models/login/LoginInfo.ts | 8 +- dmp-frontend/src/app/shared/shared.module.ts | 1 + .../src/app/user-management/login.module.ts | 37 ++++ .../src/app/user-management/login.routes.ts | 11 ++ .../linkedin-login.component.html | 0 .../linkedin-login.component.ts | 26 +++ .../login/login.component.html | 47 +++++ .../login/login.component.scss | 0 .../user-management/login/login.component.ts | 59 ++++++ .../twitter-login.component.html | 0 .../twitter-login/twitter-login.component.ts | 9 + .../user-management/utilties/LoginOptions.ts | 8 + .../utilties/LoginProviderConfiguration.ts | 19 ++ .../utilties/LoginServiceConfiguration.ts | 14 ++ .../user-management/utilties/login-service.ts | 173 ++++++++++++++++++ dmp-frontend/src/index.html | 3 + 33 files changed, 744 insertions(+), 386 deletions(-) create mode 100644 dmp-backend/src/main/java/eu/eudat/models/loginprovider/LoginProviderUser.java create mode 100644 dmp-backend/src/main/java/eu/eudat/security/validators/facebook/FacebookTokenValidator.java delete mode 100644 dmp-backend/src/main/java/eu/eudat/security/validators/google/FacebookTokenValidator.java create mode 100644 dmp-backend/src/main/java/eu/eudat/security/validators/linkedin/LinkedInTokenValidator.java delete mode 100644 dmp-frontend/src/app/login/login.component.html delete mode 100644 dmp-frontend/src/app/login/login.component.ts create mode 100644 dmp-frontend/src/app/user-management/login.module.ts create mode 100644 dmp-frontend/src/app/user-management/login.routes.ts create mode 100644 dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.html create mode 100644 dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.ts create mode 100644 dmp-frontend/src/app/user-management/login/login.component.html rename dmp-frontend/src/app/{ => user-management}/login/login.component.scss (100%) create mode 100644 dmp-frontend/src/app/user-management/login/login.component.ts create mode 100644 dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.html create mode 100644 dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.ts create mode 100644 dmp-frontend/src/app/user-management/utilties/LoginOptions.ts create mode 100644 dmp-frontend/src/app/user-management/utilties/LoginProviderConfiguration.ts create mode 100644 dmp-frontend/src/app/user-management/utilties/LoginServiceConfiguration.ts create mode 100644 dmp-frontend/src/app/user-management/utilties/login-service.ts diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml index d6d887e24..82a0eea7e 100644 --- a/dmp-backend/pom.xml +++ b/dmp-backend/pom.xml @@ -179,6 +179,13 @@ 2.0.3.RELEASE + + + org.springframework.social + spring-social-linkedin + 1.0.0.RELEASE + + diff --git a/dmp-backend/src/main/java/eu/eudat/handlers/PrincipalArgumentResolver.java b/dmp-backend/src/main/java/eu/eudat/handlers/PrincipalArgumentResolver.java index d9734a2af..28ff46a27 100644 --- a/dmp-backend/src/main/java/eu/eudat/handlers/PrincipalArgumentResolver.java +++ b/dmp-backend/src/main/java/eu/eudat/handlers/PrincipalArgumentResolver.java @@ -19,28 +19,29 @@ import java.util.UUID; public final class PrincipalArgumentResolver implements HandlerMethodArgumentResolver { private AuthenticationService authenticationService; + @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.getParameterType().equals(Principal.class); } @Override - public Object resolveArgument(MethodParameter methodParameter,ModelAndViewContainer modelAndViewContainer,NativeWebRequest nativeWebRequest,WebDataBinderFactory webDataBinderFactory) throws Exception { + public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { String token = nativeWebRequest.getHeader("AuthToken"); - if(token == null)throw new UnauthorisedException("Authentication Information Is Missing"); + if (token == null) throw new UnauthorisedException("Authentication Information Is Missing"); UUID authToken; - try{ + try { authToken = UUID.fromString(token); - }catch (IllegalArgumentException ex){ + } catch (IllegalArgumentException ex) { throw new UnauthorisedException("Authentication Information Is Missing"); } Principal principal = this.authenticationService.Touch(authToken); - if(principal==null)throw new UnauthorisedException("Authentication Information Missing"); + if (principal == null) throw new UnauthorisedException("Authentication Information Missing"); return principal; } - public PrincipalArgumentResolver(AuthenticationService authenticationService){ + public PrincipalArgumentResolver(AuthenticationService authenticationService) { this.authenticationService = authenticationService; } diff --git a/dmp-backend/src/main/java/eu/eudat/models/loginprovider/LoginProviderUser.java b/dmp-backend/src/main/java/eu/eudat/models/loginprovider/LoginProviderUser.java new file mode 100644 index 000000000..74c69e6c6 --- /dev/null +++ b/dmp-backend/src/main/java/eu/eudat/models/loginprovider/LoginProviderUser.java @@ -0,0 +1,54 @@ +package eu.eudat.models.loginprovider; + +import eu.eudat.security.validators.TokenValidatorFactoryImpl; + +/** + * Created by ikalyvas on 1/9/2018. + */ +public class LoginProviderUser { + private String name; + private String email; + private String secret; + private boolean isVerified; + private TokenValidatorFactoryImpl.LoginProvider provider; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean getIsVerified() { + return isVerified; + } + + public void setIsVerified(boolean verified) { + isVerified = verified; + } + + public TokenValidatorFactoryImpl.LoginProvider getProvider() { + return provider; + } + + public void setProvider(TokenValidatorFactoryImpl.LoginProvider provider) { + this.provider = provider; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } +} diff --git a/dmp-backend/src/main/java/eu/eudat/security/validators/TokenValidatorFactoryImpl.java b/dmp-backend/src/main/java/eu/eudat/security/validators/TokenValidatorFactoryImpl.java index b86b0d21f..0258da90e 100644 --- a/dmp-backend/src/main/java/eu/eudat/security/validators/TokenValidatorFactoryImpl.java +++ b/dmp-backend/src/main/java/eu/eudat/security/validators/TokenValidatorFactoryImpl.java @@ -1,8 +1,8 @@ package eu.eudat.security.validators; -import eu.eudat.models.project.Project; -import eu.eudat.security.validators.google.FacebookTokenValidator; +import eu.eudat.security.validators.facebook.FacebookTokenValidator; import eu.eudat.security.validators.google.GoogleTokenValidator; +import eu.eudat.security.validators.linkedin.LinkedInTokenValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -42,11 +42,12 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory{ private GoogleTokenValidator googleTokenValidator; private FacebookTokenValidator facebookTokenValidator; - + private LinkedInTokenValidator linkedInTokenValidator; @Autowired - public TokenValidatorFactoryImpl(GoogleTokenValidator googleTokenValidator, FacebookTokenValidator facebookTokenValidator) { + public TokenValidatorFactoryImpl(GoogleTokenValidator googleTokenValidator, FacebookTokenValidator facebookTokenValidator,LinkedInTokenValidator linkedInTokenValidator) { this.googleTokenValidator = googleTokenValidator; this.facebookTokenValidator = facebookTokenValidator; + this.linkedInTokenValidator = linkedInTokenValidator; } public TokenValidator getProvider(LoginProvider provider) { @@ -55,6 +56,8 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory{ return this.googleTokenValidator; case FACEBOOK: return this.facebookTokenValidator; + case LINKEDIN: + return this.linkedInTokenValidator; default: throw new RuntimeException("Login Provider Not Implemented"); } diff --git a/dmp-backend/src/main/java/eu/eudat/security/validators/facebook/FacebookTokenValidator.java b/dmp-backend/src/main/java/eu/eudat/security/validators/facebook/FacebookTokenValidator.java new file mode 100644 index 000000000..d8c9e6960 --- /dev/null +++ b/dmp-backend/src/main/java/eu/eudat/security/validators/facebook/FacebookTokenValidator.java @@ -0,0 +1,79 @@ +package eu.eudat.security.validators.facebook; + +import eu.eudat.dao.entities.UserInfoDao; +import eu.eudat.dao.entities.security.CredentialDao; +import eu.eudat.dao.entities.security.UserTokenDao; +import eu.eudat.entities.Credential; +import eu.eudat.entities.UserInfo; +import eu.eudat.entities.UserToken; +import eu.eudat.exceptions.NonValidTokenException; +import eu.eudat.models.criteria.UserInfoCriteria; +import eu.eudat.models.loginprovider.LoginProviderUser; +import eu.eudat.models.security.Principal; +import eu.eudat.security.validators.TokenValidator; +import eu.eudat.security.validators.TokenValidatorFactoryImpl; +import eu.eudat.services.ApiContext; +import eu.eudat.services.AuthenticationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.social.connect.Connection; +import org.springframework.social.connect.ConnectionKey; +import org.springframework.social.facebook.api.Facebook; +import org.springframework.social.facebook.api.User; +import org.springframework.social.facebook.connect.FacebookConnectionFactory; +import org.springframework.social.facebook.connect.FacebookServiceProvider; +import org.springframework.social.oauth2.AccessGrant; +import org.springframework.social.oauth2.OAuth2Operations; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.*; + +/** + * Created by ikalyvas on 1/9/2018. + */ +@Component("facebookTokenValidator") +public class FacebookTokenValidator implements TokenValidator { + + private Environment environment; + private ApiContext apiContext; + private AuthenticationService authenticationService; + private FacebookServiceProvider facebookServiceProvider; + + @Autowired + public FacebookTokenValidator(Environment environment,ApiContext apiContext,AuthenticationService authenticationService) { + this.environment = environment; + this.apiContext= apiContext; + this.authenticationService = authenticationService; + this.facebookServiceProvider = new FacebookServiceProvider(this.environment.getProperty("facebook.login.clientId"), this.environment.getProperty("facebook.login.clientSecret"),this.environment.getProperty("facebook.login.namespace")); + } + + @Override + public Principal validateToken(String token) throws NonValidTokenException, IOException, GeneralSecurityException { + User profile = getFacebookUser(token); + LoginProviderUser user = new LoginProviderUser(); + user.setEmail(profile.getEmail()); + user.setIsVerified(profile.isVerified()); + user.setName(profile.getName()); + user.setProvider(TokenValidatorFactoryImpl.LoginProvider.FACEBOOK); + user.setSecret(token); + return this.authenticationService.Touch(user); + } + + + private User getFacebookUser(String accessToken) { + String [] fields = { "id", "email", "first_name", "last_name","name","verified" }; + User profile = this.facebookServiceProvider.getApi(accessToken).fetchObject("me",User.class,fields); + return profile; + } + + private Date addADay(Date date){ + Date dt = new Date(); + Calendar c = Calendar.getInstance(); + c.setTime(dt); + c.add(Calendar.DATE, 1); + dt = c.getTime(); + return dt; + } +} diff --git a/dmp-backend/src/main/java/eu/eudat/security/validators/google/FacebookTokenValidator.java b/dmp-backend/src/main/java/eu/eudat/security/validators/google/FacebookTokenValidator.java deleted file mode 100644 index 58cf562f2..000000000 --- a/dmp-backend/src/main/java/eu/eudat/security/validators/google/FacebookTokenValidator.java +++ /dev/null @@ -1,124 +0,0 @@ -package eu.eudat.security.validators.google; - -import eu.eudat.dao.entities.UserInfoDao; -import eu.eudat.dao.entities.security.CredentialDao; -import eu.eudat.dao.entities.security.UserTokenDao; -import eu.eudat.entities.Credential; -import eu.eudat.entities.UserInfo; -import eu.eudat.entities.UserToken; -import eu.eudat.exceptions.NonValidTokenException; -import eu.eudat.models.criteria.UserInfoCriteria; -import eu.eudat.models.security.Principal; -import eu.eudat.security.validators.TokenValidator; -import eu.eudat.security.validators.TokenValidatorFactoryImpl; -import eu.eudat.services.ApiContext; -import eu.eudat.services.AuthenticationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.social.connect.Connection; -import org.springframework.social.connect.ConnectionKey; -import org.springframework.social.facebook.api.Facebook; -import org.springframework.social.facebook.api.User; -import org.springframework.social.facebook.connect.FacebookConnectionFactory; -import org.springframework.social.facebook.connect.FacebookServiceProvider; -import org.springframework.social.oauth2.AccessGrant; -import org.springframework.social.oauth2.OAuth2Operations; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.*; - -/** - * Created by ikalyvas on 1/9/2018. - */ -@Component("facebookTokenValidator") -public class FacebookTokenValidator implements TokenValidator { - - private Environment environment; - private ApiContext apiContext; - private FacebookServiceProvider facebookServiceProvider; - - @Autowired - public FacebookTokenValidator(Environment environment,ApiContext apiContext) { - this.environment = environment; - this.apiContext= apiContext; - this.facebookServiceProvider = new FacebookServiceProvider(this.environment.getProperty("facebook.login.clientId"), this.environment.getProperty("facebook.login.clientSecret"),this.environment.getProperty("facebook.login.namespace")); - } - - @Override - public Principal validateToken(String token) throws NonValidTokenException, IOException, GeneralSecurityException { - User profile = getFacebookUserId(token); - - UserInfoCriteria criteria = new UserInfoCriteria(); - criteria.setEmail(profile.getEmail()); - List users = apiContext.getDatabaseRepository().getUserInfoDao().getWithCriteria(criteria).toList(); - UserInfo userInfo = null; - if(users.size()>0)userInfo = users.get(0); - final Credential credential = new Credential(); - credential.setId(UUID.randomUUID()); - credential.setCreationTime(new Date()); - credential.setStatus(1); - credential.setLastUpdateTime(new Date()); - credential.setProvider((int)TokenValidatorFactoryImpl.LoginProvider.FACEBOOK.getValue()); - credential.setSecret(token); - if(userInfo == null) { - userInfo = new UserInfo(); - userInfo.setName((String)profile.getName()); - userInfo.setVerified_email(profile.isVerified()); - userInfo.setEmail(profile.getEmail()); - userInfo.setCreated(new Date()); - userInfo.setLastloggedin(new Date()); - userInfo.setAuthorization_level(new Short("1")); - userInfo.setUsertype(new Short("1")); - userInfo = apiContext.getDatabaseRepository().getUserInfoDao().createOrUpdate(userInfo); - - credential.setPublicValue(userInfo.getName()); - - credential.setUserInfo(userInfo); - apiContext.getDatabaseRepository().getCredentialDao().createOrUpdate(credential); - } - else { - userInfo.setLastloggedin(new Date()); - Set credentials = userInfo.getCredentials(); - if(credentials.contains(credential)){ - Credential oldCredential = credentials.stream().filter(item->credential.getProvider().equals(item.getProvider())).findFirst().get(); - credential.setId(oldCredential.getId()); - } - else{ - credential.setUserInfo(userInfo); - credential.setId(UUID.randomUUID()); - credential.setPublicValue(userInfo.getName()); - - apiContext.getDatabaseRepository().getCredentialDao().createOrUpdate(credential); - userInfo.getCredentials().add(credential); - } - userInfo = apiContext.getDatabaseRepository().getUserInfoDao().createOrUpdate(userInfo); - - } - - UserToken userToken = new UserToken(); - userToken.setUser(userInfo); - userToken.setIssuedAt(new Date()); - userToken.setToken(UUID.randomUUID()); - userToken.setExpiresAt(addADay(new Date())); - apiContext.getDatabaseRepository().getUserTokenDao().create(userToken); - return apiContext.getAuthenticationService().Touch(userToken.getToken()); - } - - - private User getFacebookUserId(String accessToken) { - String [] fields = { "id", "email", "first_name", "last_name","name" }; - User profile = this.facebookServiceProvider.getApi(accessToken).fetchObject("me",User.class,fields); - return profile; - } - - private Date addADay(Date date){ - Date dt = new Date(); - Calendar c = Calendar.getInstance(); - c.setTime(dt); - c.add(Calendar.DATE, 1); - dt = c.getTime(); - return dt; - } -} diff --git a/dmp-backend/src/main/java/eu/eudat/security/validators/google/GoogleTokenValidator.java b/dmp-backend/src/main/java/eu/eudat/security/validators/google/GoogleTokenValidator.java index 593b7e99e..e81a58eae 100644 --- a/dmp-backend/src/main/java/eu/eudat/security/validators/google/GoogleTokenValidator.java +++ b/dmp-backend/src/main/java/eu/eudat/security/validators/google/GoogleTokenValidator.java @@ -15,8 +15,10 @@ import eu.eudat.entities.Credential; import eu.eudat.entities.UserToken; import eu.eudat.models.criteria.UserInfoCriteria; import eu.eudat.models.login.LoginInfo; +import eu.eudat.models.loginprovider.LoginProviderUser; import eu.eudat.security.validators.TokenValidator; import eu.eudat.security.validators.TokenValidatorFactoryImpl; +import eu.eudat.services.ApiContext; import eu.eudat.services.AuthenticationService; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +30,7 @@ import com.google.api.client.json.jackson2.JacksonFactory; import eu.eudat.dao.entities.UserInfoDao; import eu.eudat.entities.UserInfo; import eu.eudat.exceptions.NonValidTokenException; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; @@ -37,23 +40,23 @@ import static com.sun.org.apache.xalan.internal.xsltc.compiler.Constants.REDIREC public class GoogleTokenValidator implements TokenValidator { private static final HttpTransport transport = new NetHttpTransport(); - @Autowired private UserInfoDao userInfoDao; - @Autowired private CredentialDao credentialDao; - @Autowired private AuthenticationService authenticationService; - @Autowired private UserTokenDao userTokenDao; + private ApiContext apiContext; + private AuthenticationService authenticationService; private GoogleIdTokenVerifier verifier; - public GoogleTokenValidator(){ + private Environment environment; + + @Autowired + public GoogleTokenValidator(ApiContext apiContext, Environment environment,AuthenticationService authenticationService){ + this.apiContext = apiContext; + this.environment = environment; + this.authenticationService = authenticationService; verifier = new GoogleIdTokenVerifier.Builder(transport, JacksonFactory.getDefaultInstance()) - .setAudience(Collections.singletonList("524432312250-sc9qsmtmbvlv05r44onl6l93ia3k9deo.apps.googleusercontent.com")) - // Or, if multiple clients access the backend: - //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3)) + .setAudience(Collections.singletonList(this.environment.getProperty("google.login.clientId"))) .build(); } private GoogleIdToken verifyUserAndGetUser(String idTokenString) throws IOException, GeneralSecurityException { - GoogleIdToken idToken = verifier.verify(idTokenString); - return idToken; } @@ -62,73 +65,13 @@ public class GoogleTokenValidator implements TokenValidator { GoogleIdToken idToken = this.verifyUserAndGetUser(token); Payload payload = idToken.getPayload(); - - UserInfoCriteria criteria = new UserInfoCriteria(); - criteria.setEmail(payload.getEmail()); - List users = userInfoDao.getWithCriteria(criteria).toList(); - UserInfo userInfo = null; - if(users.size()>0)userInfo = users.get(0); - final Credential credential = new Credential(); - credential.setId(UUID.randomUUID()); - credential.setCreationTime(new Date()); - credential.setStatus(1); - credential.setLastUpdateTime(new Date()); - credential.setProvider((int)TokenValidatorFactoryImpl.LoginProvider.GOOGLE.getValue()); - credential.setSecret(token); - if(userInfo == null) { - userInfo = new UserInfo(); - userInfo.setName((String)payload.get("name")); - userInfo.setVerified_email(payload.getEmailVerified()); - userInfo.setEmail(payload.getEmail()); - userInfo.setCreated(new Date()); - userInfo.setLastloggedin(new Date()); - userInfo.setAuthorization_level(new Short("1")); - userInfo.setUsertype(new Short("1")); - userInfo = userInfoDao.createOrUpdate(userInfo); - - credential.setPublicValue(userInfo.getName()); - - credential.setUserInfo(userInfo); - credentialDao.createOrUpdate(credential); - } - else { - userInfo.setLastloggedin(new Date()); - Set credentials = userInfo.getCredentials(); - if(credentials.contains(credential)){ - Credential oldCredential = credentials.stream().filter(item->credential.getProvider().equals(item.getProvider())).findFirst().get(); - credential.setId(oldCredential.getId()); - } - else{ - credential.setUserInfo(userInfo); - credential.setId(UUID.randomUUID()); - credential.setPublicValue(userInfo.getName()); - - credentialDao.createOrUpdate(credential); - userInfo.getCredentials().add(credential); - } - userInfo = userInfoDao.createOrUpdate(userInfo); - - } - - UserToken userToken = new UserToken(); - userToken.setUser(userInfo); - userToken.setIssuedAt(new Date()); - userToken.setToken(UUID.randomUUID()); - userToken.setExpiresAt(addADay(new Date())); - userTokenDao.create(userToken); - return authenticationService.Touch(userToken.getToken()); - + LoginProviderUser user = new LoginProviderUser(); + user.setSecret(token); + user.setProvider(TokenValidatorFactoryImpl.LoginProvider.GOOGLE); + user.setName((String)payload.get("name")); + user.setEmail(payload.getEmail()); + user.setIsVerified(payload.getEmailVerified()); + return this.authenticationService.Touch(user); } - - private Date addADay(Date date){ - Date dt = new Date(); - Calendar c = Calendar.getInstance(); - c.setTime(dt); - c.add(Calendar.DATE, 1); - dt = c.getTime(); - return dt; - } - - - + } diff --git a/dmp-backend/src/main/java/eu/eudat/security/validators/linkedin/LinkedInTokenValidator.java b/dmp-backend/src/main/java/eu/eudat/security/validators/linkedin/LinkedInTokenValidator.java new file mode 100644 index 000000000..2bbb829dd --- /dev/null +++ b/dmp-backend/src/main/java/eu/eudat/security/validators/linkedin/LinkedInTokenValidator.java @@ -0,0 +1,53 @@ +package eu.eudat.security.validators.linkedin; + +import eu.eudat.exceptions.NonValidTokenException; +import eu.eudat.models.loginprovider.LoginProviderUser; +import eu.eudat.models.security.Principal; +import eu.eudat.security.validators.TokenValidator; +import eu.eudat.security.validators.TokenValidatorFactoryImpl; +import eu.eudat.services.ApiContext; +import eu.eudat.services.AuthenticationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.social.facebook.connect.FacebookServiceProvider; +import org.springframework.social.linkedin.api.LinkedIn; +import org.springframework.social.linkedin.api.LinkedInProfile; +import org.springframework.social.linkedin.connect.LinkedInServiceProvider; +import org.springframework.social.oauth2.AccessGrant; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +/** + * Created by ikalyvas on 1/10/2018. + */ +@Component("linkedInTokenValidator") +public class LinkedInTokenValidator implements TokenValidator { + + private Environment environment; + private ApiContext apiContext; + private AuthenticationService authenticationService; + private LinkedInServiceProvider linkedInServiceProvider; + + @Autowired + public LinkedInTokenValidator(Environment environment,ApiContext apiContext,AuthenticationService authenticationService) { + this.environment = environment; + this.apiContext= apiContext; + this.authenticationService = authenticationService; + this.linkedInServiceProvider = new LinkedInServiceProvider(this.environment.getProperty("linkedin.login.clientId"), this.environment.getProperty("linkedin.login.clientSecret")); + } + @Override + public Principal validateToken(String token) throws NonValidTokenException, IOException, GeneralSecurityException { + AccessGrant accessGrant =this.linkedInServiceProvider.getOAuthOperations().exchangeForAccess(token,"http://localhost:4200/login/linkedin",null); + LinkedIn linkedInService = this.linkedInServiceProvider.getApi(accessGrant.getAccessToken()); + LinkedInProfile linkedInProfile = linkedInService.profileOperations().getUserProfile(); + LoginProviderUser user = new LoginProviderUser(); + user.setEmail(linkedInProfile.getEmailAddress()); + user.setIsVerified(true); //TODO + user.setName(linkedInProfile.getFirstName()+" "+linkedInProfile.getLastName()); + user.setProvider(TokenValidatorFactoryImpl.LoginProvider.LINKEDIN); + user.setSecret(accessGrant.getAccessToken()); + return this.authenticationService.Touch(user); + } +} diff --git a/dmp-backend/src/main/java/eu/eudat/services/ApiContext.java b/dmp-backend/src/main/java/eu/eudat/services/ApiContext.java index 341ab43c7..5f7cc8c78 100644 --- a/dmp-backend/src/main/java/eu/eudat/services/ApiContext.java +++ b/dmp-backend/src/main/java/eu/eudat/services/ApiContext.java @@ -12,5 +12,4 @@ public interface ApiContext { InvitationService getInvitationService(); RemoteFetcher getRemoteFetcher(); MailService getMailService(); - AuthenticationService getAuthenticationService(); } diff --git a/dmp-backend/src/main/java/eu/eudat/services/ApiContextImpl.java b/dmp-backend/src/main/java/eu/eudat/services/ApiContextImpl.java index 7dfe45117..ff0554386 100644 --- a/dmp-backend/src/main/java/eu/eudat/services/ApiContextImpl.java +++ b/dmp-backend/src/main/java/eu/eudat/services/ApiContextImpl.java @@ -16,7 +16,6 @@ public class ApiContextImpl implements ApiContext{ private RemoteFetcher remoteFetcher; private InvitationService invitationService; private MailService mailService; - private AuthenticationService authenticationService; @Autowired public void setDatabaseRepository(DatabaseRepository databaseRepository) { @@ -68,13 +67,4 @@ public class ApiContextImpl implements ApiContext{ this.mailService = mailService; } - @Override - public AuthenticationService getAuthenticationService() { - return authenticationService; - } - - @Autowired - public void setAuthenticationService(AuthenticationService authenticationService) { - this.authenticationService = authenticationService; - } } diff --git a/dmp-backend/src/main/java/eu/eudat/services/AuthenticationService.java b/dmp-backend/src/main/java/eu/eudat/services/AuthenticationService.java index 83570e5fd..fd96f6af6 100644 --- a/dmp-backend/src/main/java/eu/eudat/services/AuthenticationService.java +++ b/dmp-backend/src/main/java/eu/eudat/services/AuthenticationService.java @@ -2,30 +2,34 @@ package eu.eudat.services; import eu.eudat.dao.entities.UserInfoDao; import eu.eudat.dao.entities.security.UserTokenDao; +import eu.eudat.entities.Credential; import eu.eudat.entities.UserInfo; import eu.eudat.entities.UserToken; +import eu.eudat.models.criteria.UserInfoCriteria; +import eu.eudat.models.loginprovider.LoginProviderUser; import eu.eudat.models.security.Principal; +import eu.eudat.security.validators.TokenValidatorFactoryImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.xml.ws.ServiceMode; -import java.util.Date; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * Created by ikalyvas on 12/15/2017. */ @Service("authenticationService ") public class AuthenticationService { + private ApiContext apiContext; + @Autowired - UserTokenDao userTokenDao; - @Autowired - UserInfoDao userInfoDao; + public AuthenticationService(ApiContext apiContext) { + this.apiContext = apiContext; + } public Principal Touch(UUID token) { - UserToken tokenEntry = userTokenDao.read(token); + UserToken tokenEntry = this.apiContext.getDatabaseRepository().getUserTokenDao().read(token); if (tokenEntry == null || tokenEntry.getExpiresAt().before(new Date())) return null; Principal principal = this.Touch(tokenEntry); @@ -35,15 +39,15 @@ public class AuthenticationService { public void Logout(UUID token) { - UserToken tokenEntry = userTokenDao.read(token); - userTokenDao.delete(tokenEntry); + UserToken tokenEntry = this.apiContext.getDatabaseRepository().getUserTokenDao().read(token); + this.apiContext.getDatabaseRepository().getUserTokenDao().delete(tokenEntry); } private Principal Touch(UserToken token) { if (token == null || token.getExpiresAt().before(new Date())) return null; - UserInfo user = this.userInfoDao.find(token.getUser().getId()); + UserInfo user = this.apiContext.getDatabaseRepository().getUserInfoDao().find(token.getUser().getId()); if (user == null /*|| user.Status != ActivityStatus.Active*/) return null; //List appRoles = this._unitOfWork.UserRoles.GetAll().Where(x => x.UserId == token.UserId /*&& x.Status == ActivityStatus.Active*/).ToList(); @@ -64,4 +68,66 @@ public class AuthenticationService { */ return principal; } + + public Principal Touch(LoginProviderUser profile){ + UserInfoCriteria criteria = new UserInfoCriteria(); + criteria.setEmail(profile.getEmail()); + List users = apiContext.getDatabaseRepository().getUserInfoDao().getWithCriteria(criteria).toList(); + UserInfo userInfo = null; + if(users.size()>0)userInfo = users.get(0); + final Credential credential = new Credential(); + credential.setId(UUID.randomUUID()); + credential.setCreationTime(new Date()); + credential.setStatus(1); + credential.setLastUpdateTime(new Date()); + credential.setProvider((int) TokenValidatorFactoryImpl.LoginProvider.FACEBOOK.getValue()); + credential.setSecret(profile.getSecret()); + if(userInfo == null) { + userInfo = new UserInfo(); + userInfo.setName((String)profile.getName()); + userInfo.setVerified_email(profile.getIsVerified()); + userInfo.setEmail(profile.getEmail()); + userInfo.setCreated(new Date()); + userInfo.setLastloggedin(new Date()); + userInfo.setAuthorization_level(new Short("1")); + userInfo.setUsertype(new Short("1")); + userInfo = apiContext.getDatabaseRepository().getUserInfoDao().createOrUpdate(userInfo); + credential.setPublicValue(userInfo.getName()); + credential.setUserInfo(userInfo); + apiContext.getDatabaseRepository().getCredentialDao().createOrUpdate(credential); + } + else { + userInfo.setLastloggedin(new Date()); + Set credentials = userInfo.getCredentials(); + if(credentials.contains(credential)){ + Credential oldCredential = credentials.stream().filter(item->credential.getProvider().equals(item.getProvider())).findFirst().get(); + credential.setId(oldCredential.getId()); + } + else{ + credential.setUserInfo(userInfo); + credential.setId(UUID.randomUUID()); + credential.setPublicValue(userInfo.getName()); + apiContext.getDatabaseRepository().getCredentialDao().createOrUpdate(credential); + userInfo.getCredentials().add(credential); + } + userInfo = apiContext.getDatabaseRepository().getUserInfoDao().createOrUpdate(userInfo); + } + + UserToken userToken = new UserToken(); + userToken.setUser(userInfo); + userToken.setIssuedAt(new Date()); + userToken.setToken(UUID.randomUUID()); + userToken.setExpiresAt(addADay(new Date())); + apiContext.getDatabaseRepository().getUserTokenDao().create(userToken); + return Touch(userToken.getToken()); + } + + private Date addADay(Date date){ + Date dt = new Date(); + Calendar c = Calendar.getInstance(); + c.setTime(dt); + c.add(Calendar.DATE, 1); + dt = c.getTime(); + return dt; + } } diff --git a/dmp-backend/src/main/resources/application.properties b/dmp-backend/src/main/resources/application.properties index 130b4497e..b3f2a4757 100644 --- a/dmp-backend/src/main/resources/application.properties +++ b/dmp-backend/src/main/resources/application.properties @@ -33,6 +33,11 @@ mail.from = citesagrdev@gmail.com facebook.login.clientId = 110586756143149 facebook.login.clientSecret = 522a847f05c873d0222c85109e24f55a facebook.login.namespace = eudat +########################GOOGLE LOGIN Properties############################# +google.login.clientId = 524432312250-sc9qsmtmbvlv05r44onl6l93ia3k9deo.apps.googleusercontent.com +########################LINKEDIN LOGIN Properties############################# +linkedin.login.clientId = 86bl8vfk77clh9 +linkedin.login.clientSecret = 2OCO9e3wKylW05Tt ########################Persistence/Hibernate/Batch############################## #persistence.hibernate.jdbc.batch_size = 30 #persistence.hibernate.order_inserts = true diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index 977a7ff96..490152415 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -14,8 +14,8 @@ import { ProjectEditorComponent } from './projects/editor/project-editor.compone import { DataManagementPlanEditorComponent } from './dmps/editor/dmp-editor.component'; import { DatasetEditorComponent } from './datasets/editor/dataset-editor.component'; import { DatasetListingComponent } from './datasets/dataset-listing.component'; -import { LoginComponent } from './login/login.component'; import { DatasetWizardComponent } from './dataset-wizard/dataset-wizard.component'; +import { LoginComponent } from './user-management/login/login.component'; const appRoutes: Routes = [ @@ -31,7 +31,7 @@ const appRoutes: Routes = [ { path: 'dataset/:id', component: DatasetWizardComponent, canActivate: [AuthGuard] }, { path: 'datasets/new', component: DatasetWizardComponent, canActivate: [AuthGuard] }, { path: 'invitation/:id', component: InvitationAcceptedComponent}, - { path: 'login', component: LoginComponent }, + { path: 'login', loadChildren: './user-management/login.module#LoginModule' }, { path: "unauthorized", loadChildren: './unauthorized/unauthorized.module#UnauthorizedModule' }, { path: 'welcome', component: HomepageComponent, canActivate: [AuthGuard] }, { path: '', redirectTo: '/welcome', pathMatch: 'full' }, diff --git a/dmp-frontend/src/app/app.constants.ts b/dmp-frontend/src/app/app.constants.ts index 2cf927bf2..d599ff1c5 100644 --- a/dmp-frontend/src/app/app.constants.ts +++ b/dmp-frontend/src/app/app.constants.ts @@ -1,5 +1,6 @@ export const HostConfiguration = { Server: 'http://192.168.32.96:8080/', + App: 'http://localhost:4200/' //CASHost: 'https://login-devel.uoa.gr/login', //Service: 'http://elkefinman/login' } \ No newline at end of file diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index 928946f83..40b1cc6c0 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -1,3 +1,6 @@ +import { HostConfiguration } from './app.constants'; +import { LoginOptions } from './user-management/utilties/LoginOptions'; +import { LoginModule } from './user-management/login.module'; import { InvitationAcceptedComponent } from './invitation-accepted/invitation-accepted.component'; import { InvitationComponent } from './invitation/invitation.component'; import { UnauthorizedComponent } from './unauthorized/unauthorized.component'; @@ -47,7 +50,6 @@ import { BaseHttpService } from './utilities/cite-http-service-module/base-http. import { DataManagementPlanListingComponent } from './dmps/dmp-listing.component'; import { ProjectEditorComponent } from './projects/editor/project-editor.component'; import { DataManagementPlanEditorComponent } from './dmps/editor/dmp-editor.component'; -import { LoginComponent } from './login/login.component'; import { FigurecardComponent } from './shared/components/figurecard/figurecard.component'; import { DatasetListingComponent } from './datasets/dataset-listing.component'; import { DatasetEditorComponent } from './datasets/editor/dataset-editor.component'; @@ -69,7 +71,6 @@ import { AutocompleteComponent } from './shared/components/autocomplete/autocomp TableOfContentsFieldSetComponent, TableOfContentsGroupComponent, TableOfContentsSectionComponent, - LoginComponent, PageNotFoundComponent, HomepageComponent, ProjectListingComponent, @@ -95,6 +96,23 @@ import { AutocompleteComponent } from './shared/components/autocomplete/autocomp ReactiveFormsModule, SharedModule, FormsModule, + LoginModule.forRoot({ + loginProviders: [ + LoginOptions.facebookOauth, + LoginOptions.googleOauth, + LoginOptions.nativeLogin, + LoginOptions.linkedInOauth + ], + facebookConfiguration: { clientId: "110586756143149" }, + googleConfiguration: { clientId: '524432312250-sc9qsmtmbvlv05r44onl6l93ia3k9deo.apps.googleusercontent.com' }, + linkedInConfiguration: { + clientId: "86bl8vfk77clh9", + oauthUrl: "https://www.linkedin.com/oauth/v2/authorization", + redirectUri: HostConfiguration.App + "login/linkedin", + accessTokenUri: "https://www.linkedin.com/oauth/v2/accessToken", + clientSecret: "2OCO9e3wKylW05Tt" + } + }), HttpModule, HttpClientModule, CommonModule, diff --git a/dmp-frontend/src/app/login/login.component.html b/dmp-frontend/src/app/login/login.component.html deleted file mode 100644 index 08ccaa75b..000000000 --- a/dmp-frontend/src/app/login/login.component.html +++ /dev/null @@ -1,45 +0,0 @@ -
-
-
-
-
-
-

Login

- -
-

Or Be Classical

-
-
- email - - - -
-
- lock_outline - - - -
-
- -
-
-
-
-
\ No newline at end of file diff --git a/dmp-frontend/src/app/login/login.component.ts b/dmp-frontend/src/app/login/login.component.ts deleted file mode 100644 index c0bdc7046..000000000 --- a/dmp-frontend/src/app/login/login.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { LoginProviders } from '../models/login/LoginInfo'; -import { HttpClient } from '@angular/common/http'; -import { Component, OnInit, ElementRef, AfterViewInit, VERSION, Injectable, NgZone } from '@angular/core'; -import { Router, ActivatedRoute, Params } from "@angular/router"; -import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; -import { TranslateService } from "@ngx-translate/core"; -import { AuthService } from '../services/auth/auth.service'; -import { SnackBarNotificationComponent } from '../shared/components/notificaiton/snack-bar-notification.component'; - -declare const gapi: any; -declare const FB: any; - -@Component({ - selector: 'login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.scss'] -}) -export class LoginComponent implements OnInit { - - public auth2: any; - - constructor(private router: Router, - public authService: AuthService, - public route: ActivatedRoute, - public snackBar: MatSnackBar, - public language: TranslateService, - private zone: NgZone - ) { } - - - - ngOnInit() { - gapi.load('auth2', () => { - this.auth2 = gapi.auth2.init({ - client_id: '524432312250-sc9qsmtmbvlv05r44onl6l93ia3k9deo.apps.googleusercontent.com', - cookiepolicy: 'single_host_origin', - scope: 'profile email' - }); - this.attachGoogleSignin(document.getElementById('googleSignInButton')); - }); - - FB.init({ - appId: '110586756143149', - cookie: false, // enable cookies to allow the server to access - // the session - xfbml: true, // parse social plugins on this page - version: 'v2.8' // use graph api version 2.5 - }); - } - - public attachGoogleSignin(element) { - this.auth2.attachClickHandler(element, {}, - (googleUser) => { - - var id_token = googleUser.getAuthResponse().id_token; - if (id_token) { - this.authService.login({ ticket: id_token, provider: LoginProviders.Google }).subscribe( - res => this.onLogInSuccess(res), - error => this.onLogInError(error) - ) - } - - }, (error) => { - alert(JSON.stringify(error, undefined, 2)); - }); - } - - public onLogInSuccess(logoutMessage: any) { - this.snackBar.openFromComponent(SnackBarNotificationComponent, { - data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN', language: this.language }, - duration: 3000, - extraClasses: ['snackbar-success'] - }); - this.route.queryParams.subscribe((params: Params) => { - let redirectUrl = params['returnUrl'] ? params['returnUrl'] : '/'; - this.zone.run(() => this.router.navigate([redirectUrl])); - }) - } - - public onLogInError(errorMessage: string) { - console.log(errorMessage); - this.snackBar.openFromComponent(SnackBarNotificationComponent, { - data: { message: 'GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN', language: this.language }, - duration: 3000, - extraClasses: ['snackbar-warning'] - }) - } - - public facebookLogin() { - - FB.login((response: any) => { - if (response.status === 'connected' || 'not_authorized') { - this.authService.login({ ticket: response.authResponse.accessToken, provider: LoginProviders.Facebook }).subscribe( - res => this.onLogInSuccess(res), - error => this.onLogInError(error) - ) - } - - }, { scope: 'user_friends,email' }); - } -} \ No newline at end of file diff --git a/dmp-frontend/src/app/models/login/LoginInfo.ts b/dmp-frontend/src/app/models/login/LoginInfo.ts index b84cc403b..26d96ba25 100644 --- a/dmp-frontend/src/app/models/login/LoginInfo.ts +++ b/dmp-frontend/src/app/models/login/LoginInfo.ts @@ -1,7 +1,9 @@ -export enum LoginProviders{ +export enum LoginProviders { Google = 1, - Facebook = 2 - } + Facebook = 2, + Twitter = 3, + LinkedIn = 4 +} export class LoginInfo { public ticket: string; diff --git a/dmp-frontend/src/app/shared/shared.module.ts b/dmp-frontend/src/app/shared/shared.module.ts index 11a5961d9..9c0afda68 100644 --- a/dmp-frontend/src/app/shared/shared.module.ts +++ b/dmp-frontend/src/app/shared/shared.module.ts @@ -28,6 +28,7 @@ import { DataManagementPlanCriteriaComponent } from './components/criteria/data- ], exports: [ + MaterialModule, NavigationComponent, SnackBarNotificationComponent, ProjectCriteriaComponent, diff --git a/dmp-frontend/src/app/user-management/login.module.ts b/dmp-frontend/src/app/user-management/login.module.ts new file mode 100644 index 000000000..250127327 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login.module.ts @@ -0,0 +1,37 @@ +import { SnackBarNotificationComponent } from '../shared/components/notificaiton/snack-bar-notification.component'; +import { LinkedInLoginComponent } from './login/linkedin-login/linkedin-login.component'; +import { LoginRoutes } from './login.routes'; +import { MaterialModule } from '../shared/material/material.module'; +import { SharedModule } from '../shared/shared.module'; +import { LoginServiceConfiguration } from './utilties/LoginServiceConfiguration'; +import { LoginService } from './utilties/login-service'; +import { LoginComponent } from './login/login.component'; +import { ModuleWithProviders, NgModule } from "@angular/core"; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [ + SharedModule, + CommonModule, + LoginRoutes + ], + declarations: [ + LoginComponent, + LinkedInLoginComponent + ], + exports: [ + LoginComponent, + LinkedInLoginComponent + ], + providers: [LoginService] +}) +export class LoginModule { + static forRoot(config: LoginServiceConfiguration): ModuleWithProviders { + return { + ngModule: LoginModule, + providers: [ + { provide: LoginServiceConfiguration, useValue: config } + ], + }; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/login.routes.ts b/dmp-frontend/src/app/user-management/login.routes.ts new file mode 100644 index 000000000..756ce2429 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login.routes.ts @@ -0,0 +1,11 @@ +import { LinkedInLoginComponent } from './login/linkedin-login/linkedin-login.component'; +import { LoginComponent } from './login/login.component'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { path: '', component: LoginComponent }, + { path: 'linkedin', component: LinkedInLoginComponent } + +]; + +export const LoginRoutes = RouterModule.forChild(routes); diff --git a/dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.html b/dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.ts b/dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.ts new file mode 100644 index 000000000..af9ebe386 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login/linkedin-login/linkedin-login.component.ts @@ -0,0 +1,26 @@ +import { LoginService } from '../../utilties/login-service'; +import { Component, OnInit } from '@angular/core' +import { Router, ActivatedRoute, Params } from '@angular/router'; + +@Component({ + selector: 'linkedin-login', + templateUrl: './linkedin-login.component.html', +}) +export class LinkedInLoginComponent implements OnInit { + + constructor( + private router: Router, + private route: ActivatedRoute, + private loginService: LoginService + ) { + + } + + ngOnInit(): void { + this.route.queryParams.subscribe((data: any) => { + if (!data["code"]) this.loginService.linkedinAuthorize() + else this.loginService.linkedInloginUser(data["code"]) + }) + } + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/login/login.component.html b/dmp-frontend/src/app/user-management/login/login.component.html new file mode 100644 index 000000000..92a68f384 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login/login.component.html @@ -0,0 +1,47 @@ +
+
+
+
+
+
+

Login

+ +
+
+

Or Be Classical

+
+
+ email + + + +
+
+ lock_outline + + + +
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/login/login.component.scss b/dmp-frontend/src/app/user-management/login/login.component.scss similarity index 100% rename from dmp-frontend/src/app/login/login.component.scss rename to dmp-frontend/src/app/user-management/login/login.component.scss diff --git a/dmp-frontend/src/app/user-management/login/login.component.ts b/dmp-frontend/src/app/user-management/login/login.component.ts new file mode 100644 index 000000000..60c969e52 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login/login.component.ts @@ -0,0 +1,59 @@ +import { LoginOptions } from '../utilties/LoginOptions'; +import { LoginService } from '../utilties/login-service'; +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit, ElementRef, AfterViewInit, VERSION, Injectable, NgZone } from '@angular/core'; +import { Router, ActivatedRoute, Params } from "@angular/router"; +import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; +import { TranslateService } from "@ngx-translate/core"; + + + +@Component({ + selector: 'login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'] +}) +export class LoginComponent implements OnInit { + + public auth2: any; + + constructor( + private loginService: LoginService + ) { + } + + + + ngOnInit() { + this.loginService.initProviders(); + } + + public facebookLogin() { + this.loginService.facebookLogin(); + } + + public linkedInLogin() { + this.loginService.linkedInInitialiseLogin(); + } + + public hasFacebookOauth(): boolean { + return this.loginService.hasProvider(LoginOptions.facebookOauth); + } + + public hasLinkedInOauth(): boolean { + return this.loginService.hasProvider(LoginOptions.linkedInOauth); + } + + public hasTwitterOauth(): boolean { + return this.loginService.hasProvider(LoginOptions.twitterOauth); + } + + public hasGoogleOauth(): boolean { + return this.loginService.hasProvider(LoginOptions.googleOauth); + } + + public hasNativeLogin(): boolean { + return this.loginService.hasProvider(LoginOptions.nativeLogin); + } + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.html b/dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.ts b/dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.ts new file mode 100644 index 000000000..49dd238f2 --- /dev/null +++ b/dmp-frontend/src/app/user-management/login/twitter-login/twitter-login.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core' +@Component({ + selector: 'twitter-login', + templateUrl: './twitter-login.component.html', + styleUrls: ['./login.component.scss'] +}) +export class TwitterLoginComponent { + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/utilties/LoginOptions.ts b/dmp-frontend/src/app/user-management/utilties/LoginOptions.ts new file mode 100644 index 000000000..51187d8ba --- /dev/null +++ b/dmp-frontend/src/app/user-management/utilties/LoginOptions.ts @@ -0,0 +1,8 @@ +export enum LoginOptions{ + linkedInOauth = 1, + facebookOauth = 2, + twitterOauth = 3, + googleOauth = 4, + nativeLogin = 5, + all = 6 +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/utilties/LoginProviderConfiguration.ts b/dmp-frontend/src/app/user-management/utilties/LoginProviderConfiguration.ts new file mode 100644 index 000000000..b57517bd7 --- /dev/null +++ b/dmp-frontend/src/app/user-management/utilties/LoginProviderConfiguration.ts @@ -0,0 +1,19 @@ +export abstract class LoginProviderConfiguration { + public clientId: string +} + +export class FacebookLoginConfiguration extends LoginProviderConfiguration { +} + +export class GoogleLoginConfiguration extends LoginProviderConfiguration { +} + +export class TwitterLoginConfiguration extends LoginProviderConfiguration { +} + +export class LinkedInConfiguration extends LoginProviderConfiguration { + public oauthUrl: string + public redirectUri: string + public accessTokenUri: string + public clientSecret: string +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/utilties/LoginServiceConfiguration.ts b/dmp-frontend/src/app/user-management/utilties/LoginServiceConfiguration.ts new file mode 100644 index 000000000..bb251a8b3 --- /dev/null +++ b/dmp-frontend/src/app/user-management/utilties/LoginServiceConfiguration.ts @@ -0,0 +1,14 @@ +import { + FacebookLoginConfiguration, + GoogleLoginConfiguration, + LinkedInConfiguration, + TwitterLoginConfiguration, +} from './LoginProviderConfiguration'; +import { LoginOptions } from './LoginOptions'; +export class LoginServiceConfiguration { + public loginProviders: LoginOptions[]; + public facebookConfiguration?: FacebookLoginConfiguration; + public googleConfiguration?: GoogleLoginConfiguration; + public twitterConfiguration?: TwitterLoginConfiguration; + public linkedInConfiguration?: LinkedInConfiguration; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/user-management/utilties/login-service.ts b/dmp-frontend/src/app/user-management/utilties/login-service.ts new file mode 100644 index 000000000..c1c218a85 --- /dev/null +++ b/dmp-frontend/src/app/user-management/utilties/login-service.ts @@ -0,0 +1,173 @@ +import { HostConfiguration } from '../../app.constants'; +import { LoginProviderConfiguration } from './LoginProviderConfiguration'; +import { AuthService } from '../../services/auth/auth.service'; +import { LoginOptions } from './LoginOptions'; +import { LoginServiceConfiguration } from './LoginServiceConfiguration'; +import { LoginProviders } from '../../models/login/LoginInfo'; +import { Optional, NgZone, Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { MatSnackBar } from '@angular/material'; +import { SnackBarNotificationComponent } from '../../shared/components/notificaiton/snack-bar-notification.component'; +import { Router, ActivatedRoute, Params } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; + +declare const gapi: any; +declare const FB: any; +declare const IN: any; + +@Injectable() +export class LoginService { + + private providers: LoginOptions[] + private auth2: any; + constructor( + private router: Router, + public authService: AuthService, + public route: ActivatedRoute, + public snackBar: MatSnackBar, + public language: TranslateService, + private zone: NgZone, + private httpClient: HttpClient + @Optional() private config: LoginServiceConfiguration, + ) { + if (config) { + this.providers = config.loginProviders; + } + else this.providers = [LoginOptions.nativeLogin]; + } + + public initProviders() { + if (this.hasProvider(LoginOptions.googleOauth)) this.initialiseGoogleOauth(); + if (this.hasProvider(LoginOptions.facebookOauth)) this.initialiseFacebookOauth(); + } + + public hasProvider(provider: LoginOptions) { + for (let i = 0; i < this.providers.length; i++) { + if (provider === this.providers[i]) return this.isProviderProperlyConfigured(provider) + } + return false; + } + + private isProviderProperlyConfigured(provider: LoginOptions) { + switch (provider) { + case LoginOptions.facebookOauth: return this.hasAllRequiredFieldsConfigured(this.config.facebookConfiguration); + case LoginOptions.googleOauth: return this.hasAllRequiredFieldsConfigured(this.config.googleConfiguration) + case LoginOptions.linkedInOauth: return this.hasAllRequiredFieldsConfigured(this.config.linkedInConfiguration); + case LoginOptions.twitterOauth: return this.hasAllRequiredFieldsConfigured(this.config.twitterConfiguration); + case LoginOptions.nativeLogin: return true; + default: throw new Error("Unsupported Provider Type") + } + } + + private hasAllRequiredFieldsConfigured(configuration: LoginProviderConfiguration) { + if (configuration != null && configuration.clientId != null) return true + return false; + } + + /* + * GOOGLE SIGN IN + */ + + private initialiseGoogleOauth(): void { + gapi.load('auth2', () => { + this.auth2 = gapi.auth2.init({ + client_id: this.config.googleConfiguration.clientId, + cookiepolicy: 'single_host_origin', + scope: 'profile email' + }); + this.attachGoogleSignin(document.getElementById('googleSignInButton')); + }); + } + + public attachGoogleSignin(element) { + if (!element) return + this.auth2.attachClickHandler(element, {}, + (googleUser) => { + var id_token = googleUser.getAuthResponse().id_token; + if (id_token) { + this.authService.login({ ticket: id_token, provider: LoginProviders.Google }).subscribe( + res => this.onLogInSuccess(res), + error => this.onLogInError(error) + ) + } + }, (error) => { + alert(JSON.stringify(error, undefined, 2)); + }); + } + + + + /* + * FACEBOOK SIGN IN + */ + + + private initialiseFacebookOauth(): void { + FB.init({ + appId: this.config.facebookConfiguration.clientId, + cookie: false, + xfbml: true, + version: 'v2.8' + }); + } + + + + + public facebookLogin() { + FB.login((response: any) => { + if (response.status === 'connected' || 'not_authorized') { + this.authService.login({ ticket: response.authResponse.accessToken, provider: LoginProviders.Facebook }).subscribe( + res => this.onLogInSuccess(res), + error => this.onLogInError(error) + ) + } + }, { scope: 'user_friends,email' }); + } + + /* + * LINKEDIN SIGN IN + */ + + public linkedinAuthorize() { + window.location.href = this.config.linkedInConfiguration.oauthUrl + "?response_type=code&client_id=" + this.config.linkedInConfiguration.clientId + "&redirect_uri=" + this.config.linkedInConfiguration.redirectUri + "&state=987654321" + } + + public linkedInInitialiseLogin() { + this.router.navigate(["/login/linkedin"]) + } + + public linkedInloginUser(code: string) { + this.authService.login({ ticket: code, provider: LoginProviders.LinkedIn }).subscribe( + res => this.onLogInSuccess(res), + error => this.onLogInError(error) + ) + } + + /* + * LOGIN HANDLERS + */ + + + public onLogInSuccess(logoutMessage: any) { + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN', language: this.language }, + duration: 3000, + extraClasses: ['snackbar-success'] + }); + this.route.queryParams.subscribe((params: Params) => { + let redirectUrl = params['returnUrl'] ? params['returnUrl'] : '/'; + this.zone.run(() => this.router.navigate([redirectUrl])); + }) + } + + public onLogInError(errorMessage: string) { + console.log(errorMessage); + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: 'GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN', language: this.language }, + duration: 3000, + extraClasses: ['snackbar-warning'] + }) + } +} \ No newline at end of file diff --git a/dmp-frontend/src/index.html b/dmp-frontend/src/index.html index eed89e6c8..eb9b05831 100644 --- a/dmp-frontend/src/index.html +++ b/dmp-frontend/src/index.html @@ -13,6 +13,9 @@ +