Repository: syncope Updated Branches: refs/heads/2_0_X 7c8e09746 -> c267b8b82 refs/heads/master d40aafe76 -> 03cb2f012
[SYNCOPE-1100] Providing JWT expire as HTTP header in response to login + adding support for that with SAML 2.0 SP Agent Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c267b8b8 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c267b8b8 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c267b8b8 Branch: refs/heads/2_0_X Commit: c267b8b825fd40062e21686da8cebe3d0d5ad5b3 Parents: 7c8e097 Author: Francesco Chicchiriccò <ilgro...@apache.org> Authored: Tue May 30 16:28:07 2017 +0200 Committer: Francesco Chicchiriccò <ilgro...@apache.org> Committed: Tue May 30 16:28:07 2017 +0200 ---------------------------------------------------------------------- .../syncope/common/rest/api/RESTHeaders.java | 2 ++ .../syncope/core/logic/AccessTokenLogic.java | 6 ++++-- .../api/data/AccessTokenDataBinder.java | 5 +++-- .../java/data/AccessTokenDataBinderImpl.java | 19 +++++++++++++------ .../rest/cxf/service/AccessTokenServiceImpl.java | 13 +++++++++++-- .../ext/saml2lsp/agent/AssertionConsumer.java | 1 + .../syncope/ext/saml2lsp/agent/Constants.java | 2 ++ .../common/lib/to/SAML2LoginResponseTO.java | 10 ++++++++++ .../apache/syncope/core/logic/SAML2SPLogic.java | 5 ++++- 9 files changed, 50 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java ---------------------------------------------------------------------- diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java index 0c54116..2a61321 100644 --- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java +++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java @@ -27,6 +27,8 @@ public final class RESTHeaders { public static final String TOKEN = "X-Syncope-Token"; + public static final String TOKEN_EXPIRE = "X-Syncope-Token-Expire"; + public static final String OWNED_ENTITLEMENTS = "X-Syncope-Entitlements"; public static final String RESOURCE_KEY = "X-Syncope-Key"; http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java ---------------------------------------------------------------------- diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java index ece23d0..c495392 100644 --- a/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java +++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java @@ -21,10 +21,12 @@ package org.apache.syncope.core.logic; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.Transformer; +import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.to.AccessTokenTO; import org.apache.syncope.common.lib.types.StandardEntitlement; import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO; @@ -50,7 +52,7 @@ public class AccessTokenLogic extends AbstractTransactionalLogic<AccessTokenTO> private AccessTokenDAO accessTokenDAO; @PreAuthorize("isAuthenticated()") - public String login() { + public Pair<String, Date> login() { if (anonymousUser.equals(AuthContextUtils.getUsername())) { throw new IllegalArgumentException(anonymousUser + " cannot be granted for an access token"); } @@ -59,7 +61,7 @@ public class AccessTokenLogic extends AbstractTransactionalLogic<AccessTokenTO> } @PreAuthorize("isAuthenticated()") - public String refresh() { + public Pair<String, Date> refresh() { AccessToken accessToken = accessTokenDAO.findByOwner(AuthContextUtils.getUsername()); if (accessToken == null) { throw new NotFoundException("AccessToken for " + AuthContextUtils.getUsername()); http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AccessTokenDataBinder.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AccessTokenDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AccessTokenDataBinder.java index b24137f..be51926 100644 --- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AccessTokenDataBinder.java +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AccessTokenDataBinder.java @@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.api.data; import java.util.Date; import java.util.Map; +import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.syncope.common.lib.to.AccessTokenTO; import org.apache.syncope.core.persistence.api.entity.AccessToken; @@ -28,9 +29,9 @@ public interface AccessTokenDataBinder { Triple<String, String, Date> generateJWT(String subject, int duration, Map<String, Object> claims); - String create(String subject, Map<String, Object> claims, boolean replaceExisting); + Pair<String, Date> create(String subject, Map<String, Object> claims, boolean replaceExisting); - String update(AccessToken accessToken); + Pair<String, Date> update(AccessToken accessToken); AccessTokenTO getAccessTokenTO(AccessToken accessToken); http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AccessTokenDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AccessTokenDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AccessTokenDataBinderImpl.java index 6bca7e0..5159733 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AccessTokenDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AccessTokenDataBinderImpl.java @@ -24,6 +24,7 @@ import java.util.Calendar; import java.util.Date; import java.util.Map; import javax.annotation.Resource; +import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.cxf.rs.security.jose.common.JoseType; import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm; @@ -110,12 +111,16 @@ public class AccessTokenDataBinderImpl implements AccessTokenDataBinder { } @Override - public String create(final String subject, final Map<String, Object> claims, final boolean replaceExisting) { + public Pair<String, Date> create( + final String subject, final Map<String, Object> claims, final boolean replaceExisting) { + String body = null; + Date expiryTime = null; AccessToken existing = accessTokenDAO.findByOwner(subject); if (existing != null) { body = existing.getBody(); + expiryTime = existing.getExpiryTime(); } if (replaceExisting || body == null) { @@ -125,11 +130,12 @@ public class AccessTokenDataBinderImpl implements AccessTokenDataBinder { claims); body = created.getMiddle(); + expiryTime = created.getRight(); AccessToken accessToken = entityFactory.newEntity(AccessToken.class); accessToken.setKey(created.getLeft()); accessToken.setBody(body); - accessToken.setExpiryTime(created.getRight()); + accessToken.setExpiryTime(expiryTime); accessToken.setOwner(subject); if (!adminUser.equals(accessToken.getOwner())) { @@ -149,11 +155,11 @@ public class AccessTokenDataBinderImpl implements AccessTokenDataBinder { accessTokenDAO.delete(existing); } - return body; + return Pair.of(body, expiryTime); } @Override - public String update(final AccessToken accessToken) { + public Pair<String, Date> update(final AccessToken accessToken) { JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(accessToken.getBody()); Date now = new Date(); @@ -167,9 +173,10 @@ public class AccessTokenDataBinderImpl implements AccessTokenDataBinder { JwsJwtCompactProducer producer = new JwsJwtCompactProducer(token); String body = producer.signWith(jwsSignatureProvider); + Date expiryTime = expiry.getTime(); accessToken.setBody(body); - accessToken.setExpiryTime(expiry.getTime()); + accessToken.setExpiryTime(expiryTime); if (!adminUser.equals(accessToken.getOwner())) { try { @@ -183,7 +190,7 @@ public class AccessTokenDataBinderImpl implements AccessTokenDataBinder { accessTokenDAO.save(accessToken); - return body; + return Pair.of(body, expiryTime); } @Override http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AccessTokenServiceImpl.java ---------------------------------------------------------------------- diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AccessTokenServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AccessTokenServiceImpl.java index f5859db..54db9cc 100644 --- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AccessTokenServiceImpl.java +++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AccessTokenServiceImpl.java @@ -18,7 +18,10 @@ */ package org.apache.syncope.core.rest.cxf.service; +import java.util.Date; import javax.ws.rs.core.Response; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.to.AccessTokenTO; import org.apache.syncope.common.lib.to.PagedResult; import org.apache.syncope.common.rest.api.RESTHeaders; @@ -36,15 +39,21 @@ public class AccessTokenServiceImpl extends AbstractServiceImpl implements Acces @Override public Response login() { + Pair<String, Date> login = logic.login(); return Response.noContent(). - header(RESTHeaders.TOKEN, logic.login()). + header(RESTHeaders.TOKEN, login.getLeft()). + header(RESTHeaders.TOKEN_EXPIRE, + DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.format(login.getRight())). build(); } @Override public Response refresh() { + Pair<String, Date> refresh = logic.refresh(); return Response.noContent(). - header(RESTHeaders.TOKEN, logic.refresh()). + header(RESTHeaders.TOKEN, refresh.getLeft()). + header(RESTHeaders.TOKEN_EXPIRE, + DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.format(refresh.getRight())). build(); } http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java index 6407b4d..698aa7f 100644 --- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java +++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java @@ -45,6 +45,7 @@ public class AssertionConsumer extends AbstractSAML2SPServlet { validateLoginResponse(extract(request.getInputStream())); request.getSession(true).setAttribute(Constants.SAML2SPJWT, responseTO.getAccessToken()); + request.getSession(true).setAttribute(Constants.SAML2SPJWT_EXPIRE, responseTO.getAccessTokenExpiryTime()); String successURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_SUCCESS_URL); if (successURL == null) { http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Constants.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Constants.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Constants.java index 619e4b8..b7da815 100644 --- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Constants.java +++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Constants.java @@ -36,6 +36,8 @@ public final class Constants { public static final String SAML2SPJWT = "saml2sp.jwt"; + public static final String SAML2SPJWT_EXPIRE = "saml2sp.jwt.expire"; + private Constants() { // private constructor for static utility class } http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java index 941d7c5..f905035 100644 --- a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java +++ b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2LoginResponseTO.java @@ -44,6 +44,8 @@ public class SAML2LoginResponseTO extends AbstractBaseBean { private String accessToken; + private Date accessTokenExpiryTime; + private String username; private final Set<AttrTO> attrs = new HashSet<>(); @@ -106,6 +108,14 @@ public class SAML2LoginResponseTO extends AbstractBaseBean { this.accessToken = accessToken; } + public Date getAccessTokenExpiryTime() { + return accessTokenExpiryTime; + } + + public void setAccessTokenExpiryTime(final Date accessTokenExpiryTime) { + this.accessTokenExpiryTime = accessTokenExpiryTime; + } + public String getUsername() { return username; } http://git-wip-us.apache.org/repos/asf/syncope/blob/c267b8b8/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java index 9835061..e5c444c 100644 --- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; @@ -530,7 +531,9 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> { claims.put(JWT_CLAIM_NAMEID_FORMAT, nameID.getFormat()); claims.put(JWT_CLAIM_NAMEID_VALUE, nameID.getValue()); claims.put(JWT_CLAIM_SESSIONINDEX, responseTO.getSessionIndex()); - responseTO.setAccessToken(accessTokenDataBinder.create(responseTO.getUsername(), claims, true)); + Pair<String, Date> accessTokenInfo = accessTokenDataBinder.create(responseTO.getUsername(), claims, true); + responseTO.setAccessToken(accessTokenInfo.getLeft()); + responseTO.setAccessTokenExpiryTime(accessTokenInfo.getRight()); return responseTO; }