branch feature/1_socialauth updated (445695a5 -> aa859951)
This is an automated email from the git hooks/post-receive script. New change to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git omits 445695a5 refs #1 gestion de la suppression des credentials omits e18b813c refs #1 mise en page des comptes externes dans le profil omits 0821907e fix build omits dfd6aa67 refs #1 ajout de credentials depuis le profil omits d20e8ccc refs #1 permettre d'ajouter des comptes tiers à un compte existant omits 3b091220 refs #1 permettre l'ajout d'un mot de passe à des comptes créés à partir de service tiers omits 52a15fd5 refs #1 envoi d'un mail à la création d'un compte a partir d'un service tiers omits c04a57ed refs #1 erreur si l'utilisateur veut se connecter via un service tiers et que son email est deja utilisé par un autre compte Pollen omits 6ad03011 refs #1 gestion des tiers de connexion + style du login omits 96d56ad1 refs #1 ajout du socialmanager dans la session en attendant le retour du provider + gestion des tiers de connexion + gestion des comptes sans email omits e7253bfe refs #1 ajout de la conf des providers dans la base (plus simple à modifier) + début de l'admin omits 85efd12e refs #1 connexion avec google omits 6c2eaa6f refs #1 utilisation de la lib socialauth pour se connecter via des services tiers omits 36f48513 refs #1 ajout des credentials sur le user adds c3efed1b Add an offer page adds bea5382f Vérification des traductions, Séparation des traductions (1 fichier par langue) rechargement de type de vote à la modification de la locale (ref #123) adds 18a61096 Merge branch 'develop' of gitlab.nuiton.org:chorem/pollen into develop new 6e63e1c4 refs #1 ajout des credentials sur le user new c581c872 refs #1 utilisation de la lib socialauth pour se connecter via des services tiers new 3d3db40b refs #1 connexion avec google new 9ec9ff65 refs #1 ajout de la conf des providers dans la base (plus simple à modifier) + début de l'admin new 40bb3dc9 refs #1 ajout du socialmanager dans la session en attendant le retour du provider + gestion des tiers de connexion + gestion des comptes sans email new a63cca0d refs #1 gestion des tiers de connexion + style du login new a32cf352 refs #1 erreur si l'utilisateur veut se connecter via un service tiers et que son email est deja utilisé par un autre compte Pollen new 01639cf5 refs #1 envoi d'un mail à la création d'un compte a partir d'un service tiers new 1a386c04 refs #1 permettre l'ajout d'un mot de passe à des comptes créés à partir de service tiers new ef68f13e refs #1 permettre d'ajouter des comptes tiers à un compte existant new 0975e601 refs #1 ajout de credentials depuis le profil new 8e108414 fix build new 6e891e73 refs #1 mise en page des comptes externes dans le profil new f4cb642f refs #1 gestion de la suppression des credentials new aa859951 refs #1 séparaion des langues This update added new revisions after undoing existing revisions. That is to say, some revisions that were in the old version of the branch are not in the new version. This situation occurs when a user --force pushes a change and generates a repository containing something like this: * -- * -- B -- O -- O -- O (445695a5) \ N -- N -- N refs/heads/feature/1_socialauth (aa859951) You should already have received notification emails for all of the O revisions, and so the following emails describe only the N revisions from the common base, B. Any revisions marked "omits" are not gone; other references still refer to them. Any revisions marked "discards" are gone forever. The 15 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit aa85995120122bfe8cd0a84099f3ef6457ad882e Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 11:22:15 2017 +0200 refs #1 séparaion des langues commit f4cb642f147d1e8bb098fae4f27fc655d2d81a70 Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 11:01:10 2017 +0200 refs #1 gestion de la suppression des credentials commit 6e891e738403a7413e977ca566411d1e9b5260b9 Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 10:48:45 2017 +0200 refs #1 mise en page des comptes externes dans le profil commit 8e108414b4bfd6a54dbf38c0cb3c176dbf64f4a5 Author: Kevin Morin <morin@codelutin.com> Date: Tue Sep 5 16:48:06 2017 +0200 fix build commit 0975e601980fb223ec2691e40008a085b20df618 Author: Kevin Morin <morin@codelutin.com> Date: Tue Sep 5 16:08:48 2017 +0200 refs #1 ajout de credentials depuis le profil commit ef68f13ec531f3bbbf6ee5f376c6806cb8d17835 Author: Kevin Morin <morin@codelutin.com> Date: Mon Sep 4 15:21:58 2017 +0200 refs #1 permettre d'ajouter des comptes tiers à un compte existant commit 1a386c04b87a7c148a55aeb475f84cf2ea471ba0 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 31 16:08:45 2017 +0200 refs #1 permettre l'ajout d'un mot de passe à des comptes créés à partir de service tiers commit 01639cf58db6b57ca78fe8097bd221f226005cc0 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 31 14:57:45 2017 +0200 refs #1 envoi d'un mail à la création d'un compte a partir d'un service tiers commit a32cf352ca05b298cd6abb2d82ae8e8e958644c7 Author: Kevin Morin <morin@codelutin.com> Date: Tue Aug 29 17:57:01 2017 +0200 refs #1 erreur si l'utilisateur veut se connecter via un service tiers et que son email est deja utilisé par un autre compte Pollen commit a63cca0d24332ec0b9c70599f652e2cf8eb83832 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 25 18:04:36 2017 +0200 refs #1 gestion des tiers de connexion + style du login commit 40bb3dc9b68e3e40816a9d2181542416e9a5a9f6 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 25 18:03:46 2017 +0200 refs #1 ajout du socialmanager dans la session en attendant le retour du provider + gestion des tiers de connexion + gestion des comptes sans email commit 9ec9ff65a8a5d82fdf67bfd5742704c49f913d1d Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 24 17:35:35 2017 +0200 refs #1 ajout de la conf des providers dans la base (plus simple à modifier) + début de l'admin commit 3d3db40bcd343b818e04445e8856f2858987c9d5 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 24 11:05:45 2017 +0200 refs #1 connexion avec google commit c581c872057641079a7d14115c6036e03a54d1f8 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 11 17:52:32 2017 +0200 refs #1 utilisation de la lib socialauth pour se connecter via des services tiers commit 6e63e1c4ae64ec40ee24ff739576f29f7fddbfbc Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 11 17:52:10 2017 +0200 refs #1 ajout des credentials sur le user Summary of changes: .../rest/api/PollenRestApiRequestFilter.java | 24 +- pollen-ui-riot-js/src/main/web/homeCL/offers.html | 74 ++ pollen-ui-riot-js/src/main/web/homeCL/style.css | 14 +- pollen-ui-riot-js/src/main/web/i18n.json | 1099 -------------------- pollen-ui-riot-js/src/main/web/i18n/en.json | 554 ++++++++++ pollen-ui-riot-js/src/main/web/i18n/fr.json | 554 ++++++++++ pollen-ui-riot-js/src/main/web/js/FetchService.js | 5 +- pollen-ui-riot-js/src/main/web/js/Poll.js | 10 + pollen-ui-riot-js/src/main/web/js/PollForm.js | 12 +- pollen-ui-riot-js/src/main/web/js/Session.js | 5 +- .../src/main/web/tag/poll/Poll.tag.html | 8 +- .../src/main/web/tag/poll/Settings.tag.html | 8 + 12 files changed, 1249 insertions(+), 1118 deletions(-) create mode 100644 pollen-ui-riot-js/src/main/web/homeCL/offers.html delete mode 100644 pollen-ui-riot-js/src/main/web/i18n.json create mode 100644 pollen-ui-riot-js/src/main/web/i18n/en.json create mode 100644 pollen-ui-riot-js/src/main/web/i18n/fr.json -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 6e63e1c4ae64ec40ee24ff739576f29f7fddbfbc Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 11 17:52:10 2017 +0200 refs #1 ajout des credentials sur le user --- .../persistence/entity/PollenUserTopiaDao.java | 22 +++++++++++++++++++-- .../db/migration/h2/V3_0_0_8__add_credentials.sql | 13 ++++++++++++ .../postgresql/V3_0_0_8__add_credentials.sql | 12 +++++++++++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 26949 -> 27595 bytes 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserTopiaDao.java index a71e1cc1..06f84e33 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserTopiaDao.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserTopiaDao.java @@ -21,14 +21,16 @@ package org.chorem.pollen.persistence.entity; * #L% */ -import com.google.common.collect.Maps; import org.apache.commons.lang3.StringUtils; import org.chorem.pollen.persistence.DaoUtils; import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; /** * @author Tony Chemit - dev@tchemit.fr @@ -42,7 +44,7 @@ public class PollenUserTopiaDao extends AbstractPollenUserTopiaDao<PollenUser> { public PaginationResult<PollenUser> findAll(PaginationParameter page, String search) { - Map<String, Object> parameters = Maps.newHashMap(); + Map<String, Object> parameters = new HashMap<>(); String hql = "SELECT user FROM " + PollenUser.class.getName() + " as user"; if (StringUtils.isNotBlank(search)) { @@ -68,4 +70,20 @@ public class PollenUserTopiaDao extends AbstractPollenUserTopiaDao<PollenUser> { super.delete(entity); } + + public Optional<PollenUser> tryFindUserWithCredential(String providerId, String userId) { + Objects.requireNonNull(providerId); + Objects.requireNonNull(userId); + + Map<String, Object> parameters = new HashMap<>(); + + String hql = "SELECT user FROM " + PollenUser.class.getName() + " as user " + + "INNER JOIN user." + PollenUser.PROPERTY_USER_CREDENTIAL + " as credentials " + + "WHERE credentials." + UserCredential.PROPERTY_PROVIDER + " = :providerId " + + "AND credentials." + UserCredential.PROPERTY_USER_ID + " = :userId"; + parameters.put("providerId", providerId); + parameters.put("userId", userId); + + return Optional.ofNullable(findUniqueOrNull(hql, parameters)); + } } diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql new file mode 100644 index 00000000..1825b8ae --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql @@ -0,0 +1,13 @@ +-- credentials + +CREATE TABLE USERCREDENTIAL ( + TOPIAID VARCHAR(255) NOT NULL PRIMARY KEY, + TOPIAVERSION BIGINT NOT NULL, + TOPIACREATEDATE TIMESTAMP, + PROVIDER VARCHAR(255), + USERID VARCHAR(255), + EMAIL VARCHAR(255), + POLLENUSER VARCHAR(255), + FOREIGN KEY (POLLENUSER) references POLLENUSER(TOPIAID) +); + diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql new file mode 100644 index 00000000..2280308e --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql @@ -0,0 +1,12 @@ +-- credentials + +CREATE TABLE USERCREDENTIAL ( + TOPIAID VARCHAR(255) NOT NULL PRIMARY KEY, + TOPIAVERSION BIGINT NOT NULL, + TOPIACREATEDATE TIMESTAMP, + PROVIDER VARCHAR(255), + USERID VARCHAR(255), + EMAIL VARCHAR(255), + POLLENUSER VARCHAR(255), + FOREIGN KEY (POLLENUSER) references POLLENUSER(TOPIAID) +); diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index 49cb0e8f..16d95ab4 100644 --- a/pollen-persistence/src/main/xmi/pollen.properties +++ b/pollen-persistence/src/main/xmi/pollen.properties @@ -18,7 +18,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ###m -model.tagvalue.version=3.0.0.7 +model.tagvalue.version=3.0.0.8 #model.tagValue.notGenerateToString=true #model.tagValue.constantPrefix=PROPERTY_ #model.tagValue.useEnumerationName=true diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index f967fa89..72886764 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit c581c872057641079a7d14115c6036e03a54d1f8 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 11 17:52:32 2017 +0200 refs #1 utilisation de la lib socialauth pour se connecter via des services tiers --- .../rest/api/PollenRestApiRequestFilter.java | 2 + .../org/chorem/pollen/rest/api/v1/AuthApi.java | 118 ++++++++++++++------- pollen-services/pom.xml | 5 + .../services/service/PollenServiceSupport.java | 5 + .../pollen/services/service/SocialAuthService.java | 101 ++++++++++++++++++ .../services/service/security/SecurityService.java | 6 +- .../src/main/resources/oauth_consumer.properties | 87 +++++++++++++++ pollen-ui-riot-js/package.json | 2 +- pollen-ui-riot-js/src/main/web/js/AuthService.js | 7 ++ pollen-ui-riot-js/src/main/web/js/Session.js | 49 +++++---- pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 14 ++- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 16 ++- pollen-ui-riot-js/webpack.config.js | 2 +- pom.xml | 6 ++ 14 files changed, 356 insertions(+), 64 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java index 3c369f7f..cfb03701 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java @@ -44,6 +44,7 @@ import org.chorem.pollen.services.service.PollenResourceService; import org.chorem.pollen.services.service.PollenUIUrlRenderService; import org.chorem.pollen.services.service.PollenUserService; import org.chorem.pollen.services.service.ReportService; +import org.chorem.pollen.services.service.SocialAuthService; import org.chorem.pollen.services.service.VoteCountingService; import org.chorem.pollen.services.service.VoteCountingTypeService; import org.chorem.pollen.services.service.VoteService; @@ -179,6 +180,7 @@ public class PollenRestApiRequestFilter implements ContainerRequestFilter, Conta ResteasyProviderFactory.pushContext(VoteService.class, serviceContext.newService(VoteService.class)); ResteasyProviderFactory.pushContext(PollenUserService.class, serviceContext.newService(PollenUserService.class)); ResteasyProviderFactory.pushContext(FeedbackService.class, serviceContext.newService(FeedbackService.class)); + ResteasyProviderFactory.pushContext(SocialAuthService.class, serviceContext.newService(SocialAuthService.class)); } private PollenUIContext extractUIContext(ContainerRequestContext context) { diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index ffcc4507..55541664 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -21,6 +21,7 @@ package org.chorem.pollen.rest.api.v1; * #L% */ +import com.google.gson.Gson; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,6 +31,7 @@ import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.services.PollenServiceContext; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.service.PollenUserService; +import org.chorem.pollen.services.service.SocialAuthService; import org.chorem.pollen.services.service.security.MissingAuthenticationException; import org.chorem.pollen.services.service.security.PollenAuthenticationException; import org.chorem.pollen.services.service.security.PollenCypherTechnicalException; @@ -52,6 +54,8 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.Map; /** * TODO @@ -118,49 +122,58 @@ public class AuthApi { } PollenEntityRef<PollenUser> userPollenEntityRef = securityService.login(login, password, false); - userPollenEntityRef.encode(serviceContext.getTopiaApplicationContext().getTopiaIdFactory()); - - // Inject the session token in security context - SessionToken sessionToken = securityService.getSessionTokenByToken(userPollenEntityRef.getPermission()); - - securityContext.setSessionToken(sessionToken); - - // add auth cookies - - String value = securityService.encrypt( - sessionToken.getPollenUser().getTopiaId(), - sessionToken.getPollenToken().getToken() - ); - - NewCookie authCookie = new NewCookie( - COOKIE_POLLEN_AUTH, - value, - "/", - null, - null, - COOKIE_MAX_AGE, - false); - - NewCookie connectedCookie = new NewCookie( - COOKIE_POLLEN_CONNECTED, - "true", - "/", - null, - null, - COOKIE_MAX_AGE, - false); - - if (log.isDebugEnabled()) { - log.debug("Add auth cookie:: " + authCookie.getValue()); - } - - return Response.ok(userPollenEntityRef).cookie(authCookie, connectedCookie).build(); + return getLoginResponseFromPollenUser(serviceContext, securityService, securityContext, userPollenEntityRef); } throw new MissingAuthenticationException(); } + protected Response getLoginResponseFromPollenUser(PollenServiceContext serviceContext, + SecurityService securityService, + PollenSecurityContext securityContext, + PollenEntityRef<PollenUser> userPollenEntityRef) + throws PollenInvalidSessionTokenException, PollenCypherTechnicalException { + + userPollenEntityRef.encode(serviceContext.getTopiaApplicationContext().getTopiaIdFactory()); + + // Inject the session token in security context + SessionToken sessionToken = securityService.getSessionTokenByToken(userPollenEntityRef.getPermission()); + + securityContext.setSessionToken(sessionToken); + + // add auth cookies + + String value = securityService.encrypt( + sessionToken.getPollenUser().getTopiaId(), + sessionToken.getPollenToken().getToken() + ); + + NewCookie authCookie = new NewCookie( + COOKIE_POLLEN_AUTH, + value, + "/", + null, + null, + COOKIE_MAX_AGE, + false); + + NewCookie connectedCookie = new NewCookie( + COOKIE_POLLEN_CONNECTED, + "true", + "/", + null, + null, + COOKIE_MAX_AGE, + false); + + if (log.isDebugEnabled()) { + log.debug("Add auth cookie:: " + authCookie.getValue()); + } + + return Response.ok(userPollenEntityRef).cookie(authCookie, connectedCookie).build(); + } + @Path("/login2") @POST @PUT public PollenEntityRef<PollenUser> login2(@Context SecurityService securityService, @@ -172,8 +185,39 @@ public class AuthApi { PollenUserBannedException { return securityService.login(login, password, rememberMe); + } + @Path("/login/{providerId}") + @GET + public Response loginProvider(@Context SocialAuthService socialAuthService, + @PathParam("providerId") String providerId, + @QueryParam("providerRedirection") String providerRedirection) + throws Exception { + + String providerLoginUrl = socialAuthService.getProviderAuthenticationUrl(providerId, providerRedirection); + return Response.seeOther(URI.create(providerLoginUrl)).build(); } + + @Path("/login/{providerId}") + @POST + public Response loginProvider(@Context SocialAuthService socialAuthService, + @Context PollenServiceContext serviceContext, + @Context SecurityService securityService, + @Context PollenSecurityContext securityContext, + @PathParam("providerId") String providerId, + String providerRedirection, + @HeaderParam("authorization") String authorization) + throws Exception { + + Gson gson = new Gson(); + Map<String, String> paramsMap = gson.fromJson(authorization, Map.class); + PollenEntityRef<PollenUser> userPollenEntityRef = socialAuthService.login(providerId, providerRedirection, paramsMap); + + + + return getLoginResponseFromPollenUser(serviceContext, securityService, securityContext, userPollenEntityRef); + } + @Path("/logout") @GET public boolean logout(@Context SecurityService securityService, diff --git a/pollen-services/pom.xml b/pollen-services/pom.xml index a17b864f..43ed09cb 100644 --- a/pollen-services/pom.xml +++ b/pollen-services/pom.xml @@ -214,6 +214,11 @@ <artifactId>jboss-jaxrs-api_2.0_spec</artifactId> </dependency> + <dependency> + <groupId>org.brickred</groupId> + <artifactId>socialauth</artifactId> + </dependency> + </dependencies> <build> diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java index 88b0a6ca..c26c5f50 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java @@ -41,6 +41,7 @@ import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.PollenUserTopiaDao; import org.chorem.pollen.persistence.entity.ReportTopiaDao; import org.chorem.pollen.persistence.entity.SessionTokenTopiaDao; +import org.chorem.pollen.persistence.entity.UserCredentialTopiaDao; import org.chorem.pollen.persistence.entity.VoteToChoiceTopiaDao; import org.chorem.pollen.persistence.entity.VoteTopiaDao; import org.chorem.pollen.persistence.entity.VoterListMemberTopiaDao; @@ -213,6 +214,10 @@ public abstract class PollenServiceSupport implements PollenService { return getPersistenceContext().getPollenUserDao(); } + protected UserCredentialTopiaDao getUserCredentialDao() { + return getPersistenceContext().getUserCredentialDao(); + } + protected ReportTopiaDao getReportTopiaDao() { return getPersistenceContext().getReportDao(); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java new file mode 100644 index 00000000..47cb08dd --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -0,0 +1,101 @@ +package org.chorem.pollen.services.service; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.brickred.socialauth.AuthProvider; +import org.brickred.socialauth.Profile; +import org.brickred.socialauth.SocialAuthConfig; +import org.brickred.socialauth.SocialAuthManager; +import org.chorem.pollen.persistence.entity.PollenUser; +import org.chorem.pollen.persistence.entity.PollenUserImpl; +import org.chorem.pollen.persistence.entity.PollenUserTopiaDao; +import org.chorem.pollen.persistence.entity.UserCredential; +import org.chorem.pollen.persistence.entity.UserCredentialImpl; +import org.chorem.pollen.services.bean.PollenEntityRef; + +import java.util.Map; +import java.util.Optional; + +/** + * @author Kevin Morin (Code Lutin) + */ +public class SocialAuthService extends PollenServiceSupport { + + /** Logger. */ + private static final Log log = LogFactory.getLog(SocialAuthService.class); + + public String getProviderAuthenticationUrl(String providerId, String redirection) throws Exception { + SocialAuthManager manager = getSocialAuthManager(); + + // get Provider URL to which you should redirect for authentication. + // id can have values "facebook", "twitter", "yahoo" etc. or the OpenID URL + return manager.getAuthenticationUrl(providerId, redirection); + } + + public PollenEntityRef<PollenUser> login(String providerId, + String redirection, + Map<String, String> paramsMap) throws Exception { + SocialAuthManager manager = getSocialAuthManager(); + manager.getAuthenticationUrl(providerId, redirection); + + AuthProvider provider = manager.connect(paramsMap); + + // get profile + Profile p = provider.getUserProfile(); + + PollenUser pollenUser; + PollenUserTopiaDao userDao = getPollenUserDao(); + Optional<PollenUser> pollenUserForCredential = userDao.tryFindUserWithCredential(p.getProviderId(), p.getValidatedId()); + + String name = p.getDisplayName(); + if (name == null) { + name = p.getFirstName() + " " + p.getLastName(); + } + + if (pollenUserForCredential.isPresent()) { + if (log.isInfoEnabled()) { + log.info("credentials found : " + name); + } + pollenUser = pollenUserForCredential.get(); + + } else { + if (log.isInfoEnabled()) { + log.info("create new user : " + name); + } + + UserCredential credential = new UserCredentialImpl(); + credential.setProvider(p.getProviderId()); + credential.setUserId(p.getValidatedId()); + credential.setEmail(p.getEmail()); + credential = getUserCredentialDao().create(credential); + + pollenUser = new PollenUserImpl(); + pollenUser.setName(name); + pollenUser.setEmail(p.getEmail()); + pollenUser.setLanguage(p.getLanguage()); + pollenUser.setAdministrator(false); + pollenUser.setBanned(false); + pollenUser.addUserCredential(credential); + pollenUser = userDao.create(pollenUser); + + commit(); + } + + return getSecurityService().getSessionTokenForUser(pollenUser); + } + + protected SocialAuthManager getSocialAuthManager() throws Exception { + //Create an instance of SocialAuthConfgi object + SocialAuthConfig config = SocialAuthConfig.getDefault(); + + //load configuration. By default load the configuration from oauth_consumer.properties. + //You can also pass input stream, properties object or properties file name. + config.load(); + + //Create an instance of SocialAuthManager and set config + SocialAuthManager manager = new SocialAuthManager(); + manager.setSocialAuthConfig(config); + + return manager; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index 6eaebb94..1ccb28bb 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -138,6 +138,11 @@ public class SecurityService extends PollenServiceSupport { } PollenUser user = getPollenUserDao().forEmailEquals(login).findUnique(); + return getSessionTokenForUser(user); + + } + + public PollenEntityRef<PollenUser> getSessionTokenForUser(PollenUser user) throws PollenEmailNotValidatedException, PollenUserBannedException { if (!user.isEmailValidated()) { throw new PollenEmailNotValidatedException(); } @@ -163,7 +168,6 @@ public class SecurityService extends PollenServiceSupport { commit(); return PollenEntityRef.of(sessionToken); - } public void logout() { diff --git a/pollen-services/src/main/resources/oauth_consumer.properties b/pollen-services/src/main/resources/oauth_consumer.properties new file mode 100644 index 00000000..6f015cc3 --- /dev/null +++ b/pollen-services/src/main/resources/oauth_consumer.properties @@ -0,0 +1,87 @@ +#google +www.google.com.consumer_key = opensource.brickred.com +www.google.com.consumer_secret = YC06FqhmCLWvtBg/O4W/aJfj + +#you can set custom permission by using custom_permissions with provider prefix. +#www.google.com.custom_permissions = http://www.google.com/m8/feeds/,http://picasaweb.google.com/data/ + +#you can set OAuth endpoint (RequestToken URL, Authorization URL and AccessToken URL) if required or need +#to pass extra parameter +#www.google.com.request_token_url +#www.google.com.authentication_url +#www.google.com.access_token_url + +#New registration on google will always provide OAuth2 keys which is supported by GooglePlus provider +#google plus +googleapis.com.consumer_key = XXXXXXX +googleapis.com.consumer_secret = XXXXXXXX + + +#yahoo +api.login.yahoo.com.consumer_key = dj0yJmk9VTdaSUVTU3RrWlRzJmQ9WVdrOWNtSjZNMFpITm1VbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD1iMA-- +api.login.yahoo.com.consumer_secret = 1db3d0b897dac60e151aa9e2499fcb2a6b474546 + +#twitter +twitter.com.consumer_key = E3hm7J9IQbWLijpiQG7W8Q +twitter.com.consumer_secret = SGKNuXyybt0iDdgsuzVbFHOaemV7V6pr0wKwbaT2MH0 + +#facebook +graph.facebook.com.consumer_key = 152190004803645 +graph.facebook.com.consumer_secret = 64c94bd02180b0ade85889b44b2ba7c4 +#you can set custom permission by using custom_permissions with provider prefix. +#graph.facebook.com.custom_permissions = publish_stream,email,user_birthday,user_location,offline_access + +#hotmail +consent.live.com.consumer_key = 000000004403D60E +consent.live.com.consumer_secret = cYqlii67pTvgPD4pdB7NUVC7L4MIHCcs + +#Same keys will work for Linkedin OAuth2 provider +#LinkedIn +api.linkedin.com.consumer_key = 9-mmqg28fpMocVuAg87exH-RXKs70yms52GSFIqkZN25S3m96kdPGBbuSxdSBIyL +api.linkedin.com.consumer_secret = e6NBqhDYE1fX17RwYGW5vMp25Cvh7Sbw9t-zMYTIW_T5LytY5OwJ12snh_YftgE4 + +#MySpace +api.myspace.com.consumer_key = 29db395f5ee8426bb90b1db65c91c956 +api.myspace.com.consumer_secret = 0fdccc829c474e42867e16b68cda37a4c4b7b08eda574fe6a959943e3e9be709 + +#FourSquare +foursquare.com.consumer_key = JQKEM1PHWFW4YF2YPEQBRRESXE3SBGNCYJWWDTZKF3IZNJ3V +foursquare.com.consumer_secret = 4IILLDFDVPP2LC554S4KXKETQNTDKPDSEVCKVHA2QEHKYBEQ + +#Yammer +www.yammer.com.consumer_key=5zyIkp12TrkulSRbSegQ +www.yammer.com.consumer_secret=zUcCB9kqWhI1IiTAJbl9QdG2AWcUJMDWp3Qyv5VJJw + +#Please use your own keys for mendeley +#Mendeley +#api.mendeley.com.consumer_key= +#api.mendeley.com.consumer_secret= + +#Salesforce +login.salesforce.com.consumer_key = 3MVG9Y6d_Btp4xp4yFMR0tPSndkAVu4OBejuYcL2iGFC68tA49PknWKX20XdPl5s1iwWldyuAbSINWHbB2Jcu +login.salesforce.com.consumer_secret = 1993703471433041656 + +#Instagram +api.instagram.com.consumer_key=f1e23002a9da49f696d439368624c9fc +api.instagram.com.consumer_secret=f274614621f64d498cb3458b3736827a + +#Flickr +www.flickr.com.consumer_key=942a1a394b866a30dc9b4ad8db5cb8f8 +www.flickr.com.consumer_secret=f90c5bee8a8de964 + +#GITHub +api.github.com.consumer_key=4ffc69764a59dd3ce347 +api.github.com.consumer_secret=dc62937c1d7bb9ce30cb654a26d4a575858f5e1f + +#Implementations +#you can provide your custom provider here e.g 'myprovider' is your provider id +#and 'org.brickred.socialauth.provider.GoogleImpl' is your provider implementation. +#provider id should be prefixed here with 'socialauth.' +#socialauth.myprovider = org.brickred.socialauth.provider.GoogleImpl + +#If you want to set proxy for internal http calls, so you can set in following way +#proxy.host=YOUR HOST NAME(e.g. 127.0.0.1) +#proxy.port=PORT(e.g.8888) + +#If you want to set connection timeout, you can set in following way +#http.connectionTimeOut = TIMEOUT(e.g. 5000) \ No newline at end of file diff --git a/pollen-ui-riot-js/package.json b/pollen-ui-riot-js/package.json index 68ec61e0..d542116f 100644 --- a/pollen-ui-riot-js/package.json +++ b/pollen-ui-riot-js/package.json @@ -24,7 +24,7 @@ } ], "scripts": { - "start": "webpack-dev-server --hot --inline --host 0.0.0.0 --public localhost:8080", + "start": "webpack-dev-server --hot --inline --host 0.0.0.0 --public opensource.brickred.com:8080", "package": "webpack --bail" }, "devDependencies": { diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 54f272c4..23b87d3a 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -68,6 +68,13 @@ class AuthService extends FetchService { return this.post("/v1/resendValidation", email); } + signInProvider(provider, query, providerRedirection) { + return this.fetch( + "/v1/login/" + provider, + "POST", + {Authorization: JSON.stringify(query)}, + providerRedirection); + } } module.exports = singleton(AuthService); diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 27553a40..1112204f 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -133,26 +133,33 @@ class Session { } signIn(login, password) { - return authService.signIn(login, password).then(auth => { - logger.info("SignIn::"); - logger.info(auth); - return authService.userPromise(auth).then((user) => { - if (!user) { - logger.info("SignIn error"); - var oldUser = this.user; - this.user = null; - bus.trigger("user", this.user, oldUser); - return Promise.reject(); - } - logger.info("SignIn user::"); - logger.info(user); - pageTracker.trackLogin(); - var oldUser = this.user; - this.user = user; - bus.trigger("user", this.user, oldUser); + return authService.signIn(login, password).then(auth => this.updateConnection(auth, this)); + } - return this.user; - }); + signInProvider(provider, query) { + return authService.signInProvider(provider, query, this.getProviderRedirectionUrl(query.redirect)) + .then(auth => this.updateConnection(auth, this)); + } + + updateConnection(auth, session) { + logger.info("SignIn::"); + logger.info(auth); + return authService.userPromise(auth).then((user) => { + if (!user) { + logger.info("SignIn error"); + var oldUser = session.user; + session.user = null; + bus.trigger("user", session.user, oldUser); + return Promise.reject(); + } + logger.info("SignIn user::"); + logger.info(user); + pageTracker.trackLogin(); + var oldUser = session.user; + session.user = user; + bus.trigger("user", session.user, oldUser); + + return session.user; }); } @@ -165,6 +172,10 @@ class Session { }); } + getProviderRedirectionUrl(redirect) { + return this.pollenUIContext.uiEndPoint + "/?redirect=" + redirect; + } + } module.exports = singleton(Session); diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 8825148a..1ac4f6cb 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -218,8 +218,18 @@ require("./popup/InformationPopup.tag.html"); }); route(() => { - this.bus.trigger("pageChanged", "home"); - riot.mount(this.refs.content, "home"); + var q = route.query(); + console.log(q); + console.log(q.redirect); + if (q.redirect != null) { + session.signInProvider("facebook", q).then(() => { + location.href = session.pollenUIContext.uiEndPoint + "/" + unescape(decodeURIComponent(q.redirect)); + }); + + } else { + this.bus.trigger("pageChanged", "home"); + riot.mount(this.refs.content, "home"); + } }); window.onkeydown = e => { diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index e6fb6efb..739345e8 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -57,6 +57,10 @@ require("./components/HumanInput.tag.html"); </div> <a onclick="{newPassword}">{__.lostpassword}</a> </form> + <p>Ou connectez vous avec votre compte + <a onclick="{signinWithProvider('facebook')}"><i class="fa fa-facebook-official"></i></a> + <a onclick="{signinWithProvider('linkedin')}"><i class="fa fa-linkedin-square"></i></a> + </p> </div> <SignUp/> @@ -68,10 +72,10 @@ require("./components/HumanInput.tag.html"); </div> <script type="es6"> - let session = require("../js/Session"); + this.session = require("../js/Session"); let route = require("riot-route"); - this.installBundle(session, "signin"); + this.installBundle(this.session, "signin"); this.message = ""; this.openSignIn = false; @@ -95,7 +99,7 @@ require("./components/HumanInput.tag.html"); this.message = ""; - session.signIn(this.refs.login.value, this.refs.password.value) + this.session.signIn(this.refs.login.value, this.refs.password.value) .then(() => { this.openSignIn = false; this.update(); @@ -106,6 +110,12 @@ require("./components/HumanInput.tag.html"); }); }); }; + + this.signinWithProvider = (provider) => (e) => { + let redirect = location.hash || "#"; + location.href = this.session.configuration.endPoint + "/v1/login/" + provider + + "?providerRedirection=" + this.session.getProviderRedirectionUrl(escape(encodeURIComponent(redirect))); + }; </script> <style> diff --git a/pollen-ui-riot-js/webpack.config.js b/pollen-ui-riot-js/webpack.config.js index 0a233ab7..11ae81fb 100644 --- a/pollen-ui-riot-js/webpack.config.js +++ b/pollen-ui-riot-js/webpack.config.js @@ -34,7 +34,7 @@ module.exports = { new CopyWebpackPlugin([ {from: "src/main/web/conf.js", transform: function(content) { - return content.toString().replace("POLLEN_API_URL", JSON.stringify(process.env.POLLEN_SERVER_CONTEXT || "http://localhost:8888/pollen-rest-api")); + return content.toString().replace("POLLEN_API_URL", JSON.stringify(process.env.POLLEN_SERVER_CONTEXT || "http://opensource.brickred.com:8888/pollen-rest-api")); }}, {from: "src/main/web/index.html"}, {from: "src/main/web/home", to: "home"}, diff --git a/pom.xml b/pom.xml index bcc9711a..d92084cf 100644 --- a/pom.xml +++ b/pom.xml @@ -627,6 +627,12 @@ </exclusions> </dependency> + <dependency> + <groupId>org.brickred</groupId> + <artifactId>socialauth</artifactId> + <version>4.14</version> + </dependency> + <!--dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 3d3db40bcd343b818e04445e8856f2858987c9d5 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 24 11:05:45 2017 +0200 refs #1 connexion avec google --- .../src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java | 3 --- .../org/chorem/pollen/services/service/SocialAuthService.java | 2 ++ pollen-ui-riot-js/src/main/web/js/AuthService.js | 6 ++++-- pollen-ui-riot-js/src/main/web/js/Session.js | 8 ++++---- pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 10 +++++----- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 9 +++++---- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index 55541664..7a7b74bb 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -212,9 +212,6 @@ public class AuthApi { Gson gson = new Gson(); Map<String, String> paramsMap = gson.fromJson(authorization, Map.class); PollenEntityRef<PollenUser> userPollenEntityRef = socialAuthService.login(providerId, providerRedirection, paramsMap); - - - return getLoginResponseFromPollenUser(serviceContext, securityService, securityContext, userPollenEntityRef); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 47cb08dd..6866b3b5 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -6,6 +6,7 @@ import org.brickred.socialauth.AuthProvider; import org.brickred.socialauth.Profile; import org.brickred.socialauth.SocialAuthConfig; import org.brickred.socialauth.SocialAuthManager; +import org.brickred.socialauth.util.Constants; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.PollenUserImpl; import org.chorem.pollen.persistence.entity.PollenUserTopiaDao; @@ -38,6 +39,7 @@ public class SocialAuthService extends PollenServiceSupport { SocialAuthManager manager = getSocialAuthManager(); manager.getAuthenticationUrl(providerId, redirection); + paramsMap.remove(Constants.STATE); AuthProvider provider = manager.connect(paramsMap); // get profile diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 23b87d3a..42052f20 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -68,9 +68,11 @@ class AuthService extends FetchService { return this.post("/v1/resendValidation", email); } - signInProvider(provider, query, providerRedirection) { + signInProvider(query, providerRedirection) { + console.log(query) + console.log(providerRedirection) return this.fetch( - "/v1/login/" + provider, + "/v1/login/" + query.loginProvider, "POST", {Authorization: JSON.stringify(query)}, providerRedirection); diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 1112204f..f5f84fdf 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -136,8 +136,8 @@ class Session { return authService.signIn(login, password).then(auth => this.updateConnection(auth, this)); } - signInProvider(provider, query) { - return authService.signInProvider(provider, query, this.getProviderRedirectionUrl(query.redirect)) + signInProvider(query) { + return authService.signInProvider(query, this.getProviderRedirectionUrl(query.loginProvider)) .then(auth => this.updateConnection(auth, this)); } @@ -172,8 +172,8 @@ class Session { }); } - getProviderRedirectionUrl(redirect) { - return this.pollenUIContext.uiEndPoint + "/?redirect=" + redirect; + getProviderRedirectionUrl(provider) { + return this.pollenUIContext.uiEndPoint + "/?loginProvider=" + provider; } } diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 1ac4f6cb..36ca5983 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -219,11 +219,11 @@ require("./popup/InformationPopup.tag.html"); route(() => { var q = route.query(); - console.log(q); - console.log(q.redirect); - if (q.redirect != null) { - session.signInProvider("facebook", q).then(() => { - location.href = session.pollenUIContext.uiEndPoint + "/" + unescape(decodeURIComponent(q.redirect)); + if (q.loginProvider != null) { + session.signInProvider(q).then(() => { + let currentPage = localStorage.getItem("currentPage"); + localStorage.removeItem("currentPage"); + location.href = session.pollenUIContext.uiEndPoint + "/" + currentPage; }); } else { diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index 739345e8..2ce478c5 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -57,9 +57,9 @@ require("./components/HumanInput.tag.html"); </div> <a onclick="{newPassword}">{__.lostpassword}</a> </form> - <p>Ou connectez vous avec votre compte + <p>Ou connectez vous avec votre compte : <a onclick="{signinWithProvider('facebook')}"><i class="fa fa-facebook-official"></i></a> - <a onclick="{signinWithProvider('linkedin')}"><i class="fa fa-linkedin-square"></i></a> + <a onclick="{signinWithProvider('googleplus')}"><i class="fa fa-google"></i></a> </p> </div> @@ -112,9 +112,10 @@ require("./components/HumanInput.tag.html"); }; this.signinWithProvider = (provider) => (e) => { - let redirect = location.hash || "#"; + let currentPage = location.hash || "#"; + localStorage.setItem("currentPage", currentPage); location.href = this.session.configuration.endPoint + "/v1/login/" + provider - + "?providerRedirection=" + this.session.getProviderRedirectionUrl(escape(encodeURIComponent(redirect))); + + "?providerRedirection=" + encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); }; </script> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 9ec9ff65a8a5d82fdf67bfd5742704c49f913d1d Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 24 17:35:35 2017 +0200 refs #1 ajout de la conf des providers dans la base (plus simple à modifier) + début de l'admin --- .../migration/h2/V3_0_0_9__add_loginproviders.sql | 13 +++ .../postgresql/V3_0_0_9__add_loginproviders.sql | 12 +++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 27595 -> 28069 bytes .../org/chorem/pollen/rest/api/v1/AuthApi.java | 28 +++++++ .../pollen/services/bean/LoginProviderBean.java | 82 ++++++++++++++++++ .../services/service/PollenServiceSupport.java | 5 ++ .../pollen/services/service/SocialAuthService.java | 63 ++++++++++++++ .../src/main/resources/oauth_consumer.properties | 56 ++++++------- pollen-ui-riot-js/src/main/web/js/AuthService.js | 15 +++- pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 8 +- .../src/main/web/tag/PollenHeader.tag.html | 1 + pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 12 ++- .../src/main/web/tag/admin/LoginProviders.tag.html | 92 +++++++++++++++++++++ .../src/main/web/tag/{ => admin}/UserCard.tag.html | 6 +- .../web/tag/{ => admin}/UserEditModal.tag.html | 8 +- .../src/main/web/tag/{ => admin}/Users.tag.html | 10 +-- 17 files changed, 367 insertions(+), 46 deletions(-) diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_9__add_loginproviders.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_9__add_loginproviders.sql new file mode 100644 index 00000000..1a3adce2 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_9__add_loginproviders.sql @@ -0,0 +1,13 @@ +-- LOGINPROVIDER + +CREATE TABLE LOGINPROVIDER ( + TOPIAID VARCHAR(255) NOT NULL PRIMARY KEY, + TOPIAVERSION BIGINT NOT NULL, + TOPIACREATEDATE TIMESTAMP, + NAME VARCHAR(255), + KEY VARCHAR(255), + SECRET VARCHAR(255), + PERMISSIONS VARCHAR(255), + ACTIVE BOOLEAN +); + diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_9__add_loginproviders.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_9__add_loginproviders.sql new file mode 100644 index 00000000..75a094ea --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_9__add_loginproviders.sql @@ -0,0 +1,12 @@ +-- LOGINPROVIDER + +CREATE TABLE LOGINPROVIDER ( + TOPIAID VARCHAR(255) NOT NULL PRIMARY KEY, + TOPIAVERSION BIGINT NOT NULL, + TOPIACREATEDATE TIMESTAMP, + NAME VARCHAR(255), + KEY VARCHAR(255), + SECRET VARCHAR(255), + PERMISSIONS VARCHAR(255), + ACTIVE BOOLEAN +); diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index 16d95ab4..d172fe4c 100644 --- a/pollen-persistence/src/main/xmi/pollen.properties +++ b/pollen-persistence/src/main/xmi/pollen.properties @@ -18,7 +18,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ###m -model.tagvalue.version=3.0.0.8 +model.tagvalue.version=3.0.0.9 #model.tagValue.notGenerateToString=true #model.tagValue.constantPrefix=PROPERTY_ #model.tagValue.useEnumerationName=true diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index 72886764..0f29e782 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index 7a7b74bb..748dc894 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -29,6 +29,7 @@ import org.apache.shiro.codec.Base64; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.services.PollenServiceContext; +import org.chorem.pollen.services.bean.LoginProviderBean; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.service.PollenUserService; import org.chorem.pollen.services.service.SocialAuthService; @@ -55,6 +56,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import java.net.URI; +import java.util.List; import java.util.Map; /** @@ -248,4 +250,30 @@ public class AuthApi { } + @Path("/loginproviders") + @GET + public List<LoginProviderBean> getAllLoginProviders(@Context SocialAuthService socialAuthService) { + return socialAuthService.getAllLoginProviders(); + } + + @Path("/loginproviders") + @POST + public LoginProviderBean addLoginProvider(@Context SocialAuthService socialAuthService, + LoginProviderBean loginProvider) { + return socialAuthService.saveLoginProvider(loginProvider, false); + } + + @Path("/loginproviders/{providerId}") + @POST @PUT + public LoginProviderBean saveLoginProvider(@Context SocialAuthService socialAuthService, + LoginProviderBean loginProvider) { + return socialAuthService.saveLoginProvider(loginProvider, true); + } + + @Path("/loginproviders/active") + @GET + public List<String> getAvailableLoginProviders(@Context SocialAuthService socialAuthService) { + return socialAuthService.getAvailableLoginProviders(); + } + } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/LoginProviderBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/LoginProviderBean.java new file mode 100644 index 00000000..e24d2d19 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/LoginProviderBean.java @@ -0,0 +1,82 @@ +package org.chorem.pollen.services.bean; + +import org.chorem.pollen.persistence.entity.LoginProvider; +import org.chorem.pollen.persistence.entity.LoginProviderImpl; + +/** + * @author Kevin Morin (Code Lutin) + */ +public class LoginProviderBean extends PollenBean<LoginProvider> { + + protected String name; + protected String key; + protected String secret; + protected String permissions; + protected boolean active; + + public LoginProviderBean() { + super(LoginProvider.class); + } + + @Override + public void fromEntity(LoginProvider entity) { + setEntityId(entity.getTopiaId()); + setName(entity.getName()); + setKey(entity.getKey()); + setSecret(entity.getSecret()); + setPermissions(entity.getPermissions()); + setActive(entity.isActive()); + } + + @Override + public LoginProvider toEntity() { + LoginProvider entity = new LoginProviderImpl(); + entity.setTopiaId(getEntityId()); + entity.setName(getName()); + entity.setKey(getKey()); + entity.setSecret(getSecret()); + entity.setPermissions(getPermissions()); + entity.setActive(isActive()); + return entity; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public String getPermissions() { + return permissions; + } + + public void setPermissions(String permissions) { + this.permissions = permissions; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java index c26c5f50..860e0266 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java @@ -33,6 +33,7 @@ import org.chorem.pollen.persistence.entity.ChoiceTopiaDao; import org.chorem.pollen.persistence.entity.CommentTopiaDao; import org.chorem.pollen.persistence.entity.FavoriteListMemberTopiaDao; import org.chorem.pollen.persistence.entity.FavoriteListTopiaDao; +import org.chorem.pollen.persistence.entity.LoginProviderTopiaDao; import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollTopiaDao; import org.chorem.pollen.persistence.entity.PollenPrincipalTopiaDao; @@ -242,6 +243,10 @@ public abstract class PollenServiceSupport implements PollenService { return getPersistenceContext().getVoterListMemberDao(); } + protected LoginProviderTopiaDao getLoginProviderDao() { + return getPersistenceContext().getLoginProviderDao(); + } + public void commit() { getPersistenceContext().commit(); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 6866b3b5..2d4aa50f 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -1,5 +1,6 @@ package org.chorem.pollen.services.service; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.brickred.socialauth.AuthProvider; @@ -7,15 +8,22 @@ import org.brickred.socialauth.Profile; import org.brickred.socialauth.SocialAuthConfig; import org.brickred.socialauth.SocialAuthManager; import org.brickred.socialauth.util.Constants; +import org.brickred.socialauth.util.OAuthConfig; +import org.chorem.pollen.persistence.entity.LoginProvider; +import org.chorem.pollen.persistence.entity.LoginProviderTopiaDao; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.PollenUserImpl; import org.chorem.pollen.persistence.entity.PollenUserTopiaDao; import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.UserCredentialImpl; +import org.chorem.pollen.services.bean.LoginProviderBean; import org.chorem.pollen.services.bean.PollenEntityRef; +import java.util.Comparator; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; /** * @author Kevin Morin (Code Lutin) @@ -90,6 +98,22 @@ public class SocialAuthService extends PollenServiceSupport { //Create an instance of SocialAuthConfgi object SocialAuthConfig config = SocialAuthConfig.getDefault(); + List<LoginProvider> allActiveProviders = getLoginProviderDao().forActiveEquals(true).findAll(); + allActiveProviders.forEach(provider -> { + try { + OAuthConfig providerConfig = new OAuthConfig(provider.getKey(), provider.getSecret()); + if (StringUtils.isNotBlank(provider.getPermissions())) { + providerConfig.setCustomPermissions(provider.getPermissions()); + } + config.addProviderConfig(provider.getName(), providerConfig); + + } catch (Exception e) { + if (log.isErrorEnabled()) { + log.error("Error while adding config for provider " + provider.getName(), e); + } + } + }); + //load configuration. By default load the configuration from oauth_consumer.properties. //You can also pass input stream, properties object or properties file name. config.load(); @@ -100,4 +124,43 @@ public class SocialAuthService extends PollenServiceSupport { return manager; } + + public List<LoginProviderBean> getAllLoginProviders() { + checkIsAdmin(); + LoginProviderTopiaDao dao = getLoginProviderDao(); + List<LoginProvider> loginProviders = dao.findAll().stream() + .sorted(Comparator.comparing(LoginProvider::getName)) + .collect(Collectors.toList()); + return toBeanList(LoginProviderBean.class, loginProviders); + } + + public List<String> getAvailableLoginProviders() { + LoginProviderTopiaDao dao = getLoginProviderDao(); + return dao.forActiveEquals(true).findAll().stream() + .map(LoginProvider::getName) + .sorted() + .collect(Collectors.toList()); + } + + public LoginProviderBean saveLoginProvider(LoginProviderBean loginProvider, boolean loginProviderExists) { + checkIsAdmin(); + checkNotNull(loginProvider); + LoginProviderTopiaDao dao = getLoginProviderDao(); + + LoginProvider toSave; + + if (loginProviderExists) { + toSave = dao.forTopiaIdEquals(loginProvider.getEntityId()).findUnique(); + } else { + toSave = dao.create(); + } + toSave.setName(loginProvider.getName()); + toSave.setKey(loginProvider.getKey()); + toSave.setSecret(loginProvider.getSecret()); + toSave.setPermissions(loginProvider.getPermissions()); + toSave.setActive(loginProvider.isActive()); + + commit(); + return toBean(LoginProviderBean.class, toSave); + } } diff --git a/pollen-services/src/main/resources/oauth_consumer.properties b/pollen-services/src/main/resources/oauth_consumer.properties index 6f015cc3..02f55921 100644 --- a/pollen-services/src/main/resources/oauth_consumer.properties +++ b/pollen-services/src/main/resources/oauth_consumer.properties @@ -1,6 +1,6 @@ #google -www.google.com.consumer_key = opensource.brickred.com -www.google.com.consumer_secret = YC06FqhmCLWvtBg/O4W/aJfj +#www.google.com.consumer_key = opensource.brickred.com +#www.google.com.consumer_secret = YC06FqhmCLWvtBg/O4W/aJfj #you can set custom permission by using custom_permissions with provider prefix. #www.google.com.custom_permissions = http://www.google.com/m8/feeds/,http://picasaweb.google.com/data/ @@ -13,44 +13,44 @@ www.google.com.consumer_secret = YC06FqhmCLWvtBg/O4W/aJfj #New registration on google will always provide OAuth2 keys which is supported by GooglePlus provider #google plus -googleapis.com.consumer_key = XXXXXXX -googleapis.com.consumer_secret = XXXXXXXX +#googleapis.com.consumer_key = XXXXXXX +#googleapis.com.consumer_secret = XXXXXXXX #yahoo -api.login.yahoo.com.consumer_key = dj0yJmk9VTdaSUVTU3RrWlRzJmQ9WVdrOWNtSjZNMFpITm1VbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD1iMA-- -api.login.yahoo.com.consumer_secret = 1db3d0b897dac60e151aa9e2499fcb2a6b474546 +#api.login.yahoo.com.consumer_key = dj0yJmk9VTdaSUVTU3RrWlRzJmQ9WVdrOWNtSjZNMFpITm1VbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD1iMA-- +#api.login.yahoo.com.consumer_secret = 1db3d0b897dac60e151aa9e2499fcb2a6b474546 #twitter -twitter.com.consumer_key = E3hm7J9IQbWLijpiQG7W8Q -twitter.com.consumer_secret = SGKNuXyybt0iDdgsuzVbFHOaemV7V6pr0wKwbaT2MH0 +#twitter.com.consumer_key = E3hm7J9IQbWLijpiQG7W8Q +#twitter.com.consumer_secret = SGKNuXyybt0iDdgsuzVbFHOaemV7V6pr0wKwbaT2MH0 #facebook -graph.facebook.com.consumer_key = 152190004803645 -graph.facebook.com.consumer_secret = 64c94bd02180b0ade85889b44b2ba7c4 +#graph.facebook.com.consumer_key = 152190004803645 +#graph.facebook.com.consumer_secret = 64c94bd02180b0ade85889b44b2ba7c4 #you can set custom permission by using custom_permissions with provider prefix. #graph.facebook.com.custom_permissions = publish_stream,email,user_birthday,user_location,offline_access #hotmail -consent.live.com.consumer_key = 000000004403D60E -consent.live.com.consumer_secret = cYqlii67pTvgPD4pdB7NUVC7L4MIHCcs +#consent.live.com.consumer_key = 000000004403D60E +#consent.live.com.consumer_secret = cYqlii67pTvgPD4pdB7NUVC7L4MIHCcs #Same keys will work for Linkedin OAuth2 provider #LinkedIn -api.linkedin.com.consumer_key = 9-mmqg28fpMocVuAg87exH-RXKs70yms52GSFIqkZN25S3m96kdPGBbuSxdSBIyL -api.linkedin.com.consumer_secret = e6NBqhDYE1fX17RwYGW5vMp25Cvh7Sbw9t-zMYTIW_T5LytY5OwJ12snh_YftgE4 +#api.linkedin.com.consumer_key = 9-mmqg28fpMocVuAg87exH-RXKs70yms52GSFIqkZN25S3m96kdPGBbuSxdSBIyL +#api.linkedin.com.consumer_secret = e6NBqhDYE1fX17RwYGW5vMp25Cvh7Sbw9t-zMYTIW_T5LytY5OwJ12snh_YftgE4 #MySpace -api.myspace.com.consumer_key = 29db395f5ee8426bb90b1db65c91c956 -api.myspace.com.consumer_secret = 0fdccc829c474e42867e16b68cda37a4c4b7b08eda574fe6a959943e3e9be709 +#api.myspace.com.consumer_key = 29db395f5ee8426bb90b1db65c91c956 +#api.myspace.com.consumer_secret = 0fdccc829c474e42867e16b68cda37a4c4b7b08eda574fe6a959943e3e9be709 #FourSquare -foursquare.com.consumer_key = JQKEM1PHWFW4YF2YPEQBRRESXE3SBGNCYJWWDTZKF3IZNJ3V -foursquare.com.consumer_secret = 4IILLDFDVPP2LC554S4KXKETQNTDKPDSEVCKVHA2QEHKYBEQ +#foursquare.com.consumer_key = JQKEM1PHWFW4YF2YPEQBRRESXE3SBGNCYJWWDTZKF3IZNJ3V +#foursquare.com.consumer_secret = 4IILLDFDVPP2LC554S4KXKETQNTDKPDSEVCKVHA2QEHKYBEQ #Yammer -www.yammer.com.consumer_key=5zyIkp12TrkulSRbSegQ -www.yammer.com.consumer_secret=zUcCB9kqWhI1IiTAJbl9QdG2AWcUJMDWp3Qyv5VJJw +#www.yammer.com.consumer_key=5zyIkp12TrkulSRbSegQ +#www.yammer.com.consumer_secret=zUcCB9kqWhI1IiTAJbl9QdG2AWcUJMDWp3Qyv5VJJw #Please use your own keys for mendeley #Mendeley @@ -58,20 +58,20 @@ www.yammer.com.consumer_secret=zUcCB9kqWhI1IiTAJbl9QdG2AWcUJMDWp3Qyv5VJJw #api.mendeley.com.consumer_secret= #Salesforce -login.salesforce.com.consumer_key = 3MVG9Y6d_Btp4xp4yFMR0tPSndkAVu4OBejuYcL2iGFC68tA49PknWKX20XdPl5s1iwWldyuAbSINWHbB2Jcu -login.salesforce.com.consumer_secret = 1993703471433041656 +#login.salesforce.com.consumer_key = 3MVG9Y6d_Btp4xp4yFMR0tPSndkAVu4OBejuYcL2iGFC68tA49PknWKX20XdPl5s1iwWldyuAbSINWHbB2Jcu +#login.salesforce.com.consumer_secret = 1993703471433041656 #Instagram -api.instagram.com.consumer_key=f1e23002a9da49f696d439368624c9fc -api.instagram.com.consumer_secret=f274614621f64d498cb3458b3736827a +#api.instagram.com.consumer_key=f1e23002a9da49f696d439368624c9fc +#api.instagram.com.consumer_secret=f274614621f64d498cb3458b3736827a #Flickr -www.flickr.com.consumer_key=942a1a394b866a30dc9b4ad8db5cb8f8 -www.flickr.com.consumer_secret=f90c5bee8a8de964 +#www.flickr.com.consumer_key=942a1a394b866a30dc9b4ad8db5cb8f8 +#www.flickr.com.consumer_secret=f90c5bee8a8de964 #GITHub -api.github.com.consumer_key=4ffc69764a59dd3ce347 -api.github.com.consumer_secret=dc62937c1d7bb9ce30cb654a26d4a575858f5e1f +#api.github.com.consumer_key=4ffc69764a59dd3ce347 +#api.github.com.consumer_secret=dc62937c1d7bb9ce30cb654a26d4a575858f5e1f #Implementations #you can provide your custom provider here e.g 'myprovider' is your provider id diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 42052f20..5aa63a94 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -69,14 +69,25 @@ class AuthService extends FetchService { } signInProvider(query, providerRedirection) { - console.log(query) - console.log(providerRedirection) return this.fetch( "/v1/login/" + query.loginProvider, "POST", {Authorization: JSON.stringify(query)}, providerRedirection); } + + getAllLoginProviders() { + return this.get("/v1/loginproviders"); + } + + getAvailableLoginProviders() { + console.log("getAvailableLoginProviders") + return this.get("/v1/loginproviders/active"); + } + + saveLoginProvider(loginProvider) { + return this.post("/v1/loginproviders/" + (loginProvider.id || ""), loginProvider); + } } module.exports = singleton(AuthService); diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 36ca5983..5a4114b6 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -30,8 +30,9 @@ require("./poll/EditPoll.tag.html"); require("./poll/Poll.tag.html"); require("./poll/Summary.tag.html"); require("./poll/Polls.tag.html"); -require("./Users.tag.html"); require("./UserProfile.tag.html"); +require("./admin/Users.tag.html"); +require("./admin/LoginProviders.tag.html"); require("./favoriteList/FavoriteLists.tag.html"); require("./favoriteList/FavoriteList.tag.html"); require("./popup/ConfirmPopup.tag.html"); @@ -217,6 +218,11 @@ require("./popup/InformationPopup.tag.html"); riot.mount(this.refs.content, "favoritelist", {favoriteListId: favoriteListId}); }); + route("/loginProviders", () => { + this.bus.trigger("pageChanged", "loginProviders"); + riot.mount(this.refs.content, "loginproviders"); + }); + route(() => { var q = route.query(); if (q.loginProvider != null) { diff --git a/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html b/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html index 9e540e82..7974eccb 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html @@ -37,6 +37,7 @@ require("./popup/FeedbackModal.tag.html"); <div class="dropdown-content right"> <a href="#user">{__.users}</a> <a href="#poll">{__.polls}</a> + <a href="#loginProviders">{__.loginProviders}</a> </div> </div> diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index 2ce478c5..c571e63a 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -58,8 +58,7 @@ require("./components/HumanInput.tag.html"); <a onclick="{newPassword}">{__.lostpassword}</a> </form> <p>Ou connectez vous avec votre compte : - <a onclick="{signinWithProvider('facebook')}"><i class="fa fa-facebook-official"></i></a> - <a onclick="{signinWithProvider('googleplus')}"><i class="fa fa-google"></i></a> + <a each="{loginProvider in loginProviders}" onclick="{signinWithProvider(loginProvider)}">{loginProvider}</a> </p> </div> @@ -79,6 +78,15 @@ require("./components/HumanInput.tag.html"); this.message = ""; this.openSignIn = false; + let authService = require("../js/AuthService"); + this.loginProviders = []; + this.on("mount", () => { + authService.getAvailableLoginProviders().then((result) => { + this.loginProviders = result; + this.update(); + }); + }); + this.newPassword = () => { this.refs.newPassword.open(this.refs.login.value || ""); }; diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html new file mode 100644 index 00000000..5e23f89e --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html @@ -0,0 +1,92 @@ +<LoginProviders> + <div class="container" show="{loaded}"> + <h1>{__.title}</h1> + + <div class="main-content"> + + <table> + <thead> + <tr> + <th>{__.name}</th> + <th>{__.key}</th> + <th>{__.secret}</th> + <th>{__.permission}</th> + <th>{__.active}</th> + </tr> + </thead> + <tbody> + <tr each="{loginprovider, index in loginProviders}"> + <td><input type="text" ref="name{index}" value="{loginprovider.name}" required/></td> + <td><input type="text" ref="key{index}" value="{loginprovider.key}" required/></td> + <td><input type="text" ref="secret{index}" value="{loginprovider.secret}" required/></td> + <td><input type="text" ref="permissions{index}" value="{loginprovider.permissions}"/></td> + <td><input type="checkbox" ref="active{index}" checked="{loginprovider.active}"/></td> + <td> + <button class="c-button" onclick="{saveLoginProvider(index)}"><i class="fa fa-check"></i></button> + <button class="c-button" onclick="{cancelEdition(index)}"><i class="fa fa-remove"></i></button> + </td> + </tr> + </tbody> + </table> + + <button class="c-button" onclick="{addProvider}"><i class="fa fa-plus"></i></button> + </div> + </div> + + <script type="es6"> + this.loaded = false; + let session = require("../../js/Session"); + this.installBundle(session, "loginProviders"); + + let authService = require("../../js/AuthService"); + this.loginProviders = []; + authService.getAllLoginProviders().then((result) => { + if (!this.loaded) { + this.loginProviders = result; + this.loaded = true; + this.update(); + } + return result; + }); + + this.addProvider = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.loginProviders.push({}); + }; + + this.saveLoginProvider = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + let loginProvider = this.loginProviders[index]; + loginProvider.name = this.refs["name" + index].value; + loginProvider.key = this.refs["key" + index].value; + loginProvider.secret = this.refs["secret" + index].value; + loginProvider.permissions = this.refs["permissions" + index].value; + loginProvider.active = this.refs["active" + index].checked; + + authService.saveLoginProvider(loginProvider).then((result) => { + loginProvider.id = result.id; + loginProvider.name = result.name; + loginProvider.key = result.key; + loginProvider.secret = result.secret; + loginProvider.permissions = result.permissions; + loginProvider.active = result.active; + }); + }; + + this.cancelEdition = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + let loginProvider = this.loginProviders[index]; + this.refs["name" + index].value = loginProvider.name || ""; + this.refs["key" + index].value = loginProvider.key || ""; + this.refs["secret" + index].value = loginProvider.secret || ""; + this.refs["permissions" + index].value = loginProvider.permissions || ""; + this.refs["active" + index].checked = loginProvider.active || false; + }; + + </script> + <style> + </style> +</LoginProviders> diff --git a/pollen-ui-riot-js/src/main/web/tag/UserCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/UserCard.tag.html similarity index 95% rename from pollen-ui-riot-js/src/main/web/tag/UserCard.tag.html rename to pollen-ui-riot-js/src/main/web/tag/admin/UserCard.tag.html index 33ffec79..b2599ea7 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/UserCard.tag.html @@ -1,4 +1,4 @@ -require("./components/Card.tag.html"); +require("../components/Card.tag.html"); require("./UserEditModal.tag.html"); <UserCard> @@ -50,9 +50,9 @@ require("./UserEditModal.tag.html"); </form> <script type="es6"> - let session = require("../js/Session"); + let session = require("../../js/Session"); this.installBundle(session, "user"); - let userService = require("../js/UserService"); + let userService = require("../../js/UserService"); this.editing = false; this.errors = {}; diff --git a/pollen-ui-riot-js/src/main/web/tag/UserEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/UserEditModal.tag.html similarity index 94% rename from pollen-ui-riot-js/src/main/web/tag/UserEditModal.tag.html rename to pollen-ui-riot-js/src/main/web/tag/admin/UserEditModal.tag.html index 5a89e692..a41f5350 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserEditModal.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/UserEditModal.tag.html @@ -1,4 +1,4 @@ -require("./popup/Modal.tag.html"); +require("../popup/Modal.tag.html"); <UserEditModal> <Modal ref="modal" @@ -67,10 +67,10 @@ require("./popup/Modal.tag.html"); </Modal> <script type="es6"> - let session = require("../js/Session"); - let Message = require("../js/Message"); + let session = require("../../js/Session"); + let Message = require("../../js/Message"); this.installBundle(session, "user"); - let userService = require("../js/UserService"); + let userService = require("../../js/UserService"); this.errors = {}; diff --git a/pollen-ui-riot-js/src/main/web/tag/Users.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html similarity index 88% rename from pollen-ui-riot-js/src/main/web/tag/Users.tag.html rename to pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html index bb2d4351..286538ad 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Users.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html @@ -1,6 +1,6 @@ -require("./components/LazyLoad.tag.html"); -require("./components/LoadingCard.tag.html"); -require("./components/Search.tag.html"); +require("../components/LazyLoad.tag.html"); +require("../components/LoadingCard.tag.html"); +require("../components/Search.tag.html"); require("./UserCard.tag.html"); <Users> <div class="container" show="{loaded}"> @@ -28,7 +28,7 @@ require("./UserCard.tag.html"); <script type="es6"> this.loaded = false; - let session = require("../js/Session"); + let session = require("../../js/Session"); this.installBundle(session, "users"); this.pagination = { @@ -39,7 +39,7 @@ require("./UserCard.tag.html"); }; this.search = {value: ""}; - let userService = require("../js/UserService"); + let userService = require("../../js/UserService"); this.refresh = () => { this.refs.lazyLoad.reload(); -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 40bb3dc9b68e3e40816a9d2181542416e9a5a9f6 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 25 18:03:46 2017 +0200 refs #1 ajout du socialmanager dans la session en attendant le retour du provider + gestion des tiers de connexion + gestion des comptes sans email --- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 41 ++++++++++++--- .../services/service/NotificationService.java | 50 ++++++++++-------- .../pollen/services/service/SocialAuthService.java | 60 ++++++++++++++-------- 3 files changed, 101 insertions(+), 50 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index 748dc894..fc2ac99b 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -26,10 +26,13 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.shiro.codec.Base64; +import org.brickred.socialauth.SocialAuthManager; +import org.chorem.pollen.persistence.entity.LoginProvider; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.services.PollenServiceContext; import org.chorem.pollen.services.bean.LoginProviderBean; +import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.service.PollenUserService; import org.chorem.pollen.services.service.SocialAuthService; @@ -42,7 +45,9 @@ import org.chorem.pollen.services.service.security.PollenSecurityContext; import org.chorem.pollen.services.service.security.PollenUserBannedException; import org.chorem.pollen.services.service.security.SecurityService; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; @@ -55,7 +60,6 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; -import java.net.URI; import java.util.List; import java.util.Map; @@ -75,7 +79,8 @@ public class AuthApi { public static final String COOKIE_POLLEN_AUTH = "pollen-auth"; private static final String COOKIE_POLLEN_CONNECTED = "pollen-connected"; - private final static int COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year + private static final int COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year + private static final String SOCIAL_AUTH_MANAGER_SESSION_KEY = "socialAuthManager"; public static Response.ResponseBuilder removeAuthCookie(Response.ResponseBuilder reponseBuilder) { @@ -191,13 +196,15 @@ public class AuthApi { @Path("/login/{providerId}") @GET - public Response loginProvider(@Context SocialAuthService socialAuthService, + public String getLoginProviderUrl(@Context SocialAuthService socialAuthService, + @Context HttpServletRequest request, @PathParam("providerId") String providerId, @QueryParam("providerRedirection") String providerRedirection) throws Exception { - String providerLoginUrl = socialAuthService.getProviderAuthenticationUrl(providerId, providerRedirection); - return Response.seeOther(URI.create(providerLoginUrl)).build(); + SocialAuthManager socialAuthManager = socialAuthService.getSocialAuthManager(); + request.getSession(true).setAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY, socialAuthManager); + return socialAuthManager.getAuthenticationUrl(providerId, providerRedirection); } @Path("/login/{providerId}") @@ -206,14 +213,18 @@ public class AuthApi { @Context PollenServiceContext serviceContext, @Context SecurityService securityService, @Context PollenSecurityContext securityContext, - @PathParam("providerId") String providerId, - String providerRedirection, + @Context HttpServletRequest request, @HeaderParam("authorization") String authorization) throws Exception { + SocialAuthManager socialAuthManager = + (SocialAuthManager) request.getSession().getAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY); + //socialAuthManager + request.getSession().removeAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY); Gson gson = new Gson(); Map<String, String> paramsMap = gson.fromJson(authorization, Map.class); - PollenEntityRef<PollenUser> userPollenEntityRef = socialAuthService.login(providerId, providerRedirection, paramsMap); + PollenEntityRef<PollenUser> userPollenEntityRef = socialAuthService.login(socialAuthManager, + paramsMap); return getLoginResponseFromPollenUser(serviceContext, securityService, securityContext, userPollenEntityRef); } @@ -270,8 +281,22 @@ public class AuthApi { return socialAuthService.saveLoginProvider(loginProvider, true); } + @Path("/loginproviders/{providerId}") + @DELETE + public void deleteLoginProvider(@Context SocialAuthService socialAuthService, + @PathParam("providerId") PollenEntityId<LoginProvider> providerId) { + socialAuthService.deleteLoginProvider(providerId.getEntityId()); + + } + @Path("/loginproviders/active") @GET + public List<String> getActiveLoginProviders(@Context SocialAuthService socialAuthService) { + return socialAuthService.getActiveLoginProviders(); + } + + @Path("/loginproviders/available") + @GET public List<String> getAvailableLoginProviders(@Context SocialAuthService socialAuthService) { return socialAuthService.getAvailableLoginProviders(); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java index 035fb742..50e62797 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java @@ -73,10 +73,12 @@ import java.util.Set; public class NotificationService extends PollenServiceSupport { public void onUserCreated(PollenUser user) { - EmailService emailService = getEmailService(); - UserAccountCreatedEmail email = emailService.newUserAccountCreatedEmail(user); - email.addTo(user.getEmail()); - emailService.send(email); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + UserAccountCreatedEmail email = emailService.newUserAccountCreatedEmail(user); + email.addTo(user.getEmail()); + emailService.send(email); + } } public void onResendValidation(PollenUser user) { @@ -87,24 +89,30 @@ public class NotificationService extends PollenServiceSupport { } public void onUserEdited(PollenUser user) { - EmailService emailService = getEmailService(); - UserAccountEditedEmail email = emailService.newUserAccountEditedEmail(user); - email.addTo(user.getEmail()); - emailService.send(email); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + UserAccountEditedEmail email = emailService.newUserAccountEditedEmail(user); + email.addTo(user.getEmail()); + emailService.send(email); + } } public void onUserDeleted(PollenUser user) { - EmailService emailService = getEmailService(); - UserAccountDeletedEmail email = emailService.newUserAccountDeletedEmail(user); - email.addTo(user.getEmail()); - emailService.send(email); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + UserAccountDeletedEmail email = emailService.newUserAccountDeletedEmail(user); + email.addTo(user.getEmail()); + emailService.send(email); + } } public void onUserPasswordChanged(PollenUser user) { - EmailService emailService = getEmailService(); - UserAccountPasswordChangedEmail email = emailService.newUserAccountPasswordChangedEmail(user); - email.addTo(user.getEmail()); - emailService.send(email); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + UserAccountPasswordChangedEmail email = emailService.newUserAccountPasswordChangedEmail(user); + email.addTo(user.getEmail()); + emailService.send(email); + } } public void onUserEmailValidated(PollenUser user) { @@ -115,10 +123,12 @@ public class NotificationService extends PollenServiceSupport { } public void onUserLostPasswordAsked(PollenUser user, String newPassword) { - EmailService emailService = getEmailService(); - LostPasswordEmail email = emailService.newLostPasswordEmail(user, newPassword); - email.addTo(user.getEmail()); - emailService.send(email); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + LostPasswordEmail email = emailService.newLostPasswordEmail(user, newPassword); + email.addTo(user.getEmail()); + emailService.send(email); + } } public void onFavoriteListAdded(PollenUser user, FavoriteList favoriteList) { diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 2d4aa50f..2e136aa7 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -19,7 +19,7 @@ import org.chorem.pollen.persistence.entity.UserCredentialImpl; import org.chorem.pollen.services.bean.LoginProviderBean; import org.chorem.pollen.services.bean.PollenEntityRef; -import java.util.Comparator; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -33,21 +33,9 @@ public class SocialAuthService extends PollenServiceSupport { /** Logger. */ private static final Log log = LogFactory.getLog(SocialAuthService.class); - public String getProviderAuthenticationUrl(String providerId, String redirection) throws Exception { - SocialAuthManager manager = getSocialAuthManager(); - - // get Provider URL to which you should redirect for authentication. - // id can have values "facebook", "twitter", "yahoo" etc. or the OpenID URL - return manager.getAuthenticationUrl(providerId, redirection); - } - - public PollenEntityRef<PollenUser> login(String providerId, - String redirection, + public PollenEntityRef<PollenUser> login(SocialAuthManager manager, Map<String, String> paramsMap) throws Exception { - SocialAuthManager manager = getSocialAuthManager(); - manager.getAuthenticationUrl(providerId, redirection); - paramsMap.remove(Constants.STATE); AuthProvider provider = manager.connect(paramsMap); // get profile @@ -94,7 +82,7 @@ public class SocialAuthService extends PollenServiceSupport { return getSecurityService().getSessionTokenForUser(pollenUser); } - protected SocialAuthManager getSocialAuthManager() throws Exception { + public SocialAuthManager getSocialAuthManager() throws Exception { //Create an instance of SocialAuthConfgi object SocialAuthConfig config = SocialAuthConfig.getDefault(); @@ -128,27 +116,47 @@ public class SocialAuthService extends PollenServiceSupport { public List<LoginProviderBean> getAllLoginProviders() { checkIsAdmin(); LoginProviderTopiaDao dao = getLoginProviderDao(); - List<LoginProvider> loginProviders = dao.findAll().stream() - .sorted(Comparator.comparing(LoginProvider::getName)) - .collect(Collectors.toList()); + List<LoginProvider> loginProviders = dao.findAll(); return toBeanList(LoginProviderBean.class, loginProviders); } - public List<String> getAvailableLoginProviders() { + public List<String> getActiveLoginProviders() { LoginProviderTopiaDao dao = getLoginProviderDao(); return dao.forActiveEquals(true).findAll().stream() .map(LoginProvider::getName) - .sorted() .collect(Collectors.toList()); } + public List<String> getAvailableLoginProviders() { + return new ArrayList<String>() {{ + add(Constants.AMAZON); + add(Constants.FACEBOOK); + add(Constants.FLICKR); + add(Constants.FOURSQUARE); + add(Constants.GITHUB); + add(Constants.GOOGLE_PLUS); + add(Constants.HOTMAIL); + add(Constants.INSTAGRAM); + add(Constants.LINKEDIN); + add(Constants.LINKEDINOAUTH2); + add(Constants.MENDELEY); + add(Constants.MYSPACE); + add(Constants.NIMBLE); + add(Constants.RUNKEEPER); + add(Constants.SALESFORCE); + add(Constants.STACK_EXCHANGE); + add(Constants.TWITTER); + add(Constants.YAHOO); + add(Constants.YAMMER); + }}; + } + public LoginProviderBean saveLoginProvider(LoginProviderBean loginProvider, boolean loginProviderExists) { checkIsAdmin(); checkNotNull(loginProvider); - LoginProviderTopiaDao dao = getLoginProviderDao(); + LoginProviderTopiaDao dao = getLoginProviderDao(); LoginProvider toSave; - if (loginProviderExists) { toSave = dao.forTopiaIdEquals(loginProvider.getEntityId()).findUnique(); } else { @@ -163,4 +171,12 @@ public class SocialAuthService extends PollenServiceSupport { commit(); return toBean(LoginProviderBean.class, toSave); } + + public void deleteLoginProvider(String providerId) { + checkIsAdmin(); + checkNotNull(providerId); + LoginProviderTopiaDao dao = getLoginProviderDao(); + dao.delete(dao.forTopiaIdEquals(providerId).findUnique()); + commit(); + } } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit a63cca0d24332ec0b9c70599f652e2cf8eb83832 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 25 18:04:36 2017 +0200 refs #1 gestion des tiers de connexion + style du login --- pollen-ui-riot-js/src/main/web/css/main.css | 8 ++ pollen-ui-riot-js/src/main/web/js/AuthService.js | 18 ++- pollen-ui-riot-js/src/main/web/js/FetchService.js | 5 +- pollen-ui-riot-js/src/main/web/js/Session.js | 2 +- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 131 ++++++++++++++------- pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html | 4 +- .../src/main/web/tag/admin/LoginProviders.tag.html | 104 +++++++++++++--- 7 files changed, 205 insertions(+), 67 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/css/main.css b/pollen-ui-riot-js/src/main/web/css/main.css index 04db9045..59c2433c 100644 --- a/pollen-ui-riot-js/src/main/web/css/main.css +++ b/pollen-ui-riot-js/src/main/web/css/main.css @@ -470,3 +470,11 @@ pollenfooter a:hover { .no-border { border: 0; } + +.align-right { + text-align: right; +} + +.align-center { + text-align: center; + } \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 5aa63a94..3fd1d1f1 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -68,12 +68,15 @@ class AuthService extends FetchService { return this.post("/v1/resendValidation", email); } - signInProvider(query, providerRedirection) { + getLoginProviderUrl(providerId, redirection) { + return this.get("/v1/login/" + providerId, { providerRedirection: redirection}); + } + + signInProvider(query) { return this.fetch( "/v1/login/" + query.loginProvider, "POST", - {Authorization: JSON.stringify(query)}, - providerRedirection); + {Authorization: JSON.stringify(query)}); } getAllLoginProviders() { @@ -81,13 +84,20 @@ class AuthService extends FetchService { } getAvailableLoginProviders() { - console.log("getAvailableLoginProviders") + return this.get("/v1/loginproviders/available"); + } + + getActiveLoginProviders() { return this.get("/v1/loginproviders/active"); } saveLoginProvider(loginProvider) { return this.post("/v1/loginproviders/" + (loginProvider.id || ""), loginProvider); } + + deleteLoginProvider(loginProvider) { + return this.doDelete("/v1/loginproviders/" + loginProvider.id); + } } module.exports = singleton(AuthService); diff --git a/pollen-ui-riot-js/src/main/web/js/FetchService.js b/pollen-ui-riot-js/src/main/web/js/FetchService.js index 1426bb72..ae3de5a7 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -50,7 +50,10 @@ class FetchService { return null; } if (response.status === 200) { - return response.json(); + let responseCopy = response.clone(); + return responseCopy.json().catch(err => { + return response.text(); + }); } if (response.status === 400) { return response.json().then(json => Promise.reject(json)); diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index f5f84fdf..77bcd203 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -137,7 +137,7 @@ class Session { } signInProvider(query) { - return authService.signInProvider(query, this.getProviderRedirectionUrl(query.loginProvider)) + return authService.signInProvider(query) .then(auth => this.updateConnection(auth, this)); } diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index c571e63a..f58786ac 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -24,42 +24,45 @@ require("./components/HumanInput.tag.html"); <SignIn> <div class="body-container colors-default sign-in-layer" show={openSignIn}> <div class="body-content"> - <h1 class="c-heading">{__.title}</h1> + <h1 class="c-heading"><i class="fa fa-sign-in"></i> {__.title}</h1> <form class="signin"> <HumanInput onsubmit={signIn}/> <div class="o-form-element"> - <div class="c-input-group c-input-group--stacked"> - <div class="o-field"> - <input class="c-field {c-field--error : message}" - type="email" - id="login" - name="login" - ref="login" - required - placeholder={__.login_placeholder}> - </div> - <div class="o-field o-field--icon-right"> - <input class="c-field {c-field--error : message}" - type="password" - id="password" - name="password" - ref="password" - required - placeholder={__.password_placeholder}> - <button class="c-icon login-btn" - type="submit" - title={__.connexion}> - <i class="fa fa-fw fa-arrow-right"/> - </button> - </div> - </div> + <label class="c-label" for="login">{__.login}</label> + <input class="c-field {c-field--error : message}" + type="email" + id="login" + name="login" + ref="login" + required + placeholder={__.login_placeholder}/> + </div> + <div class="o-form-element"> + <label class="c-label" for="password">{__.password}</label> + <input class="c-field {c-field--error : message}" + type="password" + id="password" + name="password" + ref="password" + required + placeholder={__.password_placeholder}> + </div> + <div class="o-form-element align-right"> + <p><button class="c-button c-button--info" type="submit"><i class="fa fa-sign-in"></i> {__.title}</button></p> <div class="c-hint--static c-hint--error">{message}</div> + <p><a onclick="{newPassword}">{__.lostpassword}</a></p> + </div> + <div class="o-form-element align-center"> + <p>Ou connectez vous avec votre compte :</p> + <p> + <a each="{loginProvider in loginProviders}" class="provider-link" + onclick="{signinWithProvider(loginProvider)}"> + <i class="fa fa-{providerIcons[loginProvider]}" if="{providerIcons[loginProvider]}"></i> + <span if="{!providerIcons[loginProvider]}">{loginProvider}</span> + </a> + </p> </div> - <a onclick="{newPassword}">{__.lostpassword}</a> </form> - <p>Ou connectez vous avec votre compte : - <a each="{loginProvider in loginProviders}" onclick="{signinWithProvider(loginProvider)}">{loginProvider}</a> - </p> </div> <SignUp/> @@ -78,10 +81,25 @@ require("./components/HumanInput.tag.html"); this.message = ""; this.openSignIn = false; + this.providerIcons = { + "amazon": "amazon", + "facebook": "facebook-official", + "flickr": "flickr", + "foursquare": "foursquare", + "github": "github", + "googleplus": "google", + "instagram": "instagram", + "linkedin": "linkedin", + "linkedin2": "linkedin", + "stackexchange": "stack-exchange", + "twitter": "twitter", + "yahoo": "yahoo" + }; + let authService = require("../js/AuthService"); this.loginProviders = []; this.on("mount", () => { - authService.getAvailableLoginProviders().then((result) => { + authService.getActiveLoginProviders().then((result) => { this.loginProviders = result; this.update(); }); @@ -122,8 +140,11 @@ require("./components/HumanInput.tag.html"); this.signinWithProvider = (provider) => (e) => { let currentPage = location.hash || "#"; localStorage.setItem("currentPage", currentPage); - location.href = this.session.configuration.endPoint + "/v1/login/" + provider - + "?providerRedirection=" + encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); + let authService = require("../js/AuthService"); + let redirection = encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); + authService.getLoginProviderUrl(provider, redirection).then(result => { + location.href = result; + }); }; </script> @@ -143,21 +164,10 @@ require("./components/HumanInput.tag.html"); top: 10px; } - .signin { - width: 250px; - margin: 0 auto; - } - .c-heading { text-align: center; } - .login-btn { - border: none; - background: transparent; - font-size: 1em; - } - .body-content { margin-bottom: 20px; } @@ -168,6 +178,39 @@ require("./components/HumanInput.tag.html"); } } + .signin { + padding: 0 1em; + margin: 0 auto; + max-width: 450px; + } + + .o-form-element p { + padding: 2px 0; + } + + .provider-link { + font-size: 2em; + } + + @media (min-width: 640px) { + .o-form-element .c-label:first-child { + width: 35%; + display: inline-block; + text-align: right; + float: left; + padding-top: 0.5em; + padding-right: 5px; + } + + .o-form-element .c-field { + width: 65%; + display: inline-block; + } + + .signin .c-hint--static { + margin-left: 35%; + } + } </style> </SignIn> diff --git a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html index eee9115a..1d830d41 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html @@ -95,8 +95,8 @@ require("./components/HumanInput.tag.html"); <div class="actions-right"> <button type="submit" class="c-button c-button--info"> - <i class="fa fa-plus" aria-hidden="true"></i> - {__.validate} + <i class="fa fa-user-plus" aria-hidden="true"></i> + {__.title} </button> </div> </form> diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html index 5e23f89e..49e06b1c 100644 --- a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html @@ -1,3 +1,5 @@ +require("../components/HumanInput.tag.html"); + <LoginProviders> <div class="container" show="{loaded}"> <h1>{__.title}</h1> @@ -7,29 +9,38 @@ <table> <thead> <tr> - <th>{__.name}</th> - <th>{__.key}</th> - <th>{__.secret}</th> - <th>{__.permission}</th> + <th>{__.name}*</th> + <th>{__.key}*</th> + <th>{__.secret}*</th> + <th>{__.permissions}</th> <th>{__.active}</th> </tr> </thead> <tbody> <tr each="{loginprovider, index in loginProviders}"> - <td><input type="text" ref="name{index}" value="{loginprovider.name}" required/></td> - <td><input type="text" ref="key{index}" value="{loginprovider.key}" required/></td> - <td><input type="text" ref="secret{index}" value="{loginprovider.secret}" required/></td> - <td><input type="text" ref="permissions{index}" value="{loginprovider.permissions}"/></td> - <td><input type="checkbox" ref="active{index}" checked="{loginprovider.active}"/></td> <td> - <button class="c-button" onclick="{saveLoginProvider(index)}"><i class="fa fa-check"></i></button> - <button class="c-button" onclick="{cancelEdition(index)}"><i class="fa fa-remove"></i></button> + <select class="c-field" ref="name{index}" required disabled="{editingRow != index}"> + <option>{loginprovider.name}</option> + <option each="{availableProvider in availableLoginProviders}">{availableProvider}</option> + </select> + </td> + <td><input class="c-field" type="text" ref="key{index}" value="{loginprovider.key}" required disabled="{editingRow != index}"/></td> + <td><input class="c-field c-field--large" type="text" ref="secret{index}" value="{loginprovider.secret}" required disabled="{editingRow != index}"/></td> + <td><input class="c-field" type="text" ref="permissions{index}" value="{loginprovider.permissions}" disabled="{editingRow != index}"/></td> + <td><input type="checkbox" ref="active{index}" checked="{loginprovider.active}" disabled="{editingRow != index}"/></td> + <td if="{editingRow != index}"> + <button class="c-button c-button--info" onclick="{editLoginProvider(index)}" disabled="{editingRow != null}"><i class="fa fa-edit"></i></button> + <button class="c-button c-button--error" onclick="{deleteLoginProvider(index)}" disabled="{editingRow != null}"><i class="fa fa-trash"></i></button> + </td> + <td if="{editingRow == index}"> + <button class="c-button c-button--success" onclick="{saveLoginProvider(index)}"><i class="fa fa-check"></i></button> + <button class="c-button c-button--error" onclick="{cancelEdition(index)}"><i class="fa fa-remove"></i></button> </td> </tr> </tbody> </table> - <button class="c-button" onclick="{addProvider}"><i class="fa fa-plus"></i></button> + <button class="c-button" onclick="{addProvider}" disabled="{editingRow != null}"><i class="fa fa-plus"></i> {__.newProvider}</button> </div> </div> @@ -38,27 +49,77 @@ let session = require("../../js/Session"); this.installBundle(session, "loginProviders"); + this.editingRow = null; + let authService = require("../../js/AuthService"); this.loginProviders = []; - authService.getAllLoginProviders().then((result) => { + this.availableLoginProviders = []; + Promise.all([authService.getAllLoginProviders(), authService.getAvailableLoginProviders()]).then(results => { if (!this.loaded) { - this.loginProviders = result; + this.loginProviders = results[0]; + let usedLoginProviders = Array.from(this.loginProviders, item => item.name); + this.availableLoginProviders = results[1].filter(item => usedLoginProviders.indexOf(item) === -1); + this.availableLoginProviders.sort(); this.loaded = true; this.update(); } - return result; }); this.addProvider = (e) => { e.preventDefault(); e.stopPropagation(); this.loginProviders.push({}); + this.editingRow = this.loginProviders.length - 1; + }; + + this.editLoginProvider = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + this.editingRow = index; + }; + + this.deleteLoginProvider = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + let loginProvider = this.loginProviders[index]; + this.confirm(this.__.deleteMessage).then((confirm) => { + if (confirm) { + if (!loginProvider.id) { + this.loginProviders.splice(index, 1); + this.availableLoginProviders.push(loginProvider.name); + this.availableLoginProviders.sort(); + this.update(); + } else { + authService.deleteLoginProvider(loginProvider).then(() => { + this.loginProviders.splice(index, 1); + this.availableLoginProviders.push(loginProvider.name); + this.availableLoginProviders.sort(); + this.update(); + }); + } + } + }); }; this.saveLoginProvider = (index) => (e) => { e.preventDefault(); e.stopPropagation(); let loginProvider = this.loginProviders[index]; + let oldProvider = loginProvider.name; + + if (!this.refs["name" + index].value) { + alert(this.__.emptyName); + return; + } + if (!this.refs["key" + index].value) { + alert(this.__.emptyKey); + return; + } + if (!this.refs["secret" + index].value) { + alert(this.__.emptySecret); + return; + } + loginProvider.name = this.refs["name" + index].value; loginProvider.key = this.refs["key" + index].value; loginProvider.secret = this.refs["secret" + index].value; @@ -72,6 +133,15 @@ loginProvider.secret = result.secret; loginProvider.permissions = result.permissions; loginProvider.active = result.active; + + this.availableLoginProviders.splice(this.availableLoginProviders.indexOf(result.name), 1); + this.availableLoginProviders.push(oldProvider); + this.availableLoginProviders.sort(); + + this.refs["name" + index].value = loginProvider.name; + + this.editingRow = null; + this.update(); }); }; @@ -84,9 +154,13 @@ this.refs["secret" + index].value = loginProvider.secret || ""; this.refs["permissions" + index].value = loginProvider.permissions || ""; this.refs["active" + index].checked = loginProvider.active || false; + this.editingRow = null; }; </script> <style> + td { + text-align: center; + } </style> </LoginProviders> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit a32cf352ca05b298cd6abb2d82ae8e8e958644c7 Author: Kevin Morin <morin@codelutin.com> Date: Tue Aug 29 17:57:01 2017 +0200 refs #1 erreur si l'utilisateur veut se connecter via un service tiers et que son email est deja utilisé par un autre compte Pollen --- .../pollen/rest/api/PollenRestApiApplication.java | 2 ++ .../PollenEmailAlreadyUsedExceptionMapper.java | 20 ++++++++++++++ .../pollen/services/service/SocialAuthService.java | 4 +++ .../security/PollenEmailAlreadyUsedException.java | 11 ++++++++ pollen-ui-riot-js/src/main/web/img/logo.png | Bin 0 -> 10506 bytes pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 18 +++++++++++-- .../src/main/web/tag/PollenMessageManager.tag.html | 2 ++ .../src/main/web/tag/admin/LoginProviders.tag.html | 30 ++++++++++----------- 8 files changed, 69 insertions(+), 18 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java index 897dfbcf..271b223a 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java @@ -7,6 +7,7 @@ import org.chorem.pollen.rest.api.exceptionMappers.FavoriteListImportExceptionMa import org.chorem.pollen.rest.api.exceptionMappers.InvalidEntityLinkExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.InvalidFormExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenAuthenticationExceptionMapper; +import org.chorem.pollen.rest.api.exceptionMappers.PollenEmailAlreadyUsedExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenEmailNotValidatedExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenInvalidEmailActivationTokenExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenInvalidPermissionExceptionMapper; @@ -61,6 +62,7 @@ public class PollenRestApiApplication extends Application { new PollenInvalidPermissionExceptionMapper(), new PollenInvalidEmailActivationTokenExceptionMapper(), new PollenEmailNotValidatedExceptionMapper(), + new PollenEmailAlreadyUsedExceptionMapper(), new PollenUserBannedExceptionMapper(), new InvalidFormExceptionMapper(), new FavoriteListImportExceptionMapper(), diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java new file mode 100644 index 00000000..3b1ec37b --- /dev/null +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java @@ -0,0 +1,20 @@ +package org.chorem.pollen.rest.api.exceptionMappers; + +import org.chorem.pollen.services.service.security.PollenEmailAlreadyUsedException; + +import javax.ws.rs.core.Response; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class PollenEmailAlreadyUsedExceptionMapper extends PollenAbstractExceptionMapper<PollenEmailAlreadyUsedException> { + + public PollenEmailAlreadyUsedExceptionMapper() { + super(Response.Status.FORBIDDEN); + } + + @Override + protected Object getEntity(PollenEmailAlreadyUsedException exception) { + return "emailAlreadyUsed"; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 2e136aa7..8c9f7284 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -18,6 +18,7 @@ import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.UserCredentialImpl; import org.chorem.pollen.services.bean.LoginProviderBean; import org.chorem.pollen.services.bean.PollenEntityRef; +import org.chorem.pollen.services.service.security.PollenEmailAlreadyUsedException; import java.util.ArrayList; import java.util.List; @@ -56,6 +57,9 @@ public class SocialAuthService extends PollenServiceSupport { } pollenUser = pollenUserForCredential.get(); + } else if (userDao.emailExists(p.getEmail())) { + throw new PollenEmailAlreadyUsedException(); + } else { if (log.isInfoEnabled()) { log.info("create new user : " + name); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java new file mode 100644 index 00000000..afd67772 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java @@ -0,0 +1,11 @@ +package org.chorem.pollen.services.service.security; + +/** + * @author Kevin Morin (Code Lutin) + */ +public class PollenEmailAlreadyUsedException extends Exception { + + public PollenEmailAlreadyUsedException() { + super("emailAlreadyUsed"); + } +} diff --git a/pollen-ui-riot-js/src/main/web/img/logo.png b/pollen-ui-riot-js/src/main/web/img/logo.png new file mode 100644 index 00000000..79c5e328 Binary files /dev/null and b/pollen-ui-riot-js/src/main/web/img/logo.png differ diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 5a4114b6..a64d7482 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -71,15 +71,22 @@ require("./popup/InformationPopup.tag.html"); this.updatePageTitle(); }); + let route = require("riot-route"); + let Message = require("../js/Message"); + this.on("mount", () => { this.listen("locale", this.onLocaleChange); this.listen("unauthorize", this.refs.signIn.open); this.listen("signIn", this.refs.signIn.open); this.listen("closeSignIn", this.refs.signIn.close); + this.listen("messageManagerReady", () => { + let q = route.query(); + if (q.error) { + this.bus.trigger("message", new Message(decodeURIComponent(this._l(q.error)), "error")); + } + }); }); - let route = require("riot-route"); - route("/poll/create", () => { this.bus.trigger("pageChanged", "home"); riot.mount(this.refs.content, "createpoll"); @@ -230,6 +237,13 @@ require("./popup/InformationPopup.tag.html"); let currentPage = localStorage.getItem("currentPage"); localStorage.removeItem("currentPage"); location.href = session.pollenUIContext.uiEndPoint + "/" + currentPage; + }, (e) => { + let currentPage = localStorage.getItem("currentPage"); + localStorage.removeItem("currentPage"); + console.log(e); + e.text().then(label => { + location.href = session.pollenUIContext.uiEndPoint + "/" + currentPage + "?error=" + label; + }); }); } else { diff --git a/pollen-ui-riot-js/src/main/web/tag/PollenMessageManager.tag.html b/pollen-ui-riot-js/src/main/web/tag/PollenMessageManager.tag.html index 6b3854fa..d8fbabdc 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollenMessageManager.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/PollenMessageManager.tag.html @@ -31,8 +31,10 @@ }, message.timeout * 1000); }; + this.on("mount", () => { this.listen("message", this.handleMessages); + this.bus.trigger("messageManagerReady"); }); this.closeMessage = (messageId) => (e) => { diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html index 49e06b1c..29e16779 100644 --- a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html @@ -82,23 +82,21 @@ require("../components/HumanInput.tag.html"); e.preventDefault(); e.stopPropagation(); let loginProvider = this.loginProviders[index]; - this.confirm(this.__.deleteMessage).then((confirm) => { - if (confirm) { - if (!loginProvider.id) { - this.loginProviders.splice(index, 1); - this.availableLoginProviders.push(loginProvider.name); - this.availableLoginProviders.sort(); - this.update(); - } else { - authService.deleteLoginProvider(loginProvider).then(() => { - this.loginProviders.splice(index, 1); - this.availableLoginProviders.push(loginProvider.name); - this.availableLoginProviders.sort(); - this.update(); - }); + this.confirm(this.__.deleteMessage) + .then((confirm) => { + if (!confirm) { + return Promise.reject(); } - } - }); + if (confirm && loginProvider.id) { + return authService.deleteLoginProvider(loginProvider); + } + }) + .then(() => { + this.loginProviders.splice(index, 1); + this.availableLoginProviders.push(loginProvider.name); + this.availableLoginProviders.sort(); + this.update(); + }); }; this.saveLoginProvider = (index) => (e) => { -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 01639cf58db6b57ca78fe8097bd221f226005cc0 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 31 14:57:45 2017 +0200 refs #1 envoi d'un mail à la création d'un compte a partir d'un service tiers --- .../chorem/pollen/services/PollenUIContext.java | 10 +++ .../services/service/NotificationService.java | 11 ++++ .../pollen/services/service/SocialAuthService.java | 2 + .../pollen/services/service/mail/EmailService.java | 35 ++++++++++ .../mail/UserAccountCreatedFromProviderEmail.java | 76 ++++++++++++++++++++++ .../UserAccountCreatedFromProviderEmail.mustache | 10 +++ ...UserAccountCreatedFromProviderEmail_fr.mustache | 11 ++++ .../i18n/pollen-services_en_GB.properties | 20 ++++++ .../i18n/pollen-services_fr_FR.properties | 20 ++++++ .../service/PollenUIUrlRenderServiceTest.java | 1 + pollen-ui-riot-js/src/main/web/js/Session.js | 3 +- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 2 +- 12 files changed, 199 insertions(+), 2 deletions(-) diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/PollenUIContext.java b/pollen-services/src/main/java/org/chorem/pollen/services/PollenUIContext.java index b74ddd3a..c2bdcd61 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/PollenUIContext.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/PollenUIContext.java @@ -21,6 +21,8 @@ public class PollenUIContext implements Serializable { private String resourceDownloadUrl; + private String profileUrl; + public String getUiEndPoint() { return uiEndPoint; } @@ -76,4 +78,12 @@ public class PollenUIContext implements Serializable { public void setResourceDownloadUrl(String resourceDownloadUrl) { this.resourceDownloadUrl = resourceDownloadUrl; } + + public String getProfileUrl() { + return profileUrl; + } + + public void setProfileUrl(String profileUrl) { + this.profileUrl = profileUrl; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java index 50e62797..074c6198 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java @@ -29,6 +29,7 @@ import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollType; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.Report; +import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.Vote; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; @@ -51,6 +52,7 @@ import org.chorem.pollen.services.service.mail.PollReportForAdminEmail; import org.chorem.pollen.services.service.mail.ResendValidationEmail; import org.chorem.pollen.services.service.mail.RestrictedPollInvitationEmail; import org.chorem.pollen.services.service.mail.UserAccountCreatedEmail; +import org.chorem.pollen.services.service.mail.UserAccountCreatedFromProviderEmail; import org.chorem.pollen.services.service.mail.UserAccountDeletedEmail; import org.chorem.pollen.services.service.mail.UserAccountEditedEmail; import org.chorem.pollen.services.service.mail.UserAccountEmailValidatedEmail; @@ -81,6 +83,15 @@ public class NotificationService extends PollenServiceSupport { } } + public void onUserCreatedFromProvider(PollenUser user, UserCredential credential) { + if (StringUtils.isNotBlank(user.getEmail())) { + EmailService emailService = getEmailService(); + UserAccountCreatedFromProviderEmail email = emailService.newUserAccountCreatedFromProviderEmail(user, credential); + email.addTo(user.getEmail()); + emailService.send(email); + } + } + public void onResendValidation(PollenUser user) { EmailService emailService = getEmailService(); ResendValidationEmail email = emailService.newUserResendValidationEmail(user); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 8c9f7284..0132f818 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -81,6 +81,8 @@ public class SocialAuthService extends PollenServiceSupport { pollenUser = userDao.create(pollenUser); commit(); + + getNotificationService().onUserCreatedFromProvider(pollenUser, credential); } return getSecurityService().getSessionTokenForUser(pollenUser); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java index f1dbe453..eed9fe95 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java @@ -44,6 +44,7 @@ import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.PollenResource; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.Report; +import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.Vote; import org.chorem.pollen.services.bean.FeedbackBean; import org.chorem.pollen.services.bean.PollenEntityId; @@ -63,6 +64,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import static org.nuiton.i18n.I18n.n; +import static org.nuiton.i18n.I18n.t; + /** * Created on 4/30/14. * @@ -76,6 +80,28 @@ public class EmailService extends PollenServiceSupport { public static final String RECIPIENT_SEPARATOR = ";"; + static { + n("pollen.service.mail.loginProvider.amazon"); + n("pollen.service.mail.loginProvider.facebook"); + n("pollen.service.mail.loginProvider.flickr"); + n("pollen.service.mail.loginProvider.foursquare"); + n("pollen.service.mail.loginProvider.github"); + n("pollen.service.mail.loginProvider.googleplus"); + n("pollen.service.mail.loginProvider.hotmail"); + n("pollen.service.mail.loginProvider.instagram"); + n("pollen.service.mail.loginProvider.linkedin"); + n("pollen.service.mail.loginProvider.linkedin2"); + n("pollen.service.mail.loginProvider.mendeley"); + n("pollen.service.mail.loginProvider.myspace"); + n("pollen.service.mail.loginProvider.nimble"); + n("pollen.service.mail.loginProvider.runkeeper"); + n("pollen.service.mail.loginProvider.salesforce"); + n("pollen.service.mail.loginProvider.stackexchange"); + n("pollen.service.mail.loginProvider.twitter"); + n("pollen.service.mail.loginProvider.yahoo"); + n("pollen.service.mail.loginProvider.yammer"); + } + public ChoiceAddedEmail newChoiceAddedEmail(Poll poll, Choice choice) { ChoiceAddedEmail email = new ChoiceAddedEmail(getLocale()); email.setPoll(poll); @@ -213,6 +239,15 @@ public class EmailService extends PollenServiceSupport { return email; } + public UserAccountCreatedFromProviderEmail newUserAccountCreatedFromProviderEmail(PollenUser user, + UserCredential credential) { + UserAccountCreatedFromProviderEmail email = new UserAccountCreatedFromProviderEmail(getLocale()); + email.setUser(user); + email.setProvider(t("pollen.service.mail.loginProvider." + credential.getProvider())); + email.setProfileUrl(getUIContext().getProfileUrl()); + return email; + } + public UserAccountEditedEmail newUserAccountEditedEmail(PollenUser user) { UserAccountEditedEmail email = new UserAccountEditedEmail(getLocale()); email.setUser(user); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/UserAccountCreatedFromProviderEmail.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/UserAccountCreatedFromProviderEmail.java new file mode 100644 index 00000000..8f7adec3 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/UserAccountCreatedFromProviderEmail.java @@ -0,0 +1,76 @@ +package org.chorem.pollen.services.service.mail; + +/* + * #%L + * Pollen :: Service + * %% + * Copyright (C) 2009 - 2017 Code Lutin, Tony Chemit + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import org.chorem.pollen.persistence.entity.PollenUser; +import org.nuiton.i18n.I18n; + +import java.util.Locale; + +/** + * Created on 4/30/14. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 2.0 + */ +public class UserAccountCreatedFromProviderEmail extends PollenMail { + + private PollenUser user; + private String provider; + private String profileUrl; + + protected UserAccountCreatedFromProviderEmail(Locale locale) { + super(locale); + } + + @Override + public String getSubject() { + if (user.getName() == null) { + return I18n.l(locale, "pollen.service.mail.UserAccountCreatedFromProviderEmail.subject", user.getEmail()); + } + return I18n.l(locale, "pollen.service.mail.UserAccountCreatedFromProviderEmail.subject", user.getName()); + } + + public PollenUser getUser() { + return user; + } + + public void setUser(PollenUser user) { + this.user = user; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getProfileUrl() { + return profileUrl; + } + + public void setProfileUrl(String profileUrl) { + this.profileUrl = profileUrl; + } +} diff --git a/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail.mustache b/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail.mustache new file mode 100644 index 00000000..e477bd98 --- /dev/null +++ b/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail.mustache @@ -0,0 +1,10 @@ +Welcome {{user.name}}, + +You have just signed in for the first time with your {{provider}} account. + +A Pollen account has ben automatically created with your profile information: +Name: {{user.name}} +Email: {{user.email}} + +You can edit this information in the following page: {{profileUrl}} +You also can set a password to sign in to Pollen without using {{provider}}. \ No newline at end of file diff --git a/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail_fr.mustache b/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail_fr.mustache new file mode 100644 index 00000000..7619d044 --- /dev/null +++ b/pollen-services/src/main/resources/email/UserAccountCreatedFromProviderEmail_fr.mustache @@ -0,0 +1,11 @@ +Bonjour {{user.name}}, + +Vous venez de vous connecter à Pollen pour la première fois à partir de votre compte {{provider}}. + +Un compte Pollen a été automatiquement créé avec les informations de votre profil : + +Nom : {{user.name}} +Courriel : {{user.email}} + +Vous pouvez modifier ces informations sur la page suivante : {{profileUrl}} +Vous pouvez également renseigner un mot de passe pour pouvoir vous connecter à Pollen sans passer par {{provider}}. \ No newline at end of file diff --git a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties index aeb42167..b19d9a81 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties @@ -155,6 +155,7 @@ pollen.service.mail.PollVoteReminderEmail.subject=[Pollen] Reminder to vote on p pollen.service.mail.ResendValidationEmail.subject=[Pollen] Invitation to validate your account %s pollen.service.mail.RestrictedPollInvitationEmail.subject=[Pollen] Invitation to vote on poll %s pollen.service.mail.UserAccountCreatedEmail.subject=[Pollen] Confirmation of account creation %s +pollen.service.mail.UserAccountCreatedFromProviderEmail.subject=[Pollen] Confirmation of account creation %s pollen.service.mail.UserAccountDeletedEmail.subject=[Pollen] Confirmation of deletion of the account %s pollen.service.mail.UserAccountEditedEmail.subject=[Pollen] Update of the account %s pollen.service.mail.UserAccountEmailValidatedEmail.subject=[Pollen] Validation of your account %s @@ -164,3 +165,22 @@ pollen.service.mail.VoteDeletedEmail.subject=[Pollen] A vote was deleted in poll pollen.service.mail.VoteEditedEmail.subject=[Pollen] A vote was edited in poll %s pollen.service.mail.VoteSummaryEmail.subject=[Pollen] Summary of the votes since %s for the poll %s pollen.service.mail.feedbackEmail.subject=[Pollen] feedback - %s +pollen.service.mail.loginProvider.amazon=Amazon +pollen.service.mail.loginProvider.facebook=Facebook +pollen.service.mail.loginProvider.flickr=Flickr +pollen.service.mail.loginProvider.foursquare=Foursquare +pollen.service.mail.loginProvider.github=Github +pollen.service.mail.loginProvider.googleplus=Google +pollen.service.mail.loginProvider.hotmail=Hotmail +pollen.service.mail.loginProvider.instagram=Instagram +pollen.service.mail.loginProvider.linkedin=LinkedIn +pollen.service.mail.loginProvider.linkedin2=LinkedIn +pollen.service.mail.loginProvider.mendeley=Mendeley +pollen.service.mail.loginProvider.myspace=MySpace +pollen.service.mail.loginProvider.nimble=Nimble +pollen.service.mail.loginProvider.runkeeper=Runkeeper +pollen.service.mail.loginProvider.salesforce=Salesforce +pollen.service.mail.loginProvider.stackexchange=Stack Exchange +pollen.service.mail.loginProvider.twitter=Twitter +pollen.service.mail.loginProvider.yahoo=Yahoo +pollen.service.mail.loginProvider.yammer=Yammer diff --git a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties index 5cd63aff..ab2f93c8 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties @@ -154,6 +154,7 @@ pollen.service.mail.PollVoteReminderEmail.subject=[Pollen] Rappel du vote au son pollen.service.mail.ResendValidationEmail.subject=[Pollen] Validez votre compte %s pollen.service.mail.RestrictedPollInvitationEmail.subject=[Pollen] Invitation au sondage %s pollen.service.mail.UserAccountCreatedEmail.subject=[Pollen] Confirmation de création du compte %s +pollen.service.mail.UserAccountCreatedFromProviderEmail.subject=[Pollen] Confirmation de création du compte %s pollen.service.mail.UserAccountDeletedEmail.subject=[Pollen] Confirmation de suppression du compte %s pollen.service.mail.UserAccountEditedEmail.subject=[Pollen] Édition du compte %s pollen.service.mail.UserAccountEmailValidatedEmail.subject=[Pollen] Valiation de votre compte %s @@ -162,3 +163,22 @@ pollen.service.mail.VoteAddedEmail.subject=[Pollen] Un nouveau vote a été ajou pollen.service.mail.VoteDeletedEmail.subject=[Pollen] Un vote a été supprimé sur le sondage %s pollen.service.mail.VoteEditedEmail.subject=[Pollen] Un vote a été modifié du sondage %s pollen.service.mail.feedbackEmail.subject=[Pollen] retour utilisateur - %s +pollen.service.mail.loginProvider.amazon=Amazon +pollen.service.mail.loginProvider.facebook=Facebook +pollen.service.mail.loginProvider.flickr=Flickr +pollen.service.mail.loginProvider.foursquare=Foursquare +pollen.service.mail.loginProvider.github=Github +pollen.service.mail.loginProvider.googleplus=Google +pollen.service.mail.loginProvider.hotmail=Hotmail +pollen.service.mail.loginProvider.instagram=Instagram +pollen.service.mail.loginProvider.linkedin=LinkedIn +pollen.service.mail.loginProvider.linkedin2=LinkedIn +pollen.service.mail.loginProvider.mendeley=Mendeley +pollen.service.mail.loginProvider.myspace=MySpace +pollen.service.mail.loginProvider.nimble=Nimble +pollen.service.mail.loginProvider.runkeeper=Runkeeper +pollen.service.mail.loginProvider.salesforce=Salesforce +pollen.service.mail.loginProvider.stackexchange=Stack Exchange +pollen.service.mail.loginProvider.twitter=Twitter +pollen.service.mail.loginProvider.yahoo=Yahoo +pollen.service.mail.loginProvider.yammer=Yammer diff --git a/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java b/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java index 2081fc10..41517f1e 100644 --- a/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java +++ b/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java @@ -47,6 +47,7 @@ public class PollenUIUrlRenderServiceTest extends AbstractPollenServiceTest { pollenUIContext.setPollEditUrl(UI_END_POINT + "/#poll/edit/{pollId}/{token}"); pollenUIContext.setPollVoteUrl(UI_END_POINT + "/#poll/vote/{pollId}/{token}"); pollenUIContext.setPollVoteEditUrl(UI_END_POINT + "/#poll/vote/{pollId}/{voteId}/{token}"); + pollenUIContext.setProfileUrl(UI_END_POINT + "/#user/profile"); } @Test diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 77bcd203..57e5396e 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -46,7 +46,8 @@ class Session { pollVoteEditUrl: window.location.origin + "/#poll/{pollId}/vote/{voteId}/{token}", pollEditUrl: window.location.origin + "/#poll/{pollId}/edit/{token}", resourceUrl: this.configuration.endPoint + "/v1/resources/{resourceId}", - resourceDownloadUrl: this.configuration.endPoint + "/v1/resources/{resourceId}/download" + resourceDownloadUrl: this.configuration.endPoint + "/v1/resources/{resourceId}/download", + profileUrl: this.configuration.endPoint + "/#user/profile" }; // pour contenir les traductions this.i18n = { diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index f58786ac..10f992e7 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -52,7 +52,7 @@ require("./components/HumanInput.tag.html"); <div class="c-hint--static c-hint--error">{message}</div> <p><a onclick="{newPassword}">{__.lostpassword}</a></p> </div> - <div class="o-form-element align-center"> + <div class="o-form-element align-center" if="{loginProviders.length > 0}"> <p>Ou connectez vous avec votre compte :</p> <p> <a each="{loginProvider in loginProviders}" class="provider-link" -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 1a386c04b87a7c148a55aeb475f84cf2ea471ba0 Author: Kevin Morin <morin@codelutin.com> Date: Thu Aug 31 16:08:45 2017 +0200 refs #1 permettre l'ajout d'un mot de passe à des comptes créés à partir de service tiers --- .../java/org/chorem/pollen/services/bean/PollenUserBean.java | 12 +++++++++++- .../chorem/pollen/services/service/PollenUserService.java | 8 +++++--- .../service/security/PollenAuthenticationException.java | 4 ++++ .../pollen/services/service/security/SecurityService.java | 10 +++++++++- pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html | 11 ++++++++--- pollen-ui-riot-js/src/main/web/tag/poll/Polls.tag.html | 2 +- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java index 9bb64057..42d33279 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java @@ -46,6 +46,8 @@ public class PollenUserBean extends PollenBean<PollenUser> { protected boolean emailIsValidate; + protected boolean withPassword; + public PollenUserBean() { super(PollenUser.class); } @@ -62,7 +64,7 @@ public class PollenUserBean extends PollenBean<PollenUser> { setEmail(entity.getEmail()); setPassword(entity.getPassword()); setEmailIsValidate(entity.getEmailActivationToken() == null); - + setWithPassword(entity.getPassword() != null); } @Override @@ -136,4 +138,12 @@ public class PollenUserBean extends PollenBean<PollenUser> { public void setBanned(boolean banned) { this.banned = banned; } + + public boolean isWithPassword() { + return withPassword; + } + + public void setWithPassword(boolean withPassword) { + this.withPassword = withPassword; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java index b3cf72ef..5db9468d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java @@ -82,8 +82,11 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer checkIsConnected(); checkNotNull(userId); - PollenUser pollenUser = getUser0(userId); - + PollenUser pollenUser = getConnectedUser(); + if (!userId.equals(pollenUser.getTopiaId())) { + checkIsAdmin(); + pollenUser = getUser0(userId); + } return toBean(PollenUserBean.class, pollenUser, pollenUserFunction); } @@ -146,7 +149,6 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer String newPassword) throws InvalidFormException { checkNotNull(userId); - checkNotNull(oldPassword); checkNotNull(newPassword); PollenUser user = getUser0(userId); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenAuthenticationException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenAuthenticationException.java index f2635c8a..85ac88cd 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenAuthenticationException.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenAuthenticationException.java @@ -31,6 +31,10 @@ public class PollenAuthenticationException extends Exception { private static final long serialVersionUID = 1L; + public PollenAuthenticationException() { + super(); + } + public PollenAuthenticationException(Exception e) { super(e); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index 1ccb28bb..f351b350 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -25,6 +25,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.shiro.authc.AuthenticationException; @@ -125,6 +126,10 @@ public class SecurityService extends PollenServiceSupport { public PollenEntityRef<PollenUser> login(String login, String password, Boolean rememberMe) throws PollenAuthenticationException, PollenEmailNotValidatedException, PollenUserBannedException { + if (StringUtils.isBlank(password)) { + throw new PollenAuthenticationException(); + } + Subject subject = getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(login, password); if (rememberMe != null) { @@ -335,7 +340,10 @@ public class SecurityService extends PollenServiceSupport { public void checkUserPassword(PollenUser user, String password) throws PollenInvalidPasswordException { - String encodedPassword = serviceContext.encodePassword(user.getSalt(), password); + String encodedPassword = null; + if (password != null) { + encodedPassword = serviceContext.encodePassword(user.getSalt(), password); + } boolean valid = Objects.equals(encodedPassword, user.getPassword()); if (user.isBanned() || !valid) { throw new PollenInvalidPasswordException(); diff --git a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html index c06bed10..f7e2eda0 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html @@ -64,7 +64,7 @@ require("./components/HumanInput.tag.html"); <form ref="password-form" class="password-form"> <HumanInput onsubmit={submitPassword}/> <h3 class="c-heading"><i class="fa fa-key"/> {__.passwordChange}</h3> - <div class="o-form-element"> + <div class="o-form-element" if="{user.withPassword}"> <label class="c-label" for="oldPassword">{__.oldPassword}</label> <input class="c-field {c-field--error : errors.oldPassword}" type="password" @@ -131,6 +131,7 @@ require("./components/HumanInput.tag.html"); this.user = session.getUser() || {}; let userService = require("../js/UserService"); let authService = require("../js/AuthService"); + let Message = require("../js/Message"); this.onUserChange = (user) => { this.user = user || {}; @@ -170,13 +171,17 @@ require("./components/HumanInput.tag.html"); this.checkPassword(); if (this.errors.repeatPassword === undefined) { - let oldPassword = this.refs.oldPassword.value; + let oldPassword = this.user.withPassword ? this.refs.oldPassword.value : null; let newPassword = this.refs.newPassword.value; userService.changePassword(this.user.id, oldPassword, newPassword).then(() => { - this.refs.oldPassword.value = ""; + if (this.user.withPassword) { + this.refs.oldPassword.value = ""; + } this.refs.newPassword.value = ""; this.refs.repeatPassword.value = ""; + this.user.withPassword = true; this.update(); + this.bus.trigger("message", new Message(this._l("updatedPassword"), "success")); }) .catch((errors) => { this.errors = errors; diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Polls.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Polls.tag.html index 6f403e32..8fb9e3e7 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Polls.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Polls.tag.html @@ -96,7 +96,7 @@ require("../components/Search.tag.html"); return pollService.assignPoll(finds[1], finds[2]).then((result) => { if (result) { this.refresh(); - this.bus.trigger("message", new Message(this._l("assignSuccessMessage", result.title), "succes")); + this.bus.trigger("message", new Message(this._l("assignSuccessMessage", result.title), "success")); } else { this.bus.trigger("message", new Message(this.__.alreadyAssignMessage, "warning")); } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit ef68f13ec531f3bbbf6ee5f376c6806cb8d17835 Author: Kevin Morin <morin@codelutin.com> Date: Mon Sep 4 15:21:58 2017 +0200 refs #1 permettre d'ajouter des comptes tiers à un compte existant --- .../persistence/entity/UserCredentialTopiaDao.java | 30 +++++++ .../db/migration/h2/V3_0_0_8__add_credentials.sql | 1 + .../postgresql/V3_0_0_8__add_credentials.sql | 1 + pollen-persistence/src/main/xmi/pollen.zargo | Bin 28069 -> 28138 bytes .../pollen/rest/api/PollenRestApiApplication.java | 4 +- .../PollenEmailAlreadyUsedExceptionMapper.java | 20 ----- ...rProviderAccountAlreadyUsedExceptionMapper.java | 20 +++++ .../org/chorem/pollen/rest/api/v1/ApiUtils.java | 2 + .../org/chorem/pollen/rest/api/v1/AuthApi.java | 11 ++- .../chorem/pollen/rest/api/v1/PollenUserApi.java | 39 +++++++-- .../pollen/services/bean/PollenUserBean.java | 21 +++++ .../pollen/services/bean/UserCredentialBean.java | 49 +++++++++++ .../pollen/services/service/PollenUserService.java | 1 + .../pollen/services/service/SocialAuthService.java | 90 +++++++++++++++++---- .../security/PollenEmailAlreadyUsedException.java | 11 --- ...EmailOrProviderAccountAlreadyUsedException.java | 11 +++ 16 files changed, 249 insertions(+), 62 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/UserCredentialTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/UserCredentialTopiaDao.java new file mode 100644 index 00000000..68302fed --- /dev/null +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/UserCredentialTopiaDao.java @@ -0,0 +1,30 @@ +package org.chorem.pollen.persistence.entity; + +import java.util.HashMap; +import java.util.Map; + +public class UserCredentialTopiaDao extends AbstractUserCredentialTopiaDao<UserCredential> { + + public boolean isCredentialValid(String provider, String credentialUserId, String userTopiaId, String email) { + String query = "SELECT COUNT(*)" + + " FROM " + PollenUser.class.getName() + " AS user RIGHT JOIN user." + PollenUser.PROPERTY_USER_CREDENTIAL + " AS credential" + + " WHERE" + + " (credential." + UserCredential.PROPERTY_PROVIDER + " = :provider" + + " AND credential." + UserCredential.PROPERTY_USER_ID + " = :credentialUserId)"; + if (email != null) { + query += " OR (user." + PollenUser.PROPERTY_TOPIA_ID + " = :userTopiaId" + + " AND credential." + UserCredential.PROPERTY_EMAIL + " = :credentialEmail)" + + " OR user." + PollenUser.PROPERTY_EMAIL + " = :userEmail"; + } + + Map<String, Object> params = new HashMap<>(); + params.put("provider", provider); + params.put("credentialUserId", credentialUserId); + if (email != null) { + params.put("userEmail", email); + params.put("userTopiaId", userTopiaId); + params.put("credentialEmail", email); + } + return count(query, params) == 0; + } +} diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql index 1825b8ae..48fadea4 100644 --- a/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_0_0_8__add_credentials.sql @@ -6,6 +6,7 @@ CREATE TABLE USERCREDENTIAL ( TOPIACREATEDATE TIMESTAMP, PROVIDER VARCHAR(255), USERID VARCHAR(255), + USERNAME VARCHAR(255), EMAIL VARCHAR(255), POLLENUSER VARCHAR(255), FOREIGN KEY (POLLENUSER) references POLLENUSER(TOPIAID) diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql index 2280308e..d1f2803d 100644 --- a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_0_0_8__add_credentials.sql @@ -6,6 +6,7 @@ CREATE TABLE USERCREDENTIAL ( TOPIACREATEDATE TIMESTAMP, PROVIDER VARCHAR(255), USERID VARCHAR(255), + USERNAME VARCHAR(255), EMAIL VARCHAR(255), POLLENUSER VARCHAR(255), FOREIGN KEY (POLLENUSER) references POLLENUSER(TOPIAID) diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index 0f29e782..7ce056d6 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java index 271b223a..687e4f38 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplication.java @@ -7,7 +7,7 @@ import org.chorem.pollen.rest.api.exceptionMappers.FavoriteListImportExceptionMa import org.chorem.pollen.rest.api.exceptionMappers.InvalidEntityLinkExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.InvalidFormExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenAuthenticationExceptionMapper; -import org.chorem.pollen.rest.api.exceptionMappers.PollenEmailAlreadyUsedExceptionMapper; +import org.chorem.pollen.rest.api.exceptionMappers.PollenEmailOrProviderAccountAlreadyUsedExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenEmailNotValidatedExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenInvalidEmailActivationTokenExceptionMapper; import org.chorem.pollen.rest.api.exceptionMappers.PollenInvalidPermissionExceptionMapper; @@ -62,7 +62,7 @@ public class PollenRestApiApplication extends Application { new PollenInvalidPermissionExceptionMapper(), new PollenInvalidEmailActivationTokenExceptionMapper(), new PollenEmailNotValidatedExceptionMapper(), - new PollenEmailAlreadyUsedExceptionMapper(), + new PollenEmailOrProviderAccountAlreadyUsedExceptionMapper(), new PollenUserBannedExceptionMapper(), new InvalidFormExceptionMapper(), new FavoriteListImportExceptionMapper(), diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java deleted file mode 100644 index 3b1ec37b..00000000 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailAlreadyUsedExceptionMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.chorem.pollen.rest.api.exceptionMappers; - -import org.chorem.pollen.services.service.security.PollenEmailAlreadyUsedException; - -import javax.ws.rs.core.Response; - -/** - * @author Sylvain Bavencoff - bavencoff@codelutin.com - */ -public class PollenEmailAlreadyUsedExceptionMapper extends PollenAbstractExceptionMapper<PollenEmailAlreadyUsedException> { - - public PollenEmailAlreadyUsedExceptionMapper() { - super(Response.Status.FORBIDDEN); - } - - @Override - protected Object getEntity(PollenEmailAlreadyUsedException exception) { - return "emailAlreadyUsed"; - } -} diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailOrProviderAccountAlreadyUsedExceptionMapper.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailOrProviderAccountAlreadyUsedExceptionMapper.java new file mode 100644 index 00000000..d6671c68 --- /dev/null +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/exceptionMappers/PollenEmailOrProviderAccountAlreadyUsedExceptionMapper.java @@ -0,0 +1,20 @@ +package org.chorem.pollen.rest.api.exceptionMappers; + +import org.chorem.pollen.services.service.security.PollenEmailOrProviderAccountAlreadyUsedException; + +import javax.ws.rs.core.Response; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class PollenEmailOrProviderAccountAlreadyUsedExceptionMapper extends PollenAbstractExceptionMapper<PollenEmailOrProviderAccountAlreadyUsedException> { + + public PollenEmailOrProviderAccountAlreadyUsedExceptionMapper() { + super(Response.Status.FORBIDDEN); + } + + @Override + protected Object getEntity(PollenEmailOrProviderAccountAlreadyUsedException exception) { + return "emailOrProviderAccountAlreadyUsed"; + } +} diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/ApiUtils.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/ApiUtils.java index cebdb51c..dec31e1b 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/ApiUtils.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/ApiUtils.java @@ -27,6 +27,8 @@ import java.util.regex.Pattern; */ public class ApiUtils { + public static final String SOCIAL_AUTH_MANAGER_SESSION_KEY = "socialAuthManager"; + public static Response exportBeanToResponse(ExportBean exportBean) { InputStream inputStream = IOUtils.toInputStream(exportBean.getContent(), Charsets.UTF_8); diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index fc2ac99b..776a4f6c 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -80,7 +80,6 @@ public class AuthApi { public static final String COOKIE_POLLEN_AUTH = "pollen-auth"; private static final String COOKIE_POLLEN_CONNECTED = "pollen-connected"; private static final int COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year - private static final String SOCIAL_AUTH_MANAGER_SESSION_KEY = "socialAuthManager"; public static Response.ResponseBuilder removeAuthCookie(Response.ResponseBuilder reponseBuilder) { @@ -203,7 +202,7 @@ public class AuthApi { throws Exception { SocialAuthManager socialAuthManager = socialAuthService.getSocialAuthManager(); - request.getSession(true).setAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY, socialAuthManager); + request.getSession(true).setAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY, socialAuthManager); return socialAuthManager.getAuthenticationUrl(providerId, providerRedirection); } @@ -214,15 +213,15 @@ public class AuthApi { @Context SecurityService securityService, @Context PollenSecurityContext securityContext, @Context HttpServletRequest request, - @HeaderParam("authorization") String authorization) + String providerReturn) throws Exception { SocialAuthManager socialAuthManager = - (SocialAuthManager) request.getSession().getAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY); + (SocialAuthManager) request.getSession().getAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); //socialAuthManager - request.getSession().removeAttribute(SOCIAL_AUTH_MANAGER_SESSION_KEY); + request.getSession().removeAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); Gson gson = new Gson(); - Map<String, String> paramsMap = gson.fromJson(authorization, Map.class); + Map<String, String> paramsMap = gson.fromJson(providerReturn, Map.class); PollenEntityRef<PollenUser> userPollenEntityRef = socialAuthService.login(socialAuthManager, paramsMap); return getLoginResponseFromPollenUser(serviceContext, securityService, securityContext, userPollenEntityRef); diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java index 123e13c3..188b9ea7 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java @@ -21,7 +21,10 @@ package org.chorem.pollen.rest.api.v1; * #L% */ +import com.google.gson.Gson; +import org.brickred.socialauth.SocialAuthManager; import org.chorem.pollen.persistence.entity.PollenUser; +import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.rest.api.beans.ChangePasswordBean; import org.chorem.pollen.services.bean.PaginationParameterBean; import org.chorem.pollen.services.bean.PaginationResultBean; @@ -30,9 +33,11 @@ import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.PollenUserBean; import org.chorem.pollen.services.service.InvalidFormException; import org.chorem.pollen.services.service.PollenUserService; +import org.chorem.pollen.services.service.SocialAuthService; import org.chorem.pollen.services.service.security.PollenInvalidEmailActivationTokenException; import org.chorem.pollen.services.service.security.PollenSecurityContext; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.BeanParam; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -45,6 +50,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import java.util.Map; import java.util.Objects; /** @@ -65,7 +71,6 @@ public class PollenUserApi { @QueryParam("search") String search) { return pollenUserService.getUsers(paginationParameter, search); - } @Path("/users/connected") @@ -74,7 +79,6 @@ public class PollenUserApi { PollenUser pollenUser = securityContext.getPollenUser(); Objects.requireNonNull(pollenUser,"Could not find connected user"); return pollenUserService.getUser(pollenUser.getTopiaId()); - } @Path("/users/{userId}") @@ -83,7 +87,6 @@ public class PollenUserApi { @PathParam("userId") PollenEntityId<PollenUser> userId) { return pollenUserService.getUser(userId.getEntityId()); - } @Path("/users") @@ -92,7 +95,6 @@ public class PollenUserApi { PollenUserBean user) throws InvalidFormException { return pollenUserService.createUser(user); - } @Path("/users/{userId}") @@ -101,7 +103,6 @@ public class PollenUserApi { PollenUserBean user) throws InvalidFormException { return pollenUserService.editUser(user); - } @Path("/users/{userId}") @@ -111,7 +112,6 @@ public class PollenUserApi { @QueryParam("anonymize") boolean anonymize) { pollenUserService.deleteUser(userId.getEntityId(), anonymize); - } @Path("/users/{userId}") @@ -121,7 +121,6 @@ public class PollenUserApi { @QueryParam("token") String token) throws PollenInvalidEmailActivationTokenException { pollenUserService.validateUserEmail(userId.getEntityId(), token); - } @Path("/users/{userId}/password") @@ -131,6 +130,32 @@ public class PollenUserApi { ChangePasswordBean bean) throws InvalidFormException { pollenUserService.changePassword(userId.getEntityId(), bean.getOldPassword(), bean.getNewPassword()); + } + + @Path("/users/{userId}/credentials/{provider}") + @POST + public String addUserCredential(@Context SocialAuthService socialAuthService, + @Context HttpServletRequest request, + @PathParam("userId") PollenEntityId<PollenUser> userId, + @PathParam("provider") String provider, + String providerReturn) throws Exception { + + SocialAuthManager socialAuthManager = + (SocialAuthManager) request.getSession().getAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); + //socialAuthManager + request.getSession().removeAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); + Gson gson = new Gson(); + Map<String, String> paramsMap = gson.fromJson(providerReturn, Map.class); + return socialAuthService.addCredentialToUser(userId, socialAuthManager, paramsMap); + } + + @Path("/users/{userId}/credentials/{credentialId}") + @DELETE + public void deleteUserCredential(@Context SocialAuthService socialAuthService, + @Context HttpServletRequest request, + @PathParam("userId") PollenEntityId<PollenUser> userId, + @PathParam("credentialId") PollenEntityId<UserCredential> credentialId) throws Exception { + socialAuthService.deleteUserCredential(userId, credentialId); } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java index 42d33279..d167d9eb 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java @@ -24,6 +24,10 @@ package org.chorem.pollen.services.bean; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.PollenUserImpl; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + /** * Created on 5/15/14. * @@ -48,6 +52,8 @@ public class PollenUserBean extends PollenBean<PollenUser> { protected boolean withPassword; + protected List<UserCredentialBean> credentials = new ArrayList<>(); + public PollenUserBean() { super(PollenUser.class); } @@ -65,6 +71,13 @@ public class PollenUserBean extends PollenBean<PollenUser> { setPassword(entity.getPassword()); setEmailIsValidate(entity.getEmailActivationToken() == null); setWithPassword(entity.getPassword() != null); + setCredentials(entity.getUserCredential().stream() + .map(userCredential -> { + UserCredentialBean userCredentialBean = new UserCredentialBean(); + userCredentialBean.fromEntity(userCredential); + return userCredentialBean; + }) + .collect(Collectors.toList())); } @Override @@ -146,4 +159,12 @@ public class PollenUserBean extends PollenBean<PollenUser> { public void setWithPassword(boolean withPassword) { this.withPassword = withPassword; } + + public List<UserCredentialBean> getCredentials() { + return credentials; + } + + public void setCredentials(List<UserCredentialBean> credentials) { + this.credentials = credentials; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java new file mode 100644 index 00000000..d88f3444 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java @@ -0,0 +1,49 @@ +package org.chorem.pollen.services.bean; + +import org.chorem.pollen.persistence.entity.UserCredential; +import org.chorem.pollen.persistence.entity.UserCredentialImpl; + +/** + * @author Kevin Morin (Code Lutin) + */ +public class UserCredentialBean extends PollenBean<UserCredential> { + + protected String provider; + protected String userName; + + protected UserCredentialBean() { + super(UserCredential.class); + } + + @Override + public void fromEntity(UserCredential entity) { + setEntityId(entity.getTopiaId()); + setProvider(entity.getProvider()); + setUserName(entity.getUserName()); + } + + @Override + public UserCredential toEntity() { + UserCredential entity = new UserCredentialImpl(); + entity.setTopiaId(getEntityId()); + entity.setProvider(getProvider()); + entity.setUserName(getUserName()); + return entity; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java index 5db9468d..ae57949f 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java @@ -137,6 +137,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer anonymizeUser(user); } + getUserCredentialDao().deleteAll(user.getUserCredential()); getPollenUserDao().delete(user); commit(); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java index 0132f818..bfa301af 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/SocialAuthService.java @@ -16,9 +16,12 @@ import org.chorem.pollen.persistence.entity.PollenUserImpl; import org.chorem.pollen.persistence.entity.PollenUserTopiaDao; import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.UserCredentialImpl; +import org.chorem.pollen.persistence.entity.UserCredentialTopiaDao; import org.chorem.pollen.services.bean.LoginProviderBean; +import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; -import org.chorem.pollen.services.service.security.PollenEmailAlreadyUsedException; +import org.chorem.pollen.services.service.security.PollenEmailOrProviderAccountAlreadyUsedException; +import org.chorem.pollen.services.service.security.PollenUnauthorizedException; import java.util.ArrayList; import java.util.List; @@ -46,30 +49,26 @@ public class SocialAuthService extends PollenServiceSupport { PollenUserTopiaDao userDao = getPollenUserDao(); Optional<PollenUser> pollenUserForCredential = userDao.tryFindUserWithCredential(p.getProviderId(), p.getValidatedId()); - String name = p.getDisplayName(); - if (name == null) { - name = p.getFirstName() + " " + p.getLastName(); - } - if (pollenUserForCredential.isPresent()) { - if (log.isInfoEnabled()) { - log.info("credentials found : " + name); + if (log.isDebugEnabled()) { + log.debug("credentials found"); } pollenUser = pollenUserForCredential.get(); } else if (userDao.emailExists(p.getEmail())) { - throw new PollenEmailAlreadyUsedException(); + throw new PollenEmailOrProviderAccountAlreadyUsedException(); } else { - if (log.isInfoEnabled()) { - log.info("create new user : " + name); + String name = p.getFullName(); + if (name == null) { + name = p.getFirstName() + " " + p.getLastName(); + } + + if (log.isDebugEnabled()) { + log.debug("create new user : " + name); } - UserCredential credential = new UserCredentialImpl(); - credential.setProvider(p.getProviderId()); - credential.setUserId(p.getValidatedId()); - credential.setEmail(p.getEmail()); - credential = getUserCredentialDao().create(credential); + UserCredential credential = createUserCredential(p); pollenUser = new PollenUserImpl(); pollenUser.setName(name); @@ -88,6 +87,51 @@ public class SocialAuthService extends PollenServiceSupport { return getSecurityService().getSessionTokenForUser(pollenUser); } + public String addCredentialToUser(PollenEntityId<PollenUser> userId, + SocialAuthManager manager, + Map<String, String> paramsMap) throws Exception { + + checkIsConnected(); + PollenUser connectedUser = getConnectedUser(); + if (!connectedUser.getTopiaId().equals(userId.getEntityId())) { + throw new PollenUnauthorizedException(userId.getReducedId()); + } + + AuthProvider provider = manager.connect(paramsMap); + + // get profile + Profile p = provider.getUserProfile(); + + boolean credentialValid = getUserCredentialDao().isCredentialValid(p.getProviderId(), + p.getValidatedId(), + connectedUser.getTopiaId(), + p.getEmail()); + if (!credentialValid) { + throw new PollenEmailOrProviderAccountAlreadyUsedException(); + } + + UserCredential credential = createUserCredential(p); + connectedUser.addUserCredential(credential); + commit(); + + return credential.getUserName(); + } + + protected UserCredential createUserCredential(Profile p) { + String accountName = p.getDisplayName(); + if (accountName == null) { + accountName = p.getFullName(); + } + + UserCredential credential = new UserCredentialImpl(); + credential.setProvider(p.getProviderId()); + credential.setUserId(p.getValidatedId()); + credential.setUserName(accountName); + credential.setEmail(p.getEmail()); + credential = getUserCredentialDao().create(credential); + return credential; + } + public SocialAuthManager getSocialAuthManager() throws Exception { //Create an instance of SocialAuthConfgi object SocialAuthConfig config = SocialAuthConfig.getDefault(); @@ -185,4 +229,18 @@ public class SocialAuthService extends PollenServiceSupport { dao.delete(dao.forTopiaIdEquals(providerId).findUnique()); commit(); } + + public void deleteUserCredential(PollenEntityId<PollenUser> userId, PollenEntityId<UserCredential> credentialId) { + checkNotNull(credentialId); + + checkIsConnected(); + PollenUser connectedUser = getConnectedUser(); + if (!connectedUser.getTopiaId().equals(userId.getEntityId())) { + throw new PollenUnauthorizedException(userId.getReducedId()); + } + + UserCredentialTopiaDao dao = getUserCredentialDao(); + dao.delete(dao.forTopiaIdEquals(credentialId.getEntityId()).findUnique()); + commit(); + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java deleted file mode 100644 index afd67772..00000000 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailAlreadyUsedException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.chorem.pollen.services.service.security; - -/** - * @author Kevin Morin (Code Lutin) - */ -public class PollenEmailAlreadyUsedException extends Exception { - - public PollenEmailAlreadyUsedException() { - super("emailAlreadyUsed"); - } -} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailOrProviderAccountAlreadyUsedException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailOrProviderAccountAlreadyUsedException.java new file mode 100644 index 00000000..cb5bf239 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenEmailOrProviderAccountAlreadyUsedException.java @@ -0,0 +1,11 @@ +package org.chorem.pollen.services.service.security; + +/** + * @author Kevin Morin (Code Lutin) + */ +public class PollenEmailOrProviderAccountAlreadyUsedException extends Exception { + + public PollenEmailOrProviderAccountAlreadyUsedException() { + super("emailOrProviderAccountAlreadyUsed"); + } +} -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 0975e601980fb223ec2691e40008a085b20df618 Author: Kevin Morin <morin@codelutin.com> Date: Tue Sep 5 16:08:48 2017 +0200 refs #1 ajout de credentials depuis le profil --- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 2 +- pollen-ui-riot-js/src/main/web/js/AuthService.js | 19 ++++++-- pollen-ui-riot-js/src/main/web/js/Session.js | 2 +- pollen-ui-riot-js/src/main/web/js/UserService.js | 11 +++++ pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 35 +++++++++++--- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 28 +++-------- .../src/main/web/tag/UserProfile.tag.html | 56 ++++++++++++++++++++-- .../src/main/web/tag/admin/Users.tag.html | 4 +- 8 files changed, 118 insertions(+), 39 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index 776a4f6c..f7cc206a 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -216,7 +216,7 @@ public class AuthApi { String providerReturn) throws Exception { - SocialAuthManager socialAuthManager = + (SocialAuthManager) request.getSession().getAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); //socialAuthManager request.getSession().removeAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 3fd1d1f1..aed4e7c4 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -25,6 +25,20 @@ class AuthService extends FetchService { constructor() { super(); + this.providerIcons = { + "amazon": "amazon", + "facebook": "facebook-official", + "flickr": "flickr", + "foursquare": "foursquare", + "github": "github", + "googleplus": "google", + "instagram": "instagram", + "linkedin": "linkedin", + "linkedin2": "linkedin", + "stackexchange": "stack-exchange", + "twitter": "twitter", + "yahoo": "yahoo" + }; } signIn(login, password) { @@ -73,10 +87,9 @@ class AuthService extends FetchService { } signInProvider(query) { - return this.fetch( + return this.post( "/v1/login/" + query.loginProvider, - "POST", - {Authorization: JSON.stringify(query)}); + JSON.stringify(query)); } getAllLoginProviders() { diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 57e5396e..83049c93 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -174,7 +174,7 @@ class Session { } getProviderRedirectionUrl(provider) { - return this.pollenUIContext.uiEndPoint + "/?loginProvider=" + provider; + return this.pollenUIContext.uiEndPoint + "/?loginProvider=" + provider + "&action=signin"; } } diff --git a/pollen-ui-riot-js/src/main/web/js/UserService.js b/pollen-ui-riot-js/src/main/web/js/UserService.js index 58fe4c6e..32735ae2 100644 --- a/pollen-ui-riot-js/src/main/web/js/UserService.js +++ b/pollen-ui-riot-js/src/main/web/js/UserService.js @@ -62,6 +62,17 @@ class UserService extends FetchService { return this.post(url, body); } + linkProvider(userId, query) { + let url = this._getUrlPrefix(userId) + "/credentials/" + query.loginProvider; + let body = JSON.stringify(query); + return this.post(url, body); + } + + + unlinkProvider(userId, credentialId) { + let url = this._getUrlPrefix(userId) + "/credentials/" + credentialId; + return this.doDelete(url); + } } module.exports = singleton(UserService); diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index a64d7482..dbcddc0d 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -53,9 +53,11 @@ require("./popup/InformationPopup.tag.html"); <script type="es6"> let session = require("../js/Session"); - session.start(); this.installBundle(session, "main"); + + session.start(); this.pageTitle = undefined; + let userService = require("../js/UserService"); this.onLocaleChange = () => { this.updatePageTitle(); @@ -135,7 +137,7 @@ require("./popup/InformationPopup.tag.html"); }); route("/poll", () => { - if (!session.isConnected() && !session.getUser.administrator) { + if (!session.isConnected() && !session.getUser().administrator) { route("/signin?url=/poll"); } else { this.bus.trigger("pageChanged", "admin_polls"); @@ -144,7 +146,7 @@ require("./popup/InformationPopup.tag.html"); }); route("/user", () => { - if (!session.isConnected() && !session.getUser.administrator) { + if (!session.isConnected() && !session.getUser().administrator) { route("/signin?url=/user"); } else { this.bus.trigger("pageChanged", "admin_users"); @@ -233,19 +235,40 @@ require("./popup/InformationPopup.tag.html"); route(() => { var q = route.query(); if (q.loginProvider != null) { + if (q.action === "signin") { session.signInProvider(q).then(() => { let currentPage = localStorage.getItem("currentPage"); localStorage.removeItem("currentPage"); - location.href = session.pollenUIContext.uiEndPoint + "/" + currentPage; + location.replace(session.pollenUIContext.uiEndPoint + "/" + currentPage); }, (e) => { let currentPage = localStorage.getItem("currentPage"); localStorage.removeItem("currentPage"); - console.log(e); e.text().then(label => { - location.href = session.pollenUIContext.uiEndPoint + "/" + currentPage + "?error=" + label; + location.replace(session.pollenUIContext.uiEndPoint + "/" + currentPage + "?error=" + label); }); }); + } else if (q.action === "link" && session.isConnected()) { + let callback = (user) => { + userService.linkProvider(user.id, q).then((accountName) => { + location.replace(session.pollenUIContext.uiEndPoint + "/#user/profile"); + }, (e) => { + e.text().then(label => { + location.replace(session.pollenUIContext.uiEndPoint + "/#user/profile?error=" + label); + }); + }); + }; + + if (session.getUser()) { + callback(session.getUser()); + } else { + this.bus.on("user", (user) => { + callback(user); + this.bus.off("user", callback); + }); + } + } + } else { this.bus.trigger("pageChanged", "home"); riot.mount(this.refs.content, "home"); diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index 10f992e7..ada0bdf3 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -53,12 +53,12 @@ require("./components/HumanInput.tag.html"); <p><a onclick="{newPassword}">{__.lostpassword}</a></p> </div> <div class="o-form-element align-center" if="{loginProviders.length > 0}"> - <p>Ou connectez vous avec votre compte :</p> + <p>{__.signinWithProvider}</p> <p> <a each="{loginProvider in loginProviders}" class="provider-link" onclick="{signinWithProvider(loginProvider)}"> - <i class="fa fa-{providerIcons[loginProvider]}" if="{providerIcons[loginProvider]}"></i> - <span if="{!providerIcons[loginProvider]}">{loginProvider}</span> + <i class="fa fa-{authService.providerIcons[loginProvider]}" if="{authService.providerIcons[loginProvider]}"></i> + <span if="{!authService.providerIcons[loginProvider]}">{loginProvider}</span> </a> </p> </div> @@ -81,25 +81,10 @@ require("./components/HumanInput.tag.html"); this.message = ""; this.openSignIn = false; - this.providerIcons = { - "amazon": "amazon", - "facebook": "facebook-official", - "flickr": "flickr", - "foursquare": "foursquare", - "github": "github", - "googleplus": "google", - "instagram": "instagram", - "linkedin": "linkedin", - "linkedin2": "linkedin", - "stackexchange": "stack-exchange", - "twitter": "twitter", - "yahoo": "yahoo" - }; - - let authService = require("../js/AuthService"); + this.authService = require("../js/AuthService"); this.loginProviders = []; this.on("mount", () => { - authService.getActiveLoginProviders().then((result) => { + this.authService.getActiveLoginProviders().then((result) => { this.loginProviders = result; this.update(); }); @@ -140,9 +125,8 @@ require("./components/HumanInput.tag.html"); this.signinWithProvider = (provider) => (e) => { let currentPage = location.hash || "#"; localStorage.setItem("currentPage", currentPage); - let authService = require("../js/AuthService"); let redirection = encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); - authService.getLoginProviderUrl(provider, redirection).then(result => { + this.authService.getLoginProviderUrl(provider, redirection).then(result => { location.href = result; }); }; diff --git a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html index f7e2eda0..d036bbe2 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html @@ -59,6 +59,28 @@ require("./components/HumanInput.tag.html"); {__.saveIdentity} </button> </div> + + <div> + <div each="{credential in user.credentials}" class="credential"> + <i if="{authService.providerIcons[credential.provider]}" + class="fa fa-{authService.providerIcons[credential.provider]}"></i> + <span if="{!authService.providerIcons[credential.provider]}">{credential.userName}</span> + <span>{credential.userName}</span> + <a if="{user.withPassword && user.email || user.credentials.length > 1}" + onclick="{unlinkProvider(credential.id)}">X</a> + </div> + </div> + + <div class="o-form-element align-center" if="{loginProviders.length > 0}"> + <p>{__.linkProvider}</p> + <p> + <a each="{loginProvider in loginProviders}" class="provider-link" + onclick="{linkProvider(loginProvider)}"> + <i class="fa fa-{authService.providerIcons[loginProvider]}" if="{authService.providerIcons[loginProvider]}"></i> + <span if="{!authService.providerIcons[loginProvider]}">{loginProvider}</span> + </a> + </p> + </div> </form> <form ref="password-form" class="password-form"> @@ -130,16 +152,22 @@ require("./components/HumanInput.tag.html"); this.errors = {}; this.user = session.getUser() || {}; let userService = require("../js/UserService"); - let authService = require("../js/AuthService"); + this.authService = require("../js/AuthService"); let Message = require("../js/Message"); + this.loginProviders = []; + this.authService.getActiveLoginProviders().then((result) => { + this.loginProviders = result; + this.update(); + }); + this.onUserChange = (user) => { this.user = user || {}; this.update(); }; this.resendValidation = () => { - authService.resendValidation(this.user.email); + this.authService.resendValidation(this.user.email); }; this.submitIdentity = e => { @@ -179,8 +207,8 @@ require("./components/HumanInput.tag.html"); } this.refs.newPassword.value = ""; this.refs.repeatPassword.value = ""; - this.user.withPassword = true; this.update(); + session.updateUser(); this.bus.trigger("message", new Message(this._l("updatedPassword"), "success")); }) .catch((errors) => { @@ -190,6 +218,20 @@ require("./components/HumanInput.tag.html"); } }; + this.linkProvider = (provider) => (e) => { + let redirection = encodeURIComponent(location.origin + location.pathname + + "?loginProvider=" + provider + "&action=link"); + this.authService.getLoginProviderUrl(provider, redirection).then(result => { + location.assign(result); + }); + }; + + this.unlinkProvider = (credentialId) => (e) => { + userService.unlinkProvider(this.user.id, credentialId).then(result => { + console.log("ok"); + }); + }; + this.listen("user", this.onUserChange); </script> @@ -208,6 +250,14 @@ require("./components/HumanInput.tag.html"); padding: 0 5px; } + .credential { + font-size: 1.5em; + } + + .provider-link { + font-size: 2em; + } + </style> </UserProfile> diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html index 286538ad..fa33c0f6 100644 --- a/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/Users.tag.html @@ -47,11 +47,9 @@ require("./UserCard.tag.html"); this.lazyLoad = pagination => { return userService.users(pagination, this.search.value).then((result) => { - if (!this.loaded) { + this.loaded = true; this.count = result.pagination.count; - this.loaded = true; this.update(); - } return result; }); }; -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 8e108414b4bfd6a54dbf38c0cb3c176dbf64f4a5 Author: Kevin Morin <morin@codelutin.com> Date: Tue Sep 5 16:48:06 2017 +0200 fix build --- .../main/java/org/chorem/pollen/rest/api/v1/AuthApi.java | 2 +- .../org/chorem/pollen/services/bean/PollenUserBean.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index f7cc206a..776a4f6c 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -216,7 +216,7 @@ public class AuthApi { String providerReturn) throws Exception { - + SocialAuthManager socialAuthManager = (SocialAuthManager) request.getSession().getAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); //socialAuthManager request.getSession().removeAttribute(ApiUtils.SOCIAL_AUTH_MANAGER_SESSION_KEY); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java index d167d9eb..e1a28095 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenUserBean.java @@ -71,13 +71,15 @@ public class PollenUserBean extends PollenBean<PollenUser> { setPassword(entity.getPassword()); setEmailIsValidate(entity.getEmailActivationToken() == null); setWithPassword(entity.getPassword() != null); - setCredentials(entity.getUserCredential().stream() - .map(userCredential -> { - UserCredentialBean userCredentialBean = new UserCredentialBean(); - userCredentialBean.fromEntity(userCredential); - return userCredentialBean; - }) - .collect(Collectors.toList())); + if (entity.getUserCredential() != null) { + setCredentials(entity.getUserCredential().stream() + .map(userCredential -> { + UserCredentialBean userCredentialBean = new UserCredentialBean(); + userCredentialBean.fromEntity(userCredential); + return userCredentialBean; + }) + .collect(Collectors.toList())); + } } @Override -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 6e891e738403a7413e977ca566411d1e9b5260b9 Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 10:48:45 2017 +0200 refs #1 mise en page des comptes externes dans le profil --- .../pollen/services/bean/UserCredentialBean.java | 11 ++++ pollen-ui-riot-js/src/main/web/css/custom.css | 2 + .../src/main/web/tag/UserProfile.tag.html | 73 +++++++++++++++------- 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java index d88f3444..85b44ae1 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/UserCredentialBean.java @@ -10,6 +10,7 @@ public class UserCredentialBean extends PollenBean<UserCredential> { protected String provider; protected String userName; + protected String emailAddress; protected UserCredentialBean() { super(UserCredential.class); @@ -20,6 +21,7 @@ public class UserCredentialBean extends PollenBean<UserCredential> { setEntityId(entity.getTopiaId()); setProvider(entity.getProvider()); setUserName(entity.getUserName()); + setEmailAddress(entity.getEmail()); } @Override @@ -28,6 +30,7 @@ public class UserCredentialBean extends PollenBean<UserCredential> { entity.setTopiaId(getEntityId()); entity.setProvider(getProvider()); entity.setUserName(getUserName()); + entity.setEmail(getEmailAddress()); return entity; } @@ -46,4 +49,12 @@ public class UserCredentialBean extends PollenBean<UserCredential> { public void setUserName(String userName) { this.userName = userName; } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } } diff --git a/pollen-ui-riot-js/src/main/web/css/custom.css b/pollen-ui-riot-js/src/main/web/css/custom.css index 5dd7b38c..dbbd4d85 100644 --- a/pollen-ui-riot-js/src/main/web/css/custom.css +++ b/pollen-ui-riot-js/src/main/web/css/custom.css @@ -93,4 +93,6 @@ --report: rgba(0,0,0,0.05); --report-hover: #04c4bb; + + --list-alternate-row: #f3f3f3; } diff --git a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html index d036bbe2..3f30abfd 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html @@ -59,28 +59,6 @@ require("./components/HumanInput.tag.html"); {__.saveIdentity} </button> </div> - - <div> - <div each="{credential in user.credentials}" class="credential"> - <i if="{authService.providerIcons[credential.provider]}" - class="fa fa-{authService.providerIcons[credential.provider]}"></i> - <span if="{!authService.providerIcons[credential.provider]}">{credential.userName}</span> - <span>{credential.userName}</span> - <a if="{user.withPassword && user.email || user.credentials.length > 1}" - onclick="{unlinkProvider(credential.id)}">X</a> - </div> - </div> - - <div class="o-form-element align-center" if="{loginProviders.length > 0}"> - <p>{__.linkProvider}</p> - <p> - <a each="{loginProvider in loginProviders}" class="provider-link" - onclick="{linkProvider(loginProvider)}"> - <i class="fa fa-{authService.providerIcons[loginProvider]}" if="{authService.providerIcons[loginProvider]}"></i> - <span if="{!authService.providerIcons[loginProvider]}">{loginProvider}</span> - </a> - </p> - </div> </form> <form ref="password-form" class="password-form"> @@ -142,6 +120,32 @@ require("./components/HumanInput.tag.html"); </button> </div> </form> + + <div class="providers"> + <h3 class="c-heading"><i class="fa fa-sign-in"/> {__.loginProviders}</h3> + <div class="user-credentials"> + <div each="{credential, index in user.credentials}" class="user-credential {index % 2 == 0 ? 'even' : 'odd'}"> + <i if="{authService.providerIcons[credential.provider]}" + class="fa fa-{authService.providerIcons[credential.provider]}"></i> + <span if="{!authService.providerIcons[credential.provider]}">{credential.userName}</span> + <span class="credential-name">{credential.userName} <em if="{credential.emailAddress}">({credential.emailAddress})</em></span> + <button if="{user.withPassword && user.email || user.credentials.length > 1}" + onclick="{unlinkProvider(credential.id)}" class="c-button u-small c-button--error"><i class="fa fa-trash"></i></button> + </div> + </div> + + <div class="o-form-element align-center" if="{loginProviders.length > 0}"> + <p>{__.linkProvider}</p> + <p> + <a each="{loginProvider in loginProviders}" class="provider-link" + onclick="{linkProvider(loginProvider)}"> + <i class="fa fa-{authService.providerIcons[loginProvider]}" if="{authService.providerIcons[loginProvider]}"></i> + <span if="{!authService.providerIcons[loginProvider]}">{loginProvider}</span> + </a> + </p> + </div> + </div> + </div> </div> @@ -250,8 +254,29 @@ require("./components/HumanInput.tag.html"); padding: 0 5px; } - .credential { - font-size: 1.5em; + .providers { + padding: 0 10px; + } + + .user-credentials { + width: 100%; + } + + .user-credential { + display: flex; + justify-content: space-around; + align-items: center; + margin: 1px 0; + padding: 1px 5px; + } + + .user-credential.odd { + background-color: var(--list-alternate-row); + } + + .credential-name { + flex-grow: 1; + padding: 0 5px; } .provider-link { -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit f4cb642f147d1e8bb098fae4f27fc655d2d81a70 Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 11:01:10 2017 +0200 refs #1 gestion de la suppression des credentials --- pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html | 14 ++++++++++---- .../src/main/web/tag/admin/LoginProviders.tag.html | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html index 3f30abfd..19256cf4 100644 --- a/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/UserProfile.tag.html @@ -130,7 +130,7 @@ require("./components/HumanInput.tag.html"); <span if="{!authService.providerIcons[credential.provider]}">{credential.userName}</span> <span class="credential-name">{credential.userName} <em if="{credential.emailAddress}">({credential.emailAddress})</em></span> <button if="{user.withPassword && user.email || user.credentials.length > 1}" - onclick="{unlinkProvider(credential.id)}" class="c-button u-small c-button--error"><i class="fa fa-trash"></i></button> + onclick="{unlinkProvider(credential.id, index)}" class="c-button u-small c-button--error"><i class="fa fa-trash"></i></button> </div> </div> @@ -230,9 +230,15 @@ require("./components/HumanInput.tag.html"); }); }; - this.unlinkProvider = (credentialId) => (e) => { - userService.unlinkProvider(this.user.id, credentialId).then(result => { - console.log("ok"); + this.unlinkProvider = (credentialId, index) => (e) => { + this.confirm(this.__.unlinkProviderMessage).then((confirm) => { + if (!confirm) { + return Promise.reject(); + } + return userService.unlinkProvider(this.user.id, credentialId) + }).then(result => { + this.user.credentials.splice(index, 1); + this.update(); }); }; diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html index 29e16779..883c0b24 100644 --- a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html @@ -87,7 +87,7 @@ require("../components/HumanInput.tag.html"); if (!confirm) { return Promise.reject(); } - if (confirm && loginProvider.id) { + if (loginProvider.id) { return authService.deleteLoginProvider(loginProvider); } }) -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit aa85995120122bfe8cd0a84099f3ef6457ad882e Author: Kevin Morin <morin@codelutin.com> Date: Thu Sep 7 11:22:15 2017 +0200 refs #1 séparaion des langues --- pollen-ui-riot-js/src/main/web/i18n/en.json | 20 +++++++++++++++++++- pollen-ui-riot-js/src/main/web/i18n/fr.json | 20 +++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/i18n/en.json b/pollen-ui-riot-js/src/main/web/i18n/en.json index 16119427..c6ab170c 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/en.json +++ b/pollen-ui-riot-js/src/main/web/i18n/en.json @@ -12,6 +12,7 @@ "main_editPoll" : "Poll edition", "main_userProfile" : "My profile", "main_favoriteLists" : "List of favorites", + "main_emailOrProviderAccountAlreadyUsed": "The email address of the account you are connecting with is already used by another Pollen account.", "pagination_all": "All", "pagination_resultsPerPage": "Results per page", "summary_choices": "Choices", @@ -198,6 +199,7 @@ "signin_password_placeholder": "Enter your password", "signin_lostpassword": "Lost password?", "signin_connexion": "Connect", + "signin_signinWithProvider": "Or sign in with your account:", "signin_error_signin_emailOrPasswordInvalid": "Email or password invalid", "signin_error_signin_banned": "Bloked account", "signin_error_signin_emailNotValidated": "You must validate your account before connecting. Check your emails, we sent you an activation link.", @@ -222,6 +224,7 @@ "header_myParticipatedPolls": "Participated polls", "header_polls": "Polls", "header_users": "Users", + "header_loginProviders": "Login providers", "header_myFavoriteLists": "My favorite lists", "header_createOtherPoll": "New standard poll", "header_createDatePoll": "New date poll", @@ -387,6 +390,10 @@ "userProfile_repeatPassword_placeholder": "Confirm your new password", "userProfile_repeatPassword_error": "The two passwords are not identical.", "userProfile_savePassword": "Save", + "userProfile_updatedPassword": "Your password has been updated", + "userProfile_loginProviders": "External accounts", + "userProfile_linkProvider": "Link an external account to connect to Pollen:", + "userProfile_unlinkProviderMessage": "Unlink this external account? You will not be able to connect to your Pollen account with this external account.", "choice_description_placeholder": "You can enter a description for this choice", "date-picker_today": "Today", "date-picker_dateplaceholder": "Date", @@ -532,5 +539,16 @@ "feedback_description": "Thank to details below your bug report ou your observation", "feedback_descriptionNotBlank": "Observation must be not blank", "feedback_uploadScreenShot": "Screenshot", - "feedback_create_success": "Observation has benn send." + "feedback_create_success": "Observation has been send.", + "loginProviders_title": "Login provider", + "loginProviders_name": "Name", + "loginProviders_key": "Client key", + "loginProviders_secret": "Secret code", + "loginProviders_permissions": "Permissions", + "loginProviders_active": "Active", + "loginProviders_newProvider": "New provider", + "loginProviders_deleteMessage": "Are you sure you want to delete this provider?", + "loginProviders_emptyName": "The name is mandatory", + "loginProviders_emptyKey": "The client key is mandatory", + "loginProviders_emptySecret": "The secret code is mandatory" } diff --git a/pollen-ui-riot-js/src/main/web/i18n/fr.json b/pollen-ui-riot-js/src/main/web/i18n/fr.json index 00ac76f8..6f528757 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/fr.json +++ b/pollen-ui-riot-js/src/main/web/i18n/fr.json @@ -12,6 +12,7 @@ "main_editPoll" : "Edition du sondage", "main_userProfile" : "Mon profil", "main_favoriteLists" : "Listes de votants", + "main_emailOrProviderAccountAlreadyUsed": "L'adresse email du compte avec lequel vous essayez de vous connecter, est déjà utilisée par un autre compte Pollen.", "pagination_all": "Tous", "pagination_resultsPerPage": "Résultats par page", "summary_choices": "Choix", @@ -198,6 +199,7 @@ "signin_password_placeholder": "Entrez votre mot de passe", "signin_lostpassword": "Mot de passe perdu ?", "signin_connexion": "Se connecter", + "signin_signinWithProvider": "Ou connectez vous avec votre compte :", "signin_error_signin_emailOrPasswordInvalid": "Courriel ou mot de passe invalide", "signin_error_signin_banned": "Compte bloqué", "signin_error_signin_emailNotValidated": "Vous devez valider votre compte avant de pouvoir vous connecter. Relevez vos emails, nous vous avons envoyé un lien de validation.", @@ -222,6 +224,7 @@ "header_myParticipatedPolls": "Mes participations", "header_polls": "Sondages", "header_users": "Utilisateurs", + "header_loginProviders": "Tiers de connexion", "header_myFavoriteLists": "Mes listes de votants", "header_createOtherPoll": "Nouveau sondage standard", "header_createDatePoll": "Nouveau sondage de dates", @@ -387,6 +390,10 @@ "userProfile_repeatPassword_placeholder": "Répétez votre mot de passe", "userProfile_repeatPassword_error": "Les deux mots de passe ne sont pas identiques.", "userProfile_savePassword": "Enregistrer", + "userProfile_updatedPassword": "Votre mot de passe a été mis à jour", + "userProfile_loginProviders": "Comptes externes", + "userProfile_linkProvider": "Associez un compte externe pour vous connecter à Pollen :", + "userProfile_unlinkProviderMessage": "Désassossier ce compte externe ? Vous ne pourrez plus vous connectez à votre compte Pollen avec ce compte externe.", "choice_description_placeholder": "Vous pouvez saisir une description pour ce choix", "date-picker_today": "Aujourd'hui", "date-picker_dateplaceholder": "Date", @@ -532,5 +539,16 @@ "feedback_description": "Merci de détailler ci-dessous votre rapport de bug ou votre remarque", "feedback_descriptionNotBlank": "La description ne doit pas être blanc", "feedback_uploadScreenShot": "Copie d'écran", - "feedback_create_success": "La remarque est envoyée." + "feedback_create_success": "La remarque est envoyée.", + "loginProviders_title": "Tiers pour la connexion", + "loginProviders_name": "Nom", + "loginProviders_key": "Clé client", + "loginProviders_secret": "Code secret", + "loginProviders_permissions": "Permissions", + "loginProviders_active": "Actif", + "loginProviders_newProvider": "Nouveau tiers", + "loginProviders_deleteMessage": "Êtes-vous sûr de vouloir supprimer ce tier ?", + "loginProviders_emptyName": "Le nom est obligatoire", + "loginProviders_emptyKey": "La clé client est obligatoire", + "loginProviders_emptySecret": "Le code secret est obligatoire" } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm