Repository: syncope Updated Branches: refs/heads/master e76c59da5 -> ab4c623a3
SYNCOPE-1120 - Use the standard Bearer Authorization header for JWT tokens Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/ab4c623a Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/ab4c623a Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/ab4c623a Branch: refs/heads/master Commit: ab4c623a3f6ccdbe03968235b843ec81a2d97b1f Parents: e76c59d Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Fri Jun 23 16:36:16 2017 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Fri Jun 23 16:36:48 2017 +0100 ---------------------------------------------------------------------- .../client/console/rest/BaseRestClient.java | 5 +++- .../syncope/client/lib/SyncopeClient.java | 24 +++++++++++++------- .../client/lib/SyncopeClientFactoryBean.java | 6 ++--- .../security/JWTAuthenticationFilter.java | 11 +++++---- .../rest/cxf/service/SAML2SPServiceImpl.java | 16 ++++++++++--- .../org/apache/syncope/fit/AbstractITCase.java | 4 +++- 6 files changed, 46 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/client/console/src/main/java/org/apache/syncope/client/console/rest/BaseRestClient.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/BaseRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/BaseRestClient.java index 8b3dce2..4a780a6 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/rest/BaseRestClient.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/BaseRestClient.java @@ -19,6 +19,9 @@ package org.apache.syncope.client.console.rest; import java.net.URI; + +import javax.ws.rs.core.HttpHeaders; + import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.lib.SyncopeClient; @@ -76,7 +79,7 @@ public abstract class BaseRestClient implements RestClient { webClient.accept(SyncopeConsoleSession.get().getMediaType()).to(location.toASCIIString(), false); return webClient. header(RESTHeaders.DOMAIN, SyncopeConsoleSession.get().getDomain()). - header(RESTHeaders.TOKEN, SyncopeConsoleSession.get().getJWT()). + header(HttpHeaders.AUTHORIZATION, "Bearer " + SyncopeConsoleSession.get().getJWT()). get(resultClass); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java index f722cf8..c13fa77 100644 --- a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -107,18 +108,19 @@ public class SyncopeClient { restClientFactory.setPassword(((BasicAuthenticationHandler) handler).getPassword()); String jwt = getService(AccessTokenService.class).login().getHeaderString(RESTHeaders.TOKEN); - restClientFactory.getHeaders().put(RESTHeaders.TOKEN, Collections.singletonList(jwt)); + restClientFactory.getHeaders().put(HttpHeaders.AUTHORIZATION, Collections.singletonList("Bearer " + jwt)); restClientFactory.setUsername(null); restClientFactory.setPassword(null); } else if (handler instanceof JWTAuthenticationHandler) { restClientFactory.getHeaders().put( - RESTHeaders.TOKEN, Collections.singletonList(((JWTAuthenticationHandler) handler).getJwt())); + HttpHeaders.AUTHORIZATION, + Collections.singletonList("Bearer " + ((JWTAuthenticationHandler) handler).getJwt())); } } protected void cleanup() { - restClientFactory.getHeaders().remove(RESTHeaders.TOKEN); + restClientFactory.getHeaders().remove(HttpHeaders.AUTHORIZATION); restClientFactory.setUsername(null); restClientFactory.setPassword(null); } @@ -128,7 +130,7 @@ public class SyncopeClient { */ public void refresh() { String jwt = getService(AccessTokenService.class).refresh().getHeaderString(RESTHeaders.TOKEN); - restClientFactory.getHeaders().put(RESTHeaders.TOKEN, Collections.singletonList(jwt)); + restClientFactory.getHeaders().put(HttpHeaders.AUTHORIZATION, Collections.singletonList("Bearer " + jwt)); } /** @@ -186,16 +188,22 @@ public class SyncopeClient { } /** - * Returns the JWT in used by this instance, passed with the {@link RESTHeaders#TOKEN} header in all requests. - * It can be null (in case {@link NoAuthenticationHandler} or {@link AnonymousAuthenticationHandler} were used). + * Returns the JWT in used by this instance, passed with the {@link HttpHeaders#AUTHORIZATION} header + * in all requests. It can be null (in case {@link NoAuthenticationHandler} or + * {@link AnonymousAuthenticationHandler} were used). * * @return the JWT in used by this instance */ public String getJWT() { - List<String> headerValues = restClientFactory.getHeaders().get(RESTHeaders.TOKEN); - return headerValues == null || headerValues.isEmpty() + List<String> headerValues = restClientFactory.getHeaders().get(HttpHeaders.AUTHORIZATION); + String header = headerValues == null || headerValues.isEmpty() ? null : headerValues.get(0); + if (header != null && header.startsWith("Bearer ")) { + return header.substring("Bearer ".length()); + + } + return null; } /** http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java index 45e6ffa..1e5924b 100644 --- a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java @@ -245,7 +245,7 @@ public class SyncopeClientFactoryBean { /** * Builds client instance with the given credentials. - * Such credentials will be used only to obtain a valid JWT in the {@link RESTHeaders#TOKEN} header; + * Such credentials will be used only to obtain a valid JWT in the {@link HttpHeaders#AUTHORIZATION} header; * * @param username username * @param password password @@ -256,11 +256,11 @@ public class SyncopeClientFactoryBean { } /** - * Builds client instance which will be passing the provided value in the {@link RESTHeaders#TOKEN} + * Builds client instance which will be passing the provided value in the {@link HttpHeaders#AUTHORIZATION} * request header. * * @param jwt value received after login, in the {@link RESTHeaders#TOKEN} response header - * @return client instance which will be passing the provided value in the {{@link RESTHeaders#TOKEN} + * @return client instance which will be passing the provided value in the {@link HttpHeaders#AUTHORIZATION} * request header */ public SyncopeClient create(final String jwt) { http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/core/spring/src/main/java/org/apache/syncope/core/spring/security/JWTAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/JWTAuthenticationFilter.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/JWTAuthenticationFilter.java index 05b46f0..e5b13de 100644 --- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/JWTAuthenticationFilter.java +++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/JWTAuthenticationFilter.java @@ -23,9 +23,10 @@ import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.HttpHeaders; + import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; -import org.apache.syncope.common.rest.api.RESTHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -39,7 +40,7 @@ import org.springframework.util.Assert; import org.springframework.web.filter.OncePerRequestFilter; /** - * Processes the JSON Web Token provided as {@link RESTHeaders#TOKEN} HTTP header, putting the result into the + * Processes the JSON Web Token provided as {@link HttpHeaders#AUTHORIZATION} HTTP header, putting the result into the * {@link SecurityContextHolder}. */ public class JWTAuthenticationFilter extends OncePerRequestFilter { @@ -84,12 +85,14 @@ public class JWTAuthenticationFilter extends OncePerRequestFilter { final FilterChain chain) throws ServletException, IOException { - String stringToken = request.getHeader(RESTHeaders.TOKEN); - if (stringToken == null) { + String auth = request.getHeader(HttpHeaders.AUTHORIZATION); + String[] parts = auth == null ? null : auth.split(" "); + if (parts == null || parts.length != 2 || !"Bearer".equals(parts[0])) { chain.doFilter(request, response); return; } + String stringToken = parts[1]; LOG.debug("JWT received: {}", stringToken); JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(stringToken); http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java b/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java index 191081f..94d14f1 100644 --- a/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java +++ b/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java @@ -20,6 +20,8 @@ package org.apache.syncope.core.rest.cxf.service; import java.io.IOException; import java.io.OutputStream; + +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; @@ -27,7 +29,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.to.SAML2RequestTO; import org.apache.syncope.common.lib.to.SAML2LoginResponseTO; import org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO; -import org.apache.syncope.common.rest.api.RESTHeaders; import org.apache.syncope.common.rest.api.service.SAML2SPService; import org.apache.syncope.core.logic.SAML2SPLogic; import org.springframework.beans.factory.annotation.Autowired; @@ -68,13 +69,22 @@ public class SAML2SPServiceImpl extends AbstractServiceImpl implements SAML2SPSe @Override public SAML2RequestTO createLogoutRequest(final String spEntityID) { return logic.createLogoutRequest( - messageContext.getHttpHeaders().getHeaderString(RESTHeaders.TOKEN), + getJWTToken(), StringUtils.appendIfMissing(spEntityID, "/")); } @Override public void validateLogoutResponse(final SAML2ReceivedResponseTO response) { - logic.validateLogoutResponse(messageContext.getHttpHeaders().getHeaderString(RESTHeaders.TOKEN), response); + logic.validateLogoutResponse(getJWTToken(), response); } + private String getJWTToken() { + String auth = messageContext.getHttpHeaders().getHeaderString(HttpHeaders.AUTHORIZATION); + String[] parts = auth == null ? null : auth.split(" "); + if (parts == null || parts.length != 2 || !"Bearer".equals(parts[0])) { + return null; + } + + return parts[1]; + } } http://git-wip-us.apache.org/repos/asf/syncope/blob/ab4c623a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java index ba819af..b584802 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java @@ -104,6 +104,8 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import org.springframework.jdbc.core.JdbcTemplate; +import com.google.common.net.HttpHeaders; + @FixMethodOrder(MethodSorters.JVM) public abstract class AbstractITCase { @@ -322,7 +324,7 @@ public abstract class AbstractITCase { return webClient. header(RESTHeaders.DOMAIN, adminClient.getDomain()). - header(RESTHeaders.TOKEN, adminClient.getJWT()). + header(HttpHeaders.AUTHORIZATION, "Bearer " + adminClient.getJWT()). get(resultClass); }