branch keycloak created (now c9d9752d)
This is an automated email from the git hooks/post-receive script. New change to branch keycloak in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git at c9d9752d mise en place de keycloak This branch includes the following new commits: new c9d9752d mise en place de keycloak The 1 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 c9d9752d5c60beb3de83bf91a7925422cb157e22 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Thu Jul 27 15:48:28 2017 +0200 mise en place de keycloak -- 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 keycloak in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit c9d9752d5c60beb3de83bf91a7925422cb157e22 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Thu Jul 27 15:48:28 2017 +0200 mise en place de keycloak --- pollen-rest-api/pom.xml | 5 ++ .../pollen/rest/api/PollenKeycloakFilter.java | 26 ++++++++++ .../rest/api/PollenRestApiRequestFilter.java | 45 ++++++++++++----- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 4 ++ .../src/main/webapp/WEB-INF/keycloak.json | 12 +++++ pollen-rest-api/src/main/webapp/WEB-INF/web.xml | 11 +++- pollen-services/pom.xml | 12 +++++ pollen-services/src/main/config/PollenServices.ini | 22 +++++++- .../services/config/PollenServicesConfig.java | 21 ++++++++ .../service/security/KeycloakSecurityService.java | 40 +++++++++++++++ .../services/service/ssl/LazySSLSocketFactory.java | 58 ++++++++++++++++++++++ .../services/service/ssl/LazyTrustManager.java | 24 +++++++++ .../i18n/pollen-services_en_GB.properties | 4 ++ .../i18n/pollen-services_fr_FR.properties | 4 ++ pollen-ui-riot-js/package.json | 3 +- pollen-ui-riot-js/src/main/web/conf.js | 7 ++- pollen-ui-riot-js/src/main/web/js/FetchService.js | 7 ++- pollen-ui-riot-js/src/main/web/js/Session.js | 39 +++++++++++++++ pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 15 +++++- .../src/main/web/tag/PollenHeader.tag.html | 2 +- pom.xml | 24 +++++++++ 21 files changed, 365 insertions(+), 20 deletions(-) diff --git a/pollen-rest-api/pom.xml b/pollen-rest-api/pom.xml index 1509b6fd..658cb066 100644 --- a/pollen-rest-api/pom.xml +++ b/pollen-rest-api/pom.xml @@ -225,6 +225,11 @@ </dependency> <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-servlet-filter-adapter</artifactId> + </dependency> + + <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenKeycloakFilter.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenKeycloakFilter.java new file mode 100644 index 00000000..8c7af8d7 --- /dev/null +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenKeycloakFilter.java @@ -0,0 +1,26 @@ +package org.chorem.pollen.rest.api; + +import org.keycloak.adapters.servlet.KeycloakOIDCFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class PollenKeycloakFilter extends KeycloakOIDCFilter { + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) req; + if ("OPTIONS".equals(request.getMethod())) { + chain.doFilter(req, res); + } else { + super.doFilter(req, res, chain); + } + } +} 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 5ee83aa9..66bdfef8 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 @@ -48,11 +48,14 @@ import org.chorem.pollen.services.service.VoteCountingTypeService; import org.chorem.pollen.services.service.VoteService; import org.chorem.pollen.services.service.VoterListService; import org.chorem.pollen.services.service.mail.EmailService; +import org.chorem.pollen.services.service.security.KeycloakSecurityService; import org.chorem.pollen.services.service.security.PollenCypherTechnicalException; import org.chorem.pollen.services.service.security.PollenInvalidSessionTokenException; import org.chorem.pollen.services.service.security.PollenSecurityContext; import org.chorem.pollen.services.service.security.SecurityService; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.representations.AccessToken; import javax.ws.rs.HttpMethod; import javax.ws.rs.container.ContainerRequestContext; @@ -123,7 +126,7 @@ public class PollenRestApiRequestFilter implements ContainerRequestFilter, Conta if (StringUtils.isNotBlank(requestHeaders)) { headers.add(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders); } else { - headers.add(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, " + REQUEST_HEADER_UI_CONTEXT); + headers.add(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, " + REQUEST_HEADER_UI_CONTEXT + "," + REQUEST_HEADER_SESSION_TOKEN); } } @@ -191,28 +194,46 @@ public class PollenRestApiRequestFilter implements ContainerRequestFilter, Conta private PollenSecurityContext createSecurityContext(ContainerRequestContext context, PollenRestApiApplicationContext applicationContext, PollenServiceContext serviceContext) throws PollenInvalidSessionTokenException, PollenCypherTechnicalException { + SessionToken sessionToken = null; SecurityService securityService = serviceContext.newService(SecurityService.class); - // --- get session token (from request parameters) --- // - String sessionTokenHeader = context.getHeaderString(REQUEST_HEADER_SESSION_TOKEN); + if (applicationContext.getApplicationConfig().isKeycloakEnabled()) { - if (StringUtils.isEmpty(sessionTokenHeader)) { + KeycloakPrincipal principal = (KeycloakPrincipal) context.getSecurityContext().getUserPrincipal(); - // --- get session token (from request cookies) --- // - Cookie cookie = context.getCookies().get(COOKIE_POLLEN_AUTH); - if (cookie != null) { + if (principal != null) { - if (log.isDebugEnabled()) { - log.debug("Found pollen-auth cookie:: " + cookie.getValue()); + AccessToken token = principal.getKeycloakSecurityContext().getToken(); + + KeycloakSecurityService keycloakSecurityService = serviceContext.newService(KeycloakSecurityService.class); + + sessionToken = keycloakSecurityService.getSessionToken(token); + + } + + } else { + + // --- get session token (from request parameters) --- // + String sessionTokenHeader = context.getHeaderString(REQUEST_HEADER_SESSION_TOKEN); + + if (StringUtils.isEmpty(sessionTokenHeader)) { + + // --- get session token (from request cookies) --- // + Cookie cookie = context.getCookies().get(COOKIE_POLLEN_AUTH); + if (cookie != null) { + + if (log.isDebugEnabled()) { + log.debug("Found pollen-auth cookie:: " + cookie.getValue()); + } + sessionTokenHeader = securityService.decrypt(cookie.getValue()); } - sessionTokenHeader = securityService.decrypt(cookie.getValue()); + } + sessionToken = securityService.getSessionTokenByToken(sessionTokenHeader); } - SessionToken sessionToken = securityService.getSessionTokenByToken(sessionTokenHeader); - // --- get mainPrincipal (from request parameters) --- // String permission = null; List<String> permissions = context.getUriInfo().getQueryParameters().get(REQUEST_PERMISSION_PARAMETER); 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 b6eb9330..fb9a1a5d 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 @@ -67,7 +67,11 @@ public class AuthApi { private static final Log log = LogFactory.getLog(AuthApi.class); public static final String COOKIE_POLLEN_AUTH = "pollen-auth"; + private static final String COOKIE_POLLEN_CONNECTED = "pollen-connected"; + + public static final String COOKIE_POLLEN_KEYCLOAK_CODE = "pollen-keycloak-code"; + private final static int COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year public static Response.ResponseBuilder removeAuthCookie(Response.ResponseBuilder reponseBuilder) { diff --git a/pollen-rest-api/src/main/webapp/WEB-INF/keycloak.json b/pollen-rest-api/src/main/webapp/WEB-INF/keycloak.json new file mode 100644 index 00000000..faf5e37d --- /dev/null +++ b/pollen-rest-api/src/main/webapp/WEB-INF/keycloak.json @@ -0,0 +1,12 @@ +{ + "realm" : "Pollen", + "realm-public-key" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArN3gue13jJBaFP+oZkAAIok+ksgeB3sv5aWujSu04Y+IsT+ZF/W1obocuwkHVvxcXN/wLlTE+SgT3vo7s1st+XokI2zhjPoJM8tpUFoOiSeeaO/jgG/9B+bRiY9R8KieZe+yZsqmHuOsQb0zR2RCfw29po95FKN0uql90uZ0eSSnE8zCN7BMpj39ElC3ui/FEG8MVQKm1ECZ2RcGfbifMCIjmeHYaHjXp0pp6uz1cOH1h0pOQJ1qnAlfwRW6EwPZT5oyNPbOJSg+1PIaNw5BrrZhtxTFe2CkhEahyillsMxCHR1s7pPy7K7qpCPv+5TJgTnzkwWXcIfxK0GT/fM9HQIDAQAB", + "bearer-only" : true, + "auth-server-url" : "http://localhost:8088/auth", + "ssl-required" : "external", + "resource" : "pollen-back", + "use-resource-role-mappings" : false, + "credentials" : { + "secret" : "acadc8bb-c09c-47cb-8e96-aab3de98b6b0" + } +} diff --git a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml index d8a94176..67f8d25d 100644 --- a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml +++ b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml @@ -27,7 +27,16 @@ http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name>Pollen REST Api</display-name> - + + <filter> + <filter-name>Keycloak Filter</filter-name> + <filter-class>org.chorem.pollen.rest.api.PollenKeycloakFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>Keycloak Filter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + <filter> <filter-name>topiaTransaction</filter-name> <filter-class> diff --git a/pollen-services/pom.xml b/pollen-services/pom.xml index a17b864f..a78d5484 100644 --- a/pollen-services/pom.xml +++ b/pollen-services/pom.xml @@ -213,6 +213,18 @@ <groupId>org.jboss.spec.javax.ws.rs</groupId> <artifactId>jboss-jaxrs-api_2.0_spec</artifactId> </dependency> + + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-authz-client</artifactId> + </dependency> + + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-core</artifactId> + </dependency> + + </dependencies> diff --git a/pollen-services/src/main/config/PollenServices.ini b/pollen-services/src/main/config/PollenServices.ini index 93c92d2c..9224f5ce 100644 --- a/pollen-services/src/main/config/PollenServices.ini +++ b/pollen-services/src/main/config/PollenServices.ini @@ -181,4 +181,24 @@ type = String description = pollen.configuration.feedback.locale key = pollen.feedback.locale type = String -defaultValue = en \ No newline at end of file +defaultValue = en + +[option keycloakServer] +description = pollen.configuration.keycloak.server +key = pollen.keycloak.server +type = String + +[option keycloakRealm] +description = pollen.configuration.keycloak.realm +key = pollen.keycloak.realm +type = String + +[option keycloakResource] +description = pollen.configuration.keycloak.resource +key = pollen.keycloak.resource +type = String + +[option keycloakSecret] +description = pollen.configuration.keycloak.secret +key = pollen.keycloak.secret +type = String \ No newline at end of file diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java b/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java index bca8228d..5839af78 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java @@ -33,9 +33,11 @@ import org.chorem.pollen.persistence.entity.PollType; import org.chorem.pollen.persistence.entity.ResultVisibility; import org.chorem.pollen.persistence.entity.VoteVisibility; import org.chorem.pollen.services.PollenTechnicalException; +import org.keycloak.authorization.client.Configuration; import org.nuiton.config.ApplicationConfig; import org.nuiton.config.ArgumentsParserException; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; @@ -147,4 +149,23 @@ public class PollenServicesConfig extends GeneratedPollenServicesConfig { public Locale getFeedbackLocale() { return Locale.forLanguageTag(get().getOption(PollenServicesConfigOption.LOCALE_FEEDBACK.getKey())); } + + public boolean isKeycloakEnabled() { + return getKeycloakServer() != null; + } + + public Configuration getKeycloackConfig() { + Configuration result = null; + + if (isKeycloakEnabled()) { + result = new Configuration( + getKeycloakServer(), + getKeycloakRealm(), + getKeycloakResource(), + Collections.singletonMap("secret", getKeycloakSecret()), + null); + + } + return result; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/KeycloakSecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/KeycloakSecurityService.java new file mode 100644 index 00000000..781d4a23 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/KeycloakSecurityService.java @@ -0,0 +1,40 @@ +package org.chorem.pollen.services.service.security; + +import com.google.common.base.Optional; +import org.chorem.pollen.persistence.entity.PollenUser; +import org.chorem.pollen.persistence.entity.PollenUserImpl; +import org.chorem.pollen.persistence.entity.SessionToken; +import org.chorem.pollen.persistence.entity.SessionTokenImpl; +import org.chorem.pollen.services.service.PollenServiceSupport; +import org.keycloak.representations.AccessToken; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class KeycloakSecurityService extends PollenServiceSupport { + + public SessionToken getSessionToken(AccessToken accessToken) { + + SessionToken sessionToken = new SessionTokenImpl(); + + Optional<PollenUser> pollenUserOptional = getPollenUserDao().forEmailEquals(accessToken.getEmail()).tryFindUnique(); + PollenUser pollenUser = pollenUserOptional.or(() -> createFromAccessToken(accessToken)); + + sessionToken.setPollenUser(pollenUser); + return sessionToken; + } + + protected PollenUser createFromAccessToken(AccessToken accessToken) { + + PollenUser user = new PollenUserImpl(); + user.setEmail(accessToken.getEmail()); + user.setName(accessToken.getName()); + user.setAdministrator(accessToken.getRealmAccess().isUserInRole("pollen-administrator")); + user.isEmailValidated(); + user = getPollenUserDao().create(user); + commit(); + return user; + } + + +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazySSLSocketFactory.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazySSLSocketFactory.java new file mode 100644 index 00000000..c6561287 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazySSLSocketFactory.java @@ -0,0 +1,58 @@ +package org.chorem.pollen.services.service.ssl; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class LazySSLSocketFactory extends SSLSocketFactory { + private SSLSocketFactory factory; + public LazySSLSocketFactory() { + try { + SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init( + null, // No KeyManager required + new TrustManager[] { new LazyTrustManager() }, + new java.security.SecureRandom()); + factory = (SSLSocketFactory) sslcontext.getSocketFactory(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + public static SocketFactory getDefault() { + return new LazySSLSocketFactory(); + } + public Socket createSocket() throws IOException { + return factory.createSocket(); + } + public Socket createSocket(Socket socket, String s, int i, boolean flag) + throws IOException { + return factory.createSocket(socket, s, i, flag); + } + public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, + int j) throws IOException { + return factory.createSocket(inaddr, i, inaddr1, j); + } + public Socket createSocket(InetAddress inaddr, int i) throws IOException { + return factory.createSocket(inaddr, i); + } + public Socket createSocket(String s, int i, InetAddress inaddr, int j) + throws IOException { + return factory.createSocket(s, i, inaddr, j); + } + public Socket createSocket(String s, int i) throws IOException { + return factory.createSocket(s, i); + } + public String[] getDefaultCipherSuites() { + return factory.getSupportedCipherSuites(); + } + public String[] getSupportedCipherSuites() { + return factory.getSupportedCipherSuites(); + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazyTrustManager.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazyTrustManager.java new file mode 100644 index 00000000..da5ffc74 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/ssl/LazyTrustManager.java @@ -0,0 +1,24 @@ +package org.chorem.pollen.services.service.ssl; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class LazyTrustManager implements X509TrustManager { + public boolean isClientTrusted(X509Certificate[] cert) { + return true; + } + public boolean isServerTrusted(X509Certificate[] cert) { + return true; + } + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + public void checkClientTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException {} + public void checkServerTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException {} +} 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 1ba0fd60..45dab200 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 @@ -21,6 +21,10 @@ pollen.configuration.defaultVoteVisibility=Default vote visiblity pollen.configuration.devMode=Dev mode pollen.configuration.feedback.locale=locale to send feedback pollen.configuration.feedback.mails=mails to send feedback +pollen.configuration.keycloak.realm= +pollen.configuration.keycloak.resource= +pollen.configuration.keycloak.secret= +pollen.configuration.keycloak.server= pollen.configuration.logConfigurationFile=Path to log configuration file pollen.configuration.registration.emailAddressPattern=Regular expression that the user email address must match for registration pollen.configuration.report.maxScore=Maximum score for reporting before administrators are notified 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 497bc4ab..d33b8118 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 @@ -21,6 +21,10 @@ pollen.configuration.defaultVoteVisibility=Visibilité des votes par défaut pollen.configuration.devMode=Mode développement pollen.configuration.feedback.locale=La locale pour envoyer les retours utlisateur pollen.configuration.feedback.mails=Courriel destinataires des retours utilisateur +pollen.configuration.keycloak.realm= +pollen.configuration.keycloak.resource= +pollen.configuration.keycloak.secret= +pollen.configuration.keycloak.server= pollen.configuration.logConfigurationFile=Chemin vers le fichier de configuration des logs pollen.configuration.registration.emailAddressPattern=Expression régulière que doivent vérifier les adresses email des utilisateurs lors de l'inscription pollen.configuration.report.maxScore=Score maximum pour un signalement avant que les administrateurs soient avertis diff --git a/pollen-ui-riot-js/package.json b/pollen-ui-riot-js/package.json index 27c1099c..ac343781 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 felteu:8080", "package": "webpack --bail" }, "devDependencies": { @@ -45,6 +45,7 @@ "console.history": "^1.5.0", "font-awesome": "4.7.0", "html2canvas": "^0.5.0-beta4", + "keycloak": "^1.2.0", "moment": "^2.17.1", "nprogress": "^0.2.0", "object.values": "^1.0.4", diff --git a/pollen-ui-riot-js/src/main/web/conf.js b/pollen-ui-riot-js/src/main/web/conf.js index 5b5da95d..422b3499 100644 --- a/pollen-ui-riot-js/src/main/web/conf.js +++ b/pollen-ui-riot-js/src/main/web/conf.js @@ -3,5 +3,10 @@ window.pollenConf = { piwikUrl: "", // add the piwik url, eg: http://localhost/piwik piwikSiteId: "", // add the site id, eg: 3 defaultMessageTimeout: 15, - resourceMaxSize: 10000000 // octets => 10 Mo + resourceMaxSize: 10000000, // octets => 10 Mo + keycloak: { + url: "http://localhost:8088/auth", + realm: "Pollen", + clientId: "pollen" + } }; 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 64146ff7..51b284e2 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -21,6 +21,7 @@ let bus = require("./PollenBus.js"); + class FetchService { constructor() { @@ -28,11 +29,15 @@ class FetchService { } fetch(url, method, headers, body) { + let session = require("./Session"); headers = headers || {}; if (!(body instanceof FormData)) { headers["Content-Type"] = "application/json;charset=UTF-8"; } - headers["X-Pollen-UI-context"] = JSON.stringify(require("./Session").pollenUIContext); + headers["X-Pollen-UI-context"] = JSON.stringify(session.pollenUIContext); + if (session.keycloak && session.keycloak.token) { + headers.Authorization = "Bearer " + session.keycloak.token; + } let loadEvent = {}; bus.trigger("loading", loadEvent); 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 67fed2ef..a3991d9d 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -24,6 +24,7 @@ let authService = require("./AuthService"); let bus = require("./PollenBus.js"); let logger = require("./Logger"); let pageTracker = require("./PageTracker"); +let Keycloak = require("keycloak"); class Session { @@ -75,6 +76,37 @@ class Session { this.user = null; bus.trigger("user", this.user); }); + + + if (this.configuration.keycloak) { + this.keycloak = new Keycloak(this.configuration.keycloak); + this.keycloak.init({checkLoginIframe: false}).success(authenticated => { + if (authenticated) { + this.keycloak.loadUserProfile().success(user => { + this.user = { + name: user.username, + administrator: this.keycloak.hasRealmRole("pollen-administrator"), + email: user.email, + isDisabled: !user.enabled, + isBanned: false, + emailIsValidate: user.emailVerified, + language: user.toLocaleString() + }; + document.cookie = "pollen-connected=true"; + bus.trigger("user", this.user); + logger.info(user); + }).error(error => { + logger.error("failed to load user", error); + }); + } else { + this.user = null; + bus.trigger("user", this.user); + } + logger.info(authenticated ? "authenticated" : "not authenticated"); + }).error(() => { + logger.error("failed to initialize"); + }); + } } start() { @@ -147,6 +179,9 @@ class Session { } signOut() { + if (this.configuration.keycloak) { + this.keycloak.logout({redirectUri: window.location.href}); + } return authService.signOut().then(() => { this.user = null; bus.trigger("user", this.user); @@ -154,6 +189,10 @@ class Session { }); } + keycloakLogin() { + this.keycloak.login({redirectUri: window.location.href}); + } + } 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..a2baf8af 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 @@ -73,7 +73,13 @@ require("./popup/InformationPopup.tag.html"); this.on("mount", () => { this.listen("locale", this.onLocaleChange); this.listen("unauthorize", this.refs.signIn.open); - this.listen("signIn", this.refs.signIn.open); + this.listen("signIn", () => { + if (session.configuration.keycloak) { + session.keycloakLogin(); + } else { + this.refs.signIn.open(); + } + }); this.listen("closeSignIn", this.refs.signIn.close); }); @@ -190,7 +196,7 @@ require("./popup/InformationPopup.tag.html"); riot.mount(this.refs.content, "editpoll", {pollId: pollId, permission: permission, clone: true}); }); route("/poll/*/summary/*", (pollId, permission) => { - riot.mount(this.refs.content, "editpoll", {pollId: pollId, permission: permission, showSummary:true}); + riot.mount(this.refs.content, "editpoll", {pollId: pollId, permission: permission, showSummary: true}); }); route("/poll/*", (pollId) => { riot.mount(this.refs.content, "poll", {pollId: pollId}); @@ -217,6 +223,11 @@ require("./popup/InformationPopup.tag.html"); riot.mount(this.refs.content, "favoritelist", {favoriteListId: favoriteListId}); }); + route("code=*", code => { + session.keycloakLogin(code); + route(""); + }); + route(() => { this.bus.trigger("pageChanged", "home"); riot.mount(this.refs.content, "home"); 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 14e3003e..58058ae2 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 @@ -52,7 +52,7 @@ require("./popup/FeedbackModal.tag.html"); </div> <div if="{!user}"> - <a class="header-link" onclick="{signIn}"> + <a class="header-link" onclick={signIn}> <i class="fa fa-sign-in" aria-hidden="true" /><span class="action-label">{__.signin}</span> </a> </div> diff --git a/pom.xml b/pom.xml index bcc9711a..013fd7e5 100644 --- a/pom.xml +++ b/pom.xml @@ -197,6 +197,8 @@ <seleniumVersion>2.33.0</seleniumVersion> <httpCommonsHttpclientVersion>4.5.2</httpCommonsHttpclientVersion> + <keycloakVersion>3.2.0.Final</keycloakVersion> + <pollenI18nBundle>pollen-i18n</pollenI18nBundle> <!-- license to use --> <license.licenseName>agpl_v3</license.licenseName> @@ -723,6 +725,28 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-authz-client</artifactId> + <version>${keycloakVersion}</version> + </dependency> + + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-core</artifactId> + <version>${keycloakVersion}</version> + </dependency> + + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-servlet-filter-adapter</artifactId> + <version>${keycloakVersion}</version> + </dependency> + + + + + </dependencies> </dependencyManagement> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm