Repository: syncope Updated Branches: refs/heads/master 6a93860d8 -> 8e8368e19
[SYNCOPE-719] Added CSRF/XSRF protection by http cookie provided to angular Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/8e8368e1 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/8e8368e1 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/8e8368e1 Branch: refs/heads/master Commit: 8e8368e19772c5e39baa0a152e81a890f2cb6c3e Parents: 6a93860 Author: Andrea Patricelli <andrea.patrice...@tirasa.net> Authored: Thu Dec 31 10:38:28 2015 +0100 Committer: Andrea Patricelli <andrea.patrice...@tirasa.net> Committed: Thu Dec 31 10:38:28 2015 +0100 ---------------------------------------------------------------------- .../client/enduser/SyncopeEnduserConstants.java | 8 ++- .../client/enduser/SyncopeEnduserSession.java | 9 ++++ .../enduser/resources/AbstractBaseResource.java | 10 ++++ .../enduser/resources/CaptchaResource.java | 6 +-- .../resources/CaptchaValidateResource.java | 12 ++++- .../client/enduser/resources/InfoResource.java | 15 +++++- .../client/enduser/resources/LoginResource.java | 42 +++++++++------- .../enduser/resources/LogoutResource.java | 2 +- .../enduser/resources/SchemaResource.java | 9 ++++ .../resources/SecurityQuestionResource.java | 9 ++++ .../resources/SyncopeResourceResource.java | 9 ++++ .../resources/UserSelfCreateResource.java | 6 +++ .../enduser/resources/UserSelfReadResource.java | 13 ++++- .../resources/UserSelfUpdateResource.java | 11 ++++- .../resources/META-INF/resources/app/index.html | 2 +- .../resources/META-INF/resources/app/js/app.js | 52 +++++++++++++++----- .../app/js/controllers/LoginController.js | 49 +++--------------- .../resources/app/js/services/infoService.js | 3 +- .../META-INF/resources/app/views/self.html | 4 +- client/lib/pom.xml | 5 ++ .../syncope/client/lib/SaltGenerator.java | 42 ++++++++++++++++ 21 files changed, 228 insertions(+), 90 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java index daa0e15..4600166 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserConstants.java @@ -20,10 +20,14 @@ package org.apache.syncope.client.enduser; public final class SyncopeEnduserConstants { - public static final String CAPTCHA_SESSION_KEY = "captcha"; + public static final String CAPTCHA_SESSION_KEY = "captcha"; + + public static final String XSRF_COOKIE = "XSRF-TOKEN"; + + public static final String XSRF_HEADER_NAME = "X-XSRF-TOKEN"; private SyncopeEnduserConstants() { // private constructor for utility class } - + } http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java index bbea57b..cb51436 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java @@ -37,6 +37,7 @@ import org.apache.syncope.common.rest.api.service.SyncopeService; import org.apache.wicket.Session; import org.apache.wicket.protocol.http.WebSession; import org.apache.wicket.request.Request; +import org.apache.wicket.util.cookies.CookieUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,6 +63,8 @@ public class SyncopeEnduserSession extends WebSession { private UserTO selfTO; private final Map<Class<?>, Object> services = Collections.synchronizedMap(new HashMap<Class<?>, Object>()); + + private final CookieUtils cookieUtils; public static SyncopeEnduserSession get() { return (SyncopeEnduserSession) Session.get(); @@ -69,6 +72,8 @@ public class SyncopeEnduserSession extends WebSession { public SyncopeEnduserSession(final Request request) { super(request); + // define cookie utility to manage application cookies + cookieUtils = new CookieUtils(); anonymousClient = SyncopeEnduserApplication.get().getClientFactory().create( SyncopeEnduserApplication.get().getAnonymousUser(), @@ -173,4 +178,8 @@ public class SyncopeEnduserSession extends WebSession { return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale); } + public CookieUtils getCookieUtils() { + return cookieUtils; + } + } http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java index 69fe72f..3f9e037 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java @@ -18,6 +18,9 @@ */ package org.apache.syncope.client.enduser.resources; +import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.enduser.SyncopeEnduserConstants; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.wicket.request.resource.AbstractResource; @@ -43,4 +46,11 @@ public abstract class AbstractBaseResource extends AbstractResource { : result; } + protected final boolean xsrfCheck(final HttpServletRequest request) { + final String requestXSRFHeader = request.getHeader(SyncopeEnduserConstants.XSRF_HEADER_NAME); + return StringUtils.isNotBlank(requestXSRFHeader) + && SyncopeEnduserSession.get().getCookieUtils().getCookie(SyncopeEnduserConstants.XSRF_COOKIE). + getValue().equals(requestXSRFHeader); + } + } http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaResource.java index ad71a85..d856629 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaResource.java @@ -21,7 +21,6 @@ package org.apache.syncope.client.enduser.resources; import javax.servlet.http.HttpServletRequest; import org.apache.syncope.client.enduser.SyncopeEnduserConstants; import org.apache.wicket.extensions.markup.html.captcha.CaptchaImageResource; -import org.apache.wicket.request.Request; import org.apache.wicket.request.cycle.RequestCycle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,11 +48,10 @@ public class CaptchaResource extends CaptchaImageResource { protected byte[] render() { LOG.info("Generate captcha"); final String captcha = randomString(6, 8); - Request request = RequestCycle.get().getRequest(); - HttpServletRequest httpRequest = ((HttpServletRequest) request.getContainerRequest()); + HttpServletRequest httpRequest = ((HttpServletRequest) RequestCycle.get().getRequest().getContainerRequest()); // store the captcha in the current session httpRequest.getSession().setAttribute(SyncopeEnduserConstants.CAPTCHA_SESSION_KEY, captcha); - + getChallengeIdModel().setObject(captcha); return super.render(); } http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaValidateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaValidateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaValidateResource.java index be07096..e8749b8 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaValidateResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/CaptchaValidateResource.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.enduser.SyncopeEnduserConstants; import org.apache.syncope.client.enduser.model.CaptchaRequest; import org.apache.syncope.core.misc.serialization.POJOHelper; +import org.apache.wicket.request.resource.AbstractResource; import org.apache.wicket.request.resource.IResource; import org.apache.wicket.util.io.IOUtils; import org.slf4j.Logger; @@ -41,9 +42,16 @@ public class CaptchaValidateResource extends AbstractBaseResource { LOG.debug("Validate captcha request"); - ResourceResponse response = new ResourceResponse(); + AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { HttpServletRequest currentRequest = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + + if (!xsrfCheck(currentRequest)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + final CaptchaRequest enteredCaptcha = POJOHelper.deserialize(IOUtils.toString(currentRequest. getInputStream()), CaptchaRequest.class); @@ -57,7 +65,7 @@ public class CaptchaValidateResource extends AbstractBaseResource { LOG.info("Could not validate captcha: current session captcha or inserted captcha are empty or null"); response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "ErrorMessage{{ Could not validate captcha: current session captcha or entered captcha are " - + "empty or null }}"); + + "empty or null }}"); } else { LOG.info("Is entered captcha equal to current session captcha? {}", enteredCaptcha.getValue().equals( currentCaptcha)); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java index 530112b..1449cf0 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java @@ -20,10 +20,14 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; import javax.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.enduser.SyncopeEnduserConstants; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.adapters.SyncopeTOAdapter; +import org.apache.syncope.client.lib.SaltGenerator; import org.apache.syncope.core.misc.serialization.POJOHelper; import org.apache.wicket.request.resource.IResource; +import org.apache.wicket.util.cookies.CookieUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +49,15 @@ public class InfoResource extends AbstractBaseResource { ResourceResponse response = new ResourceResponse(); try { + final CookieUtils sessionCookieUtils = SyncopeEnduserSession.get().getCookieUtils(); +// HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + // set XSRF_TOKEN cookie + if (sessionCookieUtils.getCookie(SyncopeEnduserConstants.XSRF_COOKIE) == null || StringUtils.isBlank( + sessionCookieUtils.getCookie(SyncopeEnduserConstants.XSRF_COOKIE).getValue())) { + LOG.info("Set XSRF-TOKEN cookie"); + sessionCookieUtils.save(SyncopeEnduserConstants.XSRF_COOKIE, SaltGenerator.generate( + SyncopeEnduserSession.get().getId())); + } response.setWriteCallback(new WriteCallback() { @Override @@ -53,7 +66,7 @@ public class InfoResource extends AbstractBaseResource { SyncopeEnduserSession.get().getSyncopeTO()))); } }); - response.setStatusCode(Response.Status.OK.getStatusCode()); + response.setStatusCode(Response.Status.OK.getStatusCode()); } catch (Exception e) { LOG.error("Error retrieving syncope info", e); response.setError(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), new StringBuilder() http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java index e481d2c..28d19a3 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java @@ -25,6 +25,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.enduser.model.Credentials; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.core.misc.serialization.POJOHelper; +import org.apache.wicket.request.resource.AbstractResource; +import org.apache.wicket.request.resource.IResource; import org.apache.wicket.util.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,12 +41,19 @@ public class LoginResource extends AbstractBaseResource { } @Override - protected ResourceResponse newResourceResponse(final Attributes attributes) { + protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) { - ResourceResponse response = new ResourceResponse(); + AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + Credentials credentials = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()), Credentials.class); final String username = credentials.getUsername(); @@ -56,22 +65,21 @@ public class LoginResource extends AbstractBaseResource { LOG.error("Could not read credentials from request: username is blank!"); response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "ErrorMessage{{ Could not read credentials from request: username is blank! }}"); - } else // authenticate user - if (SyncopeEnduserSession.get().authenticate(username, password)) { - // user has been authenticated successfully - response.setWriteCallback(new WriteCallback() { + } else if (SyncopeEnduserSession.get().authenticate(username, password)) { + // user has been authenticated successfully + response.setWriteCallback(new WriteCallback() { - @Override - public void writeData(final Attributes attributes) throws IOException { - attributes.getResponse().write(username); - } - }); - response.setStatusCode(Response.Status.OK.getStatusCode()); - } else { - // not authenticated - response.setError(Response.Status.UNAUTHORIZED.getStatusCode(), - "ErrorMessage{{ Username or password are incorrect }}"); - } + @Override + public void writeData(final Attributes attributes) throws IOException { + attributes.getResponse().write(username); + } + }); + response.setStatusCode(Response.Status.OK.getStatusCode()); + } else { + // not authenticated + response.setError(Response.Status.UNAUTHORIZED.getStatusCode(), + "ErrorMessage{{ Username or password are incorrect }}"); + } } catch (Exception e) { LOG.error("Could not read credentials from request", e); response.setError(Response.Status.BAD_REQUEST.getStatusCode(), new StringBuilder() http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java index 545b44d..3101332 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java @@ -31,7 +31,7 @@ public class LogoutResource extends AbstractBaseResource { @Override protected ResourceResponse newResourceResponse(final Attributes attributes) { - LOG.debug("Enduser logout"); + LOG.debug("Logout from enduser application"); SyncopeEnduserSession.get().invalidate(); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java index b909767..12ce2f1 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java @@ -20,6 +20,7 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; import java.util.List; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.model.SchemaResponse; @@ -61,6 +62,14 @@ public class SchemaResource extends AbstractBaseResource { AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { + HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + final AnyTypeTO anyTypeUserTO = anyTypeService.read(AnyTypeKind.USER.name()); final List<PlainSchemaTO> plainSchemas = schemaService.list( http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java index 4a03601..3f6c0ea 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java @@ -20,6 +20,7 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; import java.util.List; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.common.lib.to.SecurityQuestionTO; @@ -51,6 +52,14 @@ public class SecurityQuestionResource extends AbstractBaseResource { try { + HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + final List<SecurityQuestionTO> securityQuestionTOs = securityQuestionService.list(); response.setWriteCallback(new AbstractResource.WriteCallback() { http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SyncopeResourceResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SyncopeResourceResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SyncopeResourceResource.java index 0331ce1..350d442 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SyncopeResourceResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SyncopeResourceResource.java @@ -20,6 +20,7 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; import java.util.List; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.adapters.ResourceTOAdapter; @@ -54,6 +55,14 @@ public class SyncopeResourceResource extends AbstractBaseResource { AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { + + HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + final List<ResourceTO> resourceTOs = resourceService.list(); response.setWriteCallback(new AbstractResource.WriteCallback() { http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java index d22b267..42b45fc 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java @@ -54,6 +54,12 @@ public class UserSelfCreateResource extends AbstractBaseResource { try { HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN is not matching"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN is not matching"); + return response; + } + final UserTORequest userTORequest = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()), UserTORequest.class); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java index c1d465f..fc4413b 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java @@ -19,15 +19,17 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.adapters.UserTOAdapter; import org.apache.syncope.core.misc.serialization.POJOHelper; import org.apache.wicket.request.resource.AbstractResource; +import org.apache.wicket.request.resource.IResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class UserSelfReadResource extends AbstractResource { +public class UserSelfReadResource extends AbstractBaseResource { private static final long serialVersionUID = -9184809392631523912L; @@ -43,13 +45,20 @@ public class UserSelfReadResource extends AbstractResource { } @Override - protected ResourceResponse newResourceResponse(final Attributes attributes) { + protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) { LOG.debug("Requested user self information"); AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { + HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } + final String selfTOJson = POJOHelper.serialize(userTOAdapter.toUserTORequest(SyncopeEnduserSession.get(). getSelfTO())); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java index 2737bdb..a44d53e 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java @@ -27,6 +27,8 @@ import org.apache.syncope.client.enduser.model.UserTORequest; import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.rest.api.service.UserSelfService; import org.apache.syncope.core.misc.serialization.POJOHelper; +import org.apache.wicket.request.resource.AbstractResource; +import org.apache.wicket.request.resource.IResource; import org.apache.wicket.util.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,12 +49,17 @@ public class UserSelfUpdateResource extends AbstractBaseResource { } @Override - protected ResourceResponse newResourceResponse(final Attributes attributes) { + protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) { - ResourceResponse response = new ResourceResponse(); + AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse(); try { HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); + if (!xsrfCheck(request)) { + LOG.error("XSRF TOKEN does not match"); + response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match"); + return response; + } final UserTORequest userTOResponse = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()), UserTORequest.class); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/resources/META-INF/resources/app/index.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html index 21f88d0..b684455 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/index.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html @@ -41,7 +41,7 @@ under the License. <![endif]--> <!--<div ng-view ng-cloak ng-controller="ApplicationController"></div>--> - <div ui-view ng-cloak ng-controller="ApplicationController"></div> + <div ui-view ng-cloak ng-controller="ApplicationController" ng-init="initApplication()"></div> <!-- <footer id="footer" class="hidden-print"> <ul class="nav pull-right"> http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/resources/META-INF/resources/app/js/app.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js index 4792ea4..da0e46f 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js @@ -84,13 +84,13 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'growlProvi templateUrl: 'views/user-plain-schemas.html' }) .state('create.derivedSchemas', { - url: '/derivedSchemas', - templateUrl: 'views/user-derived-schemas.html' - }) - .state('create.virtualSchemas', { - url: '/virtualSchemas', - templateUrl: 'views/user-virtual-schemas.html' - }) + url: '/derivedSchemas', + templateUrl: 'views/user-derived-schemas.html' + }) + .state('create.virtualSchemas', { + url: '/virtualSchemas', + templateUrl: 'views/user-virtual-schemas.html' + }) .state('create.resources', { url: '/resources', templateUrl: 'views/user-resources.html' @@ -181,6 +181,8 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'growlProvi // HTTP service configuration $httpProvider.defaults.withCredentials = true; + $httpProvider.defaults.xsrfCookieName = 'XSRF-TOKEN'; + $httpProvider.defaults.xsrfHeaderName = 'X-XSRF-TOKEN'; $httpProvider.interceptors.push(function ($q, $rootScope, $location) { var numLoadings = 0; @@ -268,23 +270,49 @@ app.run(['$rootScope', '$location', '$cookies', '$state', // }); }]); -app.controller('ApplicationController', function ($scope) { +app.controller('ApplicationController', ['$scope', '$rootScope', 'InfoService', function ($scope, $rootScope, + InfoService) { // DO NOTHING + +// get syncope info and set cookie, first call + $scope.initApplication = function () { +// call info service + $rootScope.selfRegAllowed = false; + $rootScope.pwdResetAllowed = false; + $rootScope.version = ""; + //info settings are initialized every time an user open the login page + InfoService.getInfo().then( + function (response) { + $rootScope.pwdResetAllowed = response.pwdResetAllowed; + $rootScope.selfRegAllowed = response.selfRegAllowed; + $rootScope.version = response.version; + }, + function (response) { + console.log("Something went wrong while accessing info resource", response); + }); + + $rootScope.isSelfRegAllowed = function () { + return $rootScope.selfRegAllowed === true; + }; + $rootScope.isPwdResetAllowed = function () { + return $rootScope.pwdResetAllowed === true; + }; + $rootScope.getVersion = function () { + return $rootScope.version; + }; // $scope.$on('success', function (event, args) { // console.log("IN CONFIG EVENTO: ", event) // $scope.$broadcast("error", "success"); // }); -}); - + } + }]); app.factory('AuthenticationHelper', ['$q', '$rootScope', function ($q, $rootScope) { return { authenticated: function () { var currentUser = $rootScope.currentUser; - console.log("AuthenticationHelper, currentUser: ", currentUser); - if (angular.isDefined(currentUser) && currentUser) { return true; } else { http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js index 8c00fc8..46ac8ea 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js @@ -20,8 +20,7 @@ 'use strict'; angular.module("login").controller("LoginController", ['$scope', '$rootScope', '$http', '$location', '$cookies', - 'AuthService', 'growl', 'InfoService', function ($scope, $rootScope, $http, $location, $cookies, AuthService, growl, - InfoService) { + 'AuthService', 'growl', function ($scope, $rootScope, $http, $location, $cookies, AuthService, growl) { $scope.credentials = { username: '', @@ -31,19 +30,14 @@ angular.module("login").controller("LoginController", ['$scope', '$rootScope', ' $scope.login = function (credentials) { - console.log("CREDENTIALS FROM PAGE: ", credentials); - console.log("AUTHSERVICE: ", AuthService); - AuthService.login($scope.credentials).then(function (user) { - console.log("LOGIN SUCCESS FOR: ", user); - console.log("DOPO AVER SETTATO CURRENT USER: ", $rootScope.currentUser); - console.log("COOKIE CURRENT USER: ", $cookies.get('currentUser')); + console.log("Login success for: ", user); // reset error message $scope.credentials.errorMessage = ''; // got to update page $location.path("/self/update"); }, function (response) { - console.log("LOGIN FAILED: ", response); + console.log("Login failed for: ", response); var errorMessage; // parse error response if (response !== undefined) { @@ -56,13 +50,10 @@ angular.module("login").controller("LoginController", ['$scope', '$rootScope', ' }; $scope.logout = function () { - - console.log("PERFORMING LOGOUT"); - AuthService.logout().then(function (response) { - console.log("LOGOUT SUCCESS: ", response); - }, function () { - console.log("LOGOUT FAILED"); + console.log("Logout successfully"); + }, function (response) { + console.log("Logout failed: ", response); }); }; @@ -96,32 +87,4 @@ angular.module("login").controller("LoginController", ['$scope', '$rootScope', ' console.log("schemaAPI response: ", data); }); }; - - $scope.selfRegAllowed = false; - $scope.pwdResetAllowed = false; - $scope.version = ""; - - //info settings are initialized every time an user open the login page - InfoService.getInfo().then( - function (response) { - $scope.pwdResetAllowed = response.pwdResetAllowed; - $scope.selfRegAllowed = response.selfRegAllowed; - $scope.version = response.version; - }, - function () { - console.log("Something went wrong while accessing info resource", response); - }); - - $scope.isSelfRegAllowed = function () { - return $scope.selfRegAllowed == true; - }; - - $scope.isPwdResetAllowed = function () { - return $scope.pwdResetAllowed == true; - }; - - $scope.getVersion = function () { - return $scope.version; - }; - }]); http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/resources/META-INF/resources/app/js/services/infoService.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/infoService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/infoService.js index 1f71e27..9c58cf7 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/infoService.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/infoService.js @@ -19,7 +19,7 @@ 'use strict'; -angular.module('info') +angular.module('SyncopeEnduserApp') .factory('InfoService', ['$resource', '$q', '$http', function ($resource, $q, $http) { @@ -32,6 +32,7 @@ angular.module('info') return response.data; }, function (response) { console.log("Something went wrong while retrieving info resource", response); + return $q.reject(response.data || response.statusText); }); }; http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/enduser/src/main/resources/META-INF/resources/app/views/self.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/self.html b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html index 93d85fb..a684ec6 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/views/self.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html @@ -84,14 +84,14 @@ under the License. </div> </div> - <div class="text-center" ng-show="!isLogged() && isSelfRegAllowed()"> + <div class="text-center" ng-show="!isLogged() && $root.isSelfRegAllowed()"> <a href="javascript:void(0);" class="btn btn-link" ng-click="selfCreate()">Self Registration</a> <!-- <div id="initialLoaderDiv"> <img src="img/busy.gif" class="ajax-loader"/> </div>--> </div> - <div class="text-center" ng-show="!isLogged() && isPwdResetAllowed()"> + <div class="text-center" ng-show="!isLogged() && $root.isPwdResetAllowed()"> <a href="javascript:void(0);" class="btn btn-link" ng-click="passwordReset()">Password Reset</a> </div> <!-- /#login-container --> http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/lib/pom.xml ---------------------------------------------------------------------- diff --git a/client/lib/pom.xml b/client/lib/pom.xml index ef5481c..134497e 100644 --- a/client/lib/pom.xml +++ b/client/lib/pom.xml @@ -62,6 +62,11 @@ under the License. </dependency> <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </dependency> + + <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/syncope/blob/8e8368e1/client/lib/src/main/java/org/apache/syncope/client/lib/SaltGenerator.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/SaltGenerator.java b/client/lib/src/main/java/org/apache/syncope/client/lib/SaltGenerator.java new file mode 100644 index 0000000..911a49b --- /dev/null +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SaltGenerator.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.lib; + +import java.security.SecureRandom; +import java.util.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class SaltGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(SaltGenerator.class); + + public static String generate(final String input) { + // generate salt + byte[] salt = new byte[16]; + // fill array with random bytes + new SecureRandom().nextBytes(salt); + // create digest with MD5 + return DigestUtils.md2Hex(input + Base64.getEncoder().encodeToString(salt)); + } + + private SaltGenerator() { + } +}