From 35ffbf041e7da7376e07d8e7425a2925ce31f403 Mon Sep 17 00:00:00 2001 From: Milton Ch <86965029+Milton-Ch@users.noreply.github.com> Date: Wed, 26 Oct 2022 10:22:31 -0400 Subject: [PATCH] fix(jans-auth-server): ssa get endpoint (#2719) --- .../java/io/jans/as/client/BaseClient.java | 4 - .../java/io/jans/as/client/SsaResponse.java | 59 ----- .../create/SsaCreateClient.java} | 37 +-- .../create/SsaCreateRequest.java} | 35 +-- .../client/ssa/create/SsaCreateResponse.java | 83 +++++++ .../jans/as/client/ssa/get/SsaGetClient.java | 75 ++++++ .../io/jans/as/client/ssa/get/SsaGetJson.java | 34 +++ .../jans/as/client/ssa/get/SsaGetRequest.java | 35 +++ .../as/client/ssa/get/SsaGetResponse.java | 79 +++++++ .../test/java/io/jans/as/client/BaseTest.java | 25 ++ .../jans/as/client/client/AssertBuilder.java | 11 +- .../SsaCreateAssertBuilder.java | 62 +++++ .../assertbuilders/SsaGetAssertBuilder.java | 78 +++++++ .../SsaResponseAssertBuilder.java | 86 ------- .../jans/as/client/ssa/SsaCreateRestTest.java | 120 ++++++++++ .../io/jans/as/client/ssa/SsaGetRestTest.java | 173 ++++++++++++++ .../ws/rs/SsaRestWebServiceHttpTest.java | 221 ------------------ .../client/src/test/resources/testng.xml | 9 +- .../io/jans/as/model/ssa/SsaRequestParam.java | 8 + .../io/jans/as/model/ssa/SsaScopeType.java | 6 +- .../java/io/jans/as/model/util/DateUtil.java | 13 ++ .../io/jans/as/model/util/DateUtilTest.java | 29 +++ .../io/jans/as/server/model/audit/Action.java | 4 +- .../external/ModifySsaResponseService.java | 36 ++- .../as/server/ssa/ws/rs/SsaJsonService.java | 56 +++-- .../server/ssa/ws/rs/SsaRestWebService.java | 20 +- .../ssa/ws/rs/SsaRestWebServiceImpl.java | 14 +- .../ssa/ws/rs/SsaRestWebServiceValidator.java | 12 +- .../jans/as/server/ssa/ws/rs/SsaService.java | 56 ++++- .../ssa/ws/rs/action/SsaCreateAction.java | 33 ++- .../server/ssa/ws/rs/action/SsaGetAction.java | 108 +++++++++ .../server/ssa/ws/rs/SsaJsonServiceTest.java | 97 ++++++-- .../ssa/ws/rs/SsaRestWebServiceImplTest.java | 21 +- .../ws/rs/SsaRestWebServiceValidatorTest.java | 110 ++++++++- .../as/server/ssa/ws/rs/SsaServiceTest.java | 112 +++++++-- .../ssa/ws/rs/action/SsaCreateActionTest.java | 49 ++-- .../ssa/ws/rs/action/SsaGetActionTest.java | 136 +++++++++++ .../type/ssa/DummyModifySsaResponseType.java | 5 + .../type/ssa/ModifySsaResponseType.java | 4 +- .../ssa_modify_response.py | 32 +++ .../test/jans-auth/data/oxauth-test-data.ldif | 20 ++ 41 files changed, 1669 insertions(+), 538 deletions(-) delete mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/SsaResponse.java rename jans-auth-server/client/src/main/java/io/jans/as/client/{SsaClient.java => ssa/create/SsaCreateClient.java} (52%) rename jans-auth-server/client/src/main/java/io/jans/as/client/{SsaRequest.java => ssa/create/SsaCreateRequest.java} (83%) create mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateResponse.java create mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetClient.java create mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetJson.java create mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetRequest.java create mode 100644 jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetResponse.java create mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaCreateAssertBuilder.java create mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaGetAssertBuilder.java delete mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaResponseAssertBuilder.java create mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaCreateRestTest.java create mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaGetRestTest.java delete mode 100644 jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SsaRestWebServiceHttpTest.java create mode 100644 jans-auth-server/model/src/main/java/io/jans/as/model/util/DateUtil.java create mode 100644 jans-auth-server/model/src/test/java/io/jans/as/model/util/DateUtilTest.java create mode 100644 jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaGetAction.java create mode 100644 jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaGetActionTest.java create mode 100644 jans-linux-setup/jans_setup/static/extension/ssa_modify_response/ssa_modify_response.py diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/BaseClient.java b/jans-auth-server/client/src/main/java/io/jans/as/client/BaseClient.java index 50e548a598a..42661dba886 100644 --- a/jans-auth-server/client/src/main/java/io/jans/as/client/BaseClient.java +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/BaseClient.java @@ -142,10 +142,6 @@ public String getRequestAsString() { String accessToken = ((UserInfoRequest) request).getAccessToken(); sb.append("\n"); sb.append(Constants.AUTHORIZATION_BEARER).append(accessToken); - } else if (request.getAuthorizationMethod() == AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD && request instanceof SsaRequest) { - String accessToken = ((SsaRequest) request).getAccessToken(); - sb.append("\n"); - sb.append(Constants.AUTHORIZATION_BEARER).append(accessToken); } sb.append("\n"); diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaResponse.java b/jans-auth-server/client/src/main/java/io/jans/as/client/SsaResponse.java deleted file mode 100644 index b5551a4c130..00000000000 --- a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaResponse.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. - * - * Copyright (c) 2020, Janssen Project - */ - -package io.jans.as.client; - -import io.jans.as.model.ssa.SsaErrorResponseType; -import jakarta.ws.rs.core.Response; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.json.JSONException; -import org.json.JSONObject; - -public class SsaResponse extends BaseResponseWithErrors { - - private static final Logger LOG = Logger.getLogger(SsaResponse.class); - - private String ssa; - - public SsaResponse() { - } - - public SsaResponse(Response clientResponse) { - super(clientResponse); - } - - @Override - public SsaErrorResponseType fromString(String p_str) { - return SsaErrorResponseType.fromString(p_str); - } - - public void injectDataFromJson() { - injectDataFromJson(entity); - } - - @Override - public void injectDataFromJson(String json) { - if (StringUtils.isNotBlank(entity)) { - try { - JSONObject jsonObj = new JSONObject(entity); - if (jsonObj.has("ssa")) { - setSsa(jsonObj.getString("ssa")); - } - } catch (JSONException e) { - LOG.error(e.getMessage(), e); - } - } - } - - public String getSsa() { - return ssa; - } - - public void setSsa(String ssa) { - this.ssa = ssa; - } -} \ No newline at end of file diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaClient.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateClient.java similarity index 52% rename from jans-auth-server/client/src/main/java/io/jans/as/client/SsaClient.java rename to jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateClient.java index d5b6aa3487a..8a3a97a7463 100644 --- a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaClient.java +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateClient.java @@ -4,8 +4,9 @@ * Copyright (c) 2020, Janssen Project */ -package io.jans.as.client; +package io.jans.as.client.ssa.create; +import io.jans.as.client.BaseClient; import io.jans.as.model.config.Constants; import jakarta.ws.rs.HttpMethod; import jakarta.ws.rs.client.Entity; @@ -16,11 +17,11 @@ import java.util.List; -public class SsaClient extends BaseClient { +public class SsaCreateClient extends BaseClient { - private static final Logger LOG = Logger.getLogger(SsaClient.class); + private static final Logger LOG = Logger.getLogger(SsaCreateClient.class); - public SsaClient(String url) { + public SsaCreateClient(String url) { super(url); } @@ -29,19 +30,21 @@ public String getHttpMethod() { return HttpMethod.POST; } - public SsaResponse execSsaCreate(String accessToken, Long orgId, Long expirationDate, String description, String softwareId, List softwareRoles, List grantTypes) { - setRequest(new SsaRequest()); - getRequest().setAccessToken(accessToken); - getRequest().setOrgId(orgId); - getRequest().setExpiration(expirationDate); - getRequest().setDescription(description); - getRequest().setSoftwareId(softwareId); - getRequest().setSoftwareRoles(softwareRoles); - getRequest().setGrantTypes(grantTypes); + public SsaCreateResponse execSsaCreate(String accessToken, Long orgId, Long expirationDate, String description, + String softwareId, List softwareRoles, List grantTypes) { + SsaCreateRequest ssaCreateRequest = new SsaCreateRequest(); + ssaCreateRequest.setAccessToken(accessToken); + ssaCreateRequest.setOrgId(orgId); + ssaCreateRequest.setExpiration(expirationDate); + ssaCreateRequest.setDescription(description); + ssaCreateRequest.setSoftwareId(softwareId); + ssaCreateRequest.setSoftwareRoles(softwareRoles); + ssaCreateRequest.setGrantTypes(grantTypes); + setRequest(ssaCreateRequest); return exec(); } - public SsaResponse exec() { + public SsaCreateResponse exec() { try { initClient(); @@ -55,9 +58,9 @@ public SsaResponse exec() { JSONObject requestBody = getRequest().getJSONParameters(); clientResponse = clientRequest.buildPost(Entity.json(requestBody.toString(4))).invoke(); - final SsaResponse ssaResponse = new SsaResponse(clientResponse); - ssaResponse.injectDataFromJson(); - setResponse(ssaResponse); + final SsaCreateResponse ssaCreateResponse = new SsaCreateResponse(clientResponse); + ssaCreateResponse.injectDataFromJson(); + setResponse(ssaCreateResponse); } catch (Exception e) { LOG.error(e.getMessage(), e); diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaRequest.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateRequest.java similarity index 83% rename from jans-auth-server/client/src/main/java/io/jans/as/client/SsaRequest.java rename to jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateRequest.java index 2bf0c149955..51de6f08ca0 100644 --- a/jans-auth-server/client/src/main/java/io/jans/as/client/SsaRequest.java +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateRequest.java @@ -4,10 +4,11 @@ * Copyright (c) 2020, Janssen Project */ -package io.jans.as.client; +package io.jans.as.client.ssa.create; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import io.jans.as.client.BaseRequest; import io.jans.as.client.util.ClientUtil; import io.jans.as.model.common.AuthorizationMethod; import io.jans.as.model.json.JsonApplier; @@ -19,12 +20,13 @@ import java.util.ArrayList; import java.util.List; -import static io.jans.as.client.util.ClientUtil.*; +import static io.jans.as.client.util.ClientUtil.extractListByKey; +import static io.jans.as.client.util.ClientUtil.longOrNull; import static io.jans.as.model.ssa.SsaRequestParam.*; -public class SsaRequest extends BaseRequest { +public class SsaCreateRequest extends BaseRequest { - private static final Logger log = Logger.getLogger(SsaRequest.class); + private static final Logger log = Logger.getLogger(SsaCreateRequest.class); @JsonProperty(value = "org_id") private Long orgId; @@ -50,7 +52,7 @@ public class SsaRequest extends BaseRequest { private String accessToken; - public SsaRequest() { + public SsaCreateRequest() { setContentType(MediaType.APPLICATION_JSON); setMediaType(MediaType.APPLICATION_JSON); setAuthorizationMethod(AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD); @@ -129,21 +131,21 @@ public void setAccessToken(String accessToken) { this.accessToken = accessToken; } - public static SsaRequest fromJson(String json) throws JSONException { + public static SsaCreateRequest fromJson(String json) throws JSONException { return fromJson(new JSONObject(json)); } - public static SsaRequest fromJson(JSONObject requestObject) throws JSONException { - final SsaRequest result = new SsaRequest(); + public static SsaCreateRequest fromJson(JSONObject requestObject) throws JSONException { + final SsaCreateRequest result = new SsaCreateRequest(); JsonApplier.getInstance().apply(requestObject, result); - result.setOrgId(requestObject.getLong(ORG_ID.toString())); - result.setExpiration(longOrNull(requestObject, EXPIRATION.toString())); - result.setDescription(requestObject.optString(DESCRIPTION.toString())); - result.setSoftwareId(requestObject.optString(SOFTWARE_ID.toString())); - result.setSoftwareRoles(extractListByKey(requestObject, SOFTWARE_ROLES.toString())); - result.setGrantTypes(extractListByKey(requestObject, GRANT_TYPES.toString())); - result.setOneTimeUse(booleanOrNull(requestObject, ONE_TIME_USE.toString())); - result.setRotateSsa(booleanOrNull(requestObject, ROTATE_SSA.toString())); + result.setOrgId(requestObject.getLong(ORG_ID.getName())); + result.setExpiration(longOrNull(requestObject, EXPIRATION.getName())); + result.setDescription(requestObject.optString(DESCRIPTION.getName())); + result.setSoftwareId(requestObject.optString(SOFTWARE_ID.getName())); + result.setSoftwareRoles(extractListByKey(requestObject, SOFTWARE_ROLES.getName())); + result.setGrantTypes(extractListByKey(requestObject, GRANT_TYPES.getName())); + result.setOneTimeUse(requestObject.optBoolean(ONE_TIME_USE.getName(), true)); + result.setRotateSsa(requestObject.optBoolean(ROTATE_SSA.getName(), true)); return result; } @@ -182,7 +184,6 @@ public String toString() { ", grantTypes=" + grantTypes + ", oneTimeUse=" + oneTimeUse + ", rotateSsa=" + rotateSsa + - ", accessToken='" + accessToken + '\'' + '}'; } } diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateResponse.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateResponse.java new file mode 100644 index 00000000000..9838def3ba5 --- /dev/null +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/create/SsaCreateResponse.java @@ -0,0 +1,83 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa.create; + +import io.jans.as.client.BaseResponseWithErrors; +import io.jans.as.model.jwt.Jwt; +import io.jans.as.model.jwt.JwtClaims; +import io.jans.as.model.ssa.SsaErrorResponseType; +import jakarta.ws.rs.core.Response; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Objects; + +import static io.jans.as.model.ssa.SsaRequestParam.JTI; +import static io.jans.as.model.ssa.SsaRequestParam.SSA; + +public class SsaCreateResponse extends BaseResponseWithErrors { + + private static final Logger LOG = Logger.getLogger(SsaCreateResponse.class); + + private String ssa; + + private String jti; + + public SsaCreateResponse() { + } + + public SsaCreateResponse(Response clientResponse) { + super(clientResponse); + } + + @Override + public SsaErrorResponseType fromString(String p_str) { + return SsaErrorResponseType.fromString(p_str); + } + + public void injectDataFromJson() { + injectDataFromJson(entity); + } + + @Override + public void injectDataFromJson(String json) { + if (StringUtils.isNotBlank(entity)) { + try { + JSONObject jsonObj = new JSONObject(entity); + if (jsonObj.has(SSA.getName())) { + ssa = jsonObj.getString(SSA.getName()); + if (StringUtils.isNotBlank(ssa)) { + JwtClaims jwtClaims = Objects.requireNonNull(Jwt.parseSilently(ssa)).getClaims(); + if (jwtClaims.hasClaim(JTI.getName())) { + jti = jwtClaims.getClaimAsString(JTI.getName()); + } + } + } + } catch (JSONException e) { + LOG.error(e.getMessage(), e); + } + } + } + + public String getSsa() { + return ssa; + } + + public void setSsa(String ssa) { + this.ssa = ssa; + } + + public String getJti() { + return jti; + } + + public void setJti(String jti) { + this.jti = jti; + } +} \ No newline at end of file diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetClient.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetClient.java new file mode 100644 index 00000000000..e31fad182c5 --- /dev/null +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetClient.java @@ -0,0 +1,75 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa.get; + +import io.jans.as.client.BaseClient; +import io.jans.as.model.config.Constants; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.client.Invocation.Builder; +import org.apache.commons.lang.StringUtils; +import org.apache.http.client.utils.URIBuilder; +import org.apache.log4j.Logger; + +public class SsaGetClient extends BaseClient { + + private static final Logger LOG = Logger.getLogger(SsaGetClient.class); + + public SsaGetClient(String url) { + super(url); + } + + @Override + public String getHttpMethod() { + return HttpMethod.GET; + } + + public SsaGetResponse execSsaGet(String accessToken, String jti, Long orgId, Boolean softwareRoles) { + SsaGetRequest ssaGetRequest = new SsaGetRequest(); + ssaGetRequest.setAccessToken(accessToken); + setRequest(ssaGetRequest); + + URIBuilder uriBuilder = new URIBuilder(); + if (StringUtils.isNotBlank(jti)) { + uriBuilder.addParameter("jti", jti); + } + if (orgId != null && orgId > 0) { + uriBuilder.addParameter("org_id", orgId.toString()); + } + if (softwareRoles != null) { + uriBuilder.addParameter("software_roles", softwareRoles.toString()); + } + setUrl(getUrl() + uriBuilder); + return exec(); + } + + public SsaGetResponse exec() { + try { + initClient(); + + Builder clientRequest = webTarget.request(); + applyCookies(clientRequest); + + clientRequest.header("Content-Type", request.getContentType()); + if (StringUtils.isNotBlank(request.getAccessToken())) { + clientRequest.header(Constants.AUTHORIZATION, "Bearer ".concat(request.getAccessToken())); + } + + clientResponse = clientRequest.buildGet().invoke(); + final SsaGetResponse ssaGetResponse = new SsaGetResponse(clientResponse); + ssaGetResponse.injectDataFromJson(); + setResponse(ssaGetResponse); + + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } finally { + closeConnection(); + } + + return getResponse(); + } +} + diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetJson.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetJson.java new file mode 100644 index 00000000000..b489795c69d --- /dev/null +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetJson.java @@ -0,0 +1,34 @@ +package io.jans.as.client.ssa.get; + +import org.json.JSONObject; + +public class SsaGetJson { + + private String jti; + + private JSONObject jsonObject; + + public String getJti() { + return jti; + } + + public void setJti(String jti) { + this.jti = jti; + } + + public JSONObject getJsonObject() { + return jsonObject; + } + + public void setJsonObject(JSONObject jsonObject) { + this.jsonObject = jsonObject; + } + + @Override + public String toString() { + return "SsaDTO{" + + "jti='" + jti + '\'' + + ", jsonObject=" + jsonObject + + '}'; + } +} diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetRequest.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetRequest.java new file mode 100644 index 00000000000..efada1cc61e --- /dev/null +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetRequest.java @@ -0,0 +1,35 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa.get; + +import io.jans.as.client.BaseRequest; +import io.jans.as.model.common.AuthorizationMethod; +import jakarta.ws.rs.core.MediaType; + +public class SsaGetRequest extends BaseRequest { + + private String accessToken; + + public SsaGetRequest() { + setContentType(MediaType.APPLICATION_JSON); + setMediaType(MediaType.APPLICATION_JSON); + setAuthorizationMethod(AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD); + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public String getQueryString() { + return null; + } +} diff --git a/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetResponse.java b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetResponse.java new file mode 100644 index 00000000000..c64c291991d --- /dev/null +++ b/jans-auth-server/client/src/main/java/io/jans/as/client/ssa/get/SsaGetResponse.java @@ -0,0 +1,79 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa.get; + +import io.jans.as.client.BaseResponseWithErrors; +import io.jans.as.model.ssa.SsaErrorResponseType; +import jakarta.ws.rs.core.Response; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static io.jans.as.client.util.ClientUtil.stringOrNull; +import static io.jans.as.model.ssa.SsaRequestParam.JTI; +import static io.jans.as.model.ssa.SsaRequestParam.SSA; + +public class SsaGetResponse extends BaseResponseWithErrors { + + private static final Logger LOG = Logger.getLogger(SsaGetResponse.class); + + private List ssaList = new ArrayList<>(); + + public SsaGetResponse() { + } + + public SsaGetResponse(Response clientResponse) { + super(clientResponse); + } + + public List getSsaList() { + return ssaList; + } + + public void setSsaList(List ssaList) { + this.ssaList = ssaList; + } + + @Override + public SsaErrorResponseType fromString(String p_str) { + return SsaErrorResponseType.fromString(p_str); + } + + public void injectDataFromJson() { + injectDataFromJson(entity); + } + + @Override + public void injectDataFromJson(String json) { + if (StringUtils.isNotBlank(entity)) { + try { + JSONArray jsonArray = new JSONArray(entity); + if (!jsonArray.isEmpty()) { + for (Object item : jsonArray) { + if (item instanceof JSONObject) { + JSONObject ssaWrapper = (JSONObject) item; + SsaGetJson ssaGetJson = new SsaGetJson(); + ssaGetJson.setJsonObject(ssaWrapper); + if (ssaWrapper.has(SSA.getName())) { + JSONObject ssaJson = ssaWrapper.getJSONObject(SSA.getName()); + ssaGetJson.setJti(stringOrNull(ssaJson, JTI.getName())); + } + ssaList.add(ssaGetJson); + } + } + } + } catch (JSONException e) { + LOG.error(e.getMessage(), e); + } + } + } +} \ No newline at end of file diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/BaseTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/BaseTest.java index 115535c4d43..3d0ad3ee3aa 100644 --- a/jans-auth-server/client/src/test/java/io/jans/as/client/BaseTest.java +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/BaseTest.java @@ -1116,6 +1116,23 @@ public RegisterResponse registerClient(final String redirectUris, List responseTypes, List grantTypes, List scopes, String sectorIdentifierUri) { + RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "jans test app", + io.jans.as.model.util.StringUtils.spaceSeparatedToList(redirectUris)); + registerRequest.setResponseTypes(responseTypes); + registerRequest.setScope(scopes); + registerRequest.setGrantTypes(grantTypes); + registerRequest.setSubjectType(SubjectType.PAIRWISE); + registerRequest.setSectorIdentifierUri(sectorIdentifierUri); + + RegisterClient registerClient = newRegisterClient(registerRequest); + RegisterResponse registerResponse = registerClient.exec(); + + showClient(registerClient); + AssertBuilder.registerResponse(registerResponse).created().check(); + return registerResponse; + } + public RegisterResponse registerClient( final String redirectUris, final List responseTypes, final String sectorIdentifierUri, final String clientJwksUri, final SignatureAlgorithm signatureAlgorithm, @@ -1218,4 +1235,12 @@ public AuthorizationResponse authorizationRequest( return authorizationResponse; } + + public TokenResponse tokenClientCredentialsGrant(String scope, String clientId, String clientSecret) { + TokenClient tokenClient = new TokenClient(tokenEndpoint); + TokenResponse tokenResponse = tokenClient.execClientCredentialsGrant(scope, clientId, clientSecret); + showClient(tokenClient); + AssertBuilder.tokenResponse(tokenResponse).ok().check(); + return tokenResponse; + } } diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/client/AssertBuilder.java b/jans-auth-server/client/src/test/java/io/jans/as/client/client/AssertBuilder.java index 0c8640c9dd9..242604deba7 100644 --- a/jans-auth-server/client/src/test/java/io/jans/as/client/client/AssertBuilder.java +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/client/AssertBuilder.java @@ -9,6 +9,9 @@ import io.jans.as.client.*; import io.jans.as.client.client.assertbuilders.*; import io.jans.as.client.par.ParResponse; +import io.jans.as.client.ssa.create.SsaCreateRequest; +import io.jans.as.client.ssa.create.SsaCreateResponse; +import io.jans.as.client.ssa.get.SsaGetResponse; import io.jans.as.model.exception.InvalidJwtException; import io.jans.as.model.jwe.Jwe; import io.jans.as.model.jwt.Jwt; @@ -55,7 +58,11 @@ public static JweAssertBuilder jwe(Jwe jwe) { return new JweAssertBuilder(jwe); } - public static SsaResponseAssertBuilder ssaResponse(SsaRequest request, SsaResponse response) { - return new SsaResponseAssertBuilder(request, response); + public static SsaCreateAssertBuilder ssaCreate(SsaCreateRequest request, SsaCreateResponse response) { + return new SsaCreateAssertBuilder(request, response); + } + + public static SsaGetAssertBuilder ssaGet(SsaGetResponse response) { + return new SsaGetAssertBuilder(response); } } diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaCreateAssertBuilder.java b/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaCreateAssertBuilder.java new file mode 100644 index 00000000000..3cd9d610ccd --- /dev/null +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaCreateAssertBuilder.java @@ -0,0 +1,62 @@ +package io.jans.as.client.client.assertbuilders; + +import io.jans.as.client.ssa.create.SsaCreateRequest; +import io.jans.as.client.ssa.create.SsaCreateResponse; +import io.jans.as.model.jwt.Jwt; +import io.jans.as.model.jwt.JwtClaims; +import org.apache.http.HttpStatus; + +import static io.jans.as.model.ssa.SsaRequestParam.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +public class SsaCreateAssertBuilder extends BaseAssertBuilder { + + private final SsaCreateRequest request; + private final SsaCreateResponse response; + private int status = HttpStatus.SC_CREATED; + + public SsaCreateAssertBuilder(SsaCreateRequest request, SsaCreateResponse response) { + this.request = request; + this.response = response; + } + + public SsaCreateAssertBuilder status(int status) { + this.status = status; + return this; + } + + @Override + public void check() { + assertNotNull(response, "SsaCreateResponse is null"); + assertEquals(response.getStatus(), status, "Unexpected response code: " + response.getStatus()); + if (status == HttpStatus.SC_CREATED) { + assertNotNull(response.getEntity(), "The entity is null"); + assertNotNull(response.getSsa(), "The ssa token is null"); + + Jwt jwt = Jwt.parseSilently(response.getSsa()); + assertNotNull(jwt, "The jwt is null"); + JwtClaims jwtClaims = jwt.getClaims(); + assertNotNull(jwtClaims.getClaim(ORG_ID.getName()), "The org_id in jwt is null"); + assertEquals(jwtClaims.getClaimAsLong(ORG_ID.getName()), request.getOrgId()); + assertNotNull(jwtClaims.getClaim(SOFTWARE_ID.getName()), "The software_id in jwt is null"); + assertEquals(jwtClaims.getClaimAsString(SOFTWARE_ID.getName()), request.getSoftwareId()); + assertNotNull(jwtClaims.getClaim(SOFTWARE_ROLES.getName()), "The software_roles in jwt is null"); + assertEquals(jwtClaims.getClaimAsStringList(SOFTWARE_ROLES.getName()), request.getSoftwareRoles()); + assertNotNull(jwtClaims.getClaim(GRANT_TYPES.getName()), "The grant_types in jwt is null"); + assertEquals(jwtClaims.getClaimAsStringList(GRANT_TYPES.getName()), request.getGrantTypes()); + + assertNotNull(jwtClaims.getClaim(JTI.getName()), "The jti in jwt is null"); + assertNotNull(jwtClaims.getClaim(ISS.getName()), "The iss in jwt is null"); + assertNotNull(jwtClaims.getClaim(IAT.getName()), "The iat in jwt is null"); + assertNotNull(jwtClaims.getClaim(EXP.getName()), "The exp in jwt is null"); + if (request.getExpiration() != null) { + assertEquals(jwtClaims.getClaimAsLong(EXP.getName()), request.getExpiration()); + } + } else { + assertEquals(response.getStatus(), status, "Unexpected HTTP status response: " + response.getEntity()); + assertNotNull(response.getEntity(), "The entity is null"); + assertNotNull(response.getErrorDescription()); + } + } +} diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaGetAssertBuilder.java b/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaGetAssertBuilder.java new file mode 100644 index 00000000000..3be3e5b1988 --- /dev/null +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaGetAssertBuilder.java @@ -0,0 +1,78 @@ +package io.jans.as.client.client.assertbuilders; + +import io.jans.as.client.ssa.get.SsaGetJson; +import io.jans.as.client.ssa.get.SsaGetResponse; +import org.apache.http.HttpStatus; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import static io.jans.as.model.ssa.SsaRequestParam.*; +import static org.testng.Assert.*; + +public class SsaGetAssertBuilder extends BaseAssertBuilder { + + private final SsaGetResponse response; + + private Integer ssaListSize; + + private List jtiList; + + public SsaGetAssertBuilder(SsaGetResponse response) { + this.response = response; + } + + public SsaGetAssertBuilder ssaListSize(Integer ssaListSize) { + this.ssaListSize = ssaListSize; + return this; + } + + public SsaGetAssertBuilder jtiList(List jtiList) { + this.jtiList = jtiList; + return this; + } + + @Override + public void check() { + assertNotNull(response, "SsaResponse is null"); + assertEquals(response.getStatus(), HttpStatus.SC_OK, "Unexpected response code: " + response.getStatus()); + assertNotNull(response.getEntity(), "The entity is null"); + assertNotNull(response.getSsaList(), "The ssaList is null"); + if (jtiList != null && !jtiList.isEmpty()) { + response.setSsaList(filterSsaList(response.getSsaList(), jtiList)); + } + + if (ssaListSize != null) { + assertEquals(response.getSsaList().size(), ssaListSize.intValue()); + if (ssaListSize > 0) { + response.getSsaList().forEach(ssaGetJson -> { + JSONObject ssaWrapper = ssaGetJson.getJsonObject(); + assertNotNull(ssaWrapper); + assertTrue(ssaWrapper.has(SSA.getName())); + assertTrue(ssaWrapper.has(CREATED_AT.getName())); + assertTrue(ssaWrapper.has(EXPIRATION.getName())); + assertTrue(ssaWrapper.has(ISSUER.getName())); + + JSONObject ssaJson = ssaWrapper.getJSONObject(SSA.getName()); + assertNotNull(ssaJson); + assertTrue(ssaJson.has(ISS.getName())); + assertTrue(ssaJson.has(IAT.getName())); + assertTrue(ssaJson.has(JTI.getName())); + assertTrue(ssaJson.has(SOFTWARE_ID.getName())); + assertTrue(ssaJson.has(SOFTWARE_ROLES.getName())); + assertTrue(ssaJson.has(GRANT_TYPES.getName())); + assertTrue(ssaJson.has(EXP.getName())); + }); + } + } + } + + private List filterSsaList(List ssaGetJsonList, List jtiList) { + List ssaList = new ArrayList<>(); + jtiList.forEach(s -> ssaGetJsonList.stream() + .filter(ssaGetJson -> ssaGetJson.getJti().equals(s)) + .findFirst().map(ssaList::add)); + return ssaList; + } +} diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaResponseAssertBuilder.java b/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaResponseAssertBuilder.java deleted file mode 100644 index 0d5759591a0..00000000000 --- a/jans-auth-server/client/src/test/java/io/jans/as/client/client/assertbuilders/SsaResponseAssertBuilder.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.jans.as.client.client.assertbuilders; - -import io.jans.as.client.SsaRequest; -import io.jans.as.client.SsaResponse; -import io.jans.as.model.jwt.Jwt; -import io.jans.as.model.jwt.JwtClaims; -import io.jans.as.model.ssa.SsaErrorResponseType; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - -public class SsaResponseAssertBuilder extends BaseAssertBuilder { - - private final SsaRequest request; - private final SsaResponse response; - private int status = 200; - private SsaErrorResponseType errorResponseType; - - public SsaResponseAssertBuilder(SsaRequest request, SsaResponse response) { - this.request = request; - this.response = response; - } - - public SsaResponseAssertBuilder ok() { - this.status = 200; - return this; - } - - public SsaResponseAssertBuilder created() { - this.status = 201; - return this; - } - - public SsaResponseAssertBuilder bad(SsaErrorResponseType responseType) { - this.status = 400; - this.errorResponseType = responseType; - return this; - } - - public SsaResponseAssertBuilder status(int status) { - this.status = status; - return this; - } - - public SsaResponseAssertBuilder errorResponseType(SsaErrorResponseType errorResponseType) { - this.errorResponseType = errorResponseType; - return this; - } - - @Override - public void check() { - assertNotNull(response, "SsaResponse is null"); - if (status == 200 || status == 201) { - assertEquals(response.getStatus(), status, "Unexpected response code: " + response.getStatus()); - assertNotNull(response.getEntity(), "The entity is null"); - assertNotNull(response.getSsa(), "The ssa token is null"); - - Jwt jwt = Jwt.parseSilently(response.getSsa()); - assertNotNull(jwt, "The jwt is null"); - JwtClaims jwtClaims = jwt.getClaims(); - assertNotNull(jwtClaims.getClaim("org_id"), "The org_id in jwt is null"); - assertEquals(jwtClaims.getClaimAsLong("org_id"), request.getOrgId()); - assertNotNull(jwtClaims.getClaim("software_id"), "The software_id in jwt is null"); - assertEquals(jwtClaims.getClaimAsString("software_id"), request.getSoftwareId()); - assertNotNull(jwtClaims.getClaim("software_roles"), "The software_roles in jwt is null"); - assertEquals(jwtClaims.getClaimAsStringList("software_roles"), request.getSoftwareRoles()); - assertNotNull(jwtClaims.getClaim("grant_types"), "The grant_types in jwt is null"); - assertEquals(jwtClaims.getClaimAsStringList("grant_types"), request.getGrantTypes()); - - assertNotNull(jwtClaims.getClaim("jti"), "The jti in jwt is null"); - assertNotNull(jwtClaims.getClaim("iss"), "The iss in jwt is null"); - assertNotNull(jwtClaims.getClaim("iat"), "The iat in jwt is null"); - assertNotNull(jwtClaims.getClaim("exp"), "The exp in jwt is null"); - if (request.getExpiration() != null) { - assertEquals(jwtClaims.getClaimAsLong("exp"), request.getExpiration()); - } - } else { - assertEquals(response.getStatus(), status, "Unexpected HTTP status response: " + response.getEntity()); - assertNotNull(response.getEntity(), "The entity is null"); - if (errorResponseType != null) { - assertEquals(response.getErrorType(), errorResponseType, "Unexpected error type, should be " + errorResponseType.getParameter()); - } - assertNotNull(response.getErrorDescription()); - } - } -} diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaCreateRestTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaCreateRestTest.java new file mode 100644 index 00000000000..4d9897e661a --- /dev/null +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaCreateRestTest.java @@ -0,0 +1,120 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa; + +import io.jans.as.client.BaseTest; +import io.jans.as.client.RegisterResponse; +import io.jans.as.client.TokenResponse; +import io.jans.as.client.client.AssertBuilder; +import io.jans.as.client.ssa.create.SsaCreateClient; +import io.jans.as.client.ssa.create.SsaCreateResponse; +import io.jans.as.model.common.GrantType; +import io.jans.as.model.common.ResponseType; +import io.jans.as.model.ssa.SsaScopeType; +import io.jans.as.model.util.DateUtil; +import org.apache.http.HttpStatus; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import java.util.*; + +public class SsaCreateRestTest extends BaseTest { + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void createSsaValid(final String redirectUris, final String sectorIdentifierUri) { + showTitle("createSsaValid"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Ssa create + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + Long orgId = 1L; + Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC")); + calendar.add(Calendar.HOUR, 24); + Long expirationDate = DateUtil.dateToUnixEpoch(calendar.getTime()); + String description = "test description"; + String softwareId = "gluu-scan-api"; + List softwareRoles = Collections.singletonList("passwurd"); + List ssaGrantTypes = Collections.singletonList("client_credentials"); + SsaCreateResponse ssaCreateResponse = ssaCreateClient.execSsaCreate(accessToken, orgId, expirationDate, description, softwareId, softwareRoles, ssaGrantTypes); + + showClient(ssaCreateClient); + AssertBuilder.ssaCreate(ssaCreateClient.getRequest(), ssaCreateResponse).check(); + } + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void createSsaInvalidWithoutScopeAdmin(final String redirectUris, final String sectorIdentifierUri) { + showTitle("createSsaInvalidWithoutScopeAdmin"); + List scopes = Collections.singletonList("openid"); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant("", clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Ssa create + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + Long orgId = 1L; + Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC")); + calendar.add(Calendar.HOUR, 24); + Long expirationDate = DateUtil.dateToUnixEpoch(calendar.getTime()); + String description = "test description"; + String softwareId = "gluu-scan-api"; + List softwareRoles = Collections.singletonList("passwurd"); + List ssaGrantTypes = Collections.singletonList("client_credentials"); + SsaCreateResponse ssaCreateResponse = ssaCreateClient.execSsaCreate(accessToken, orgId, expirationDate, description, softwareId, softwareRoles, ssaGrantTypes); + + showClient(ssaCreateClient); + AssertBuilder.ssaCreate(ssaCreateClient.getRequest(), ssaCreateResponse) + .status(HttpStatus.SC_UNAUTHORIZED).check(); + } + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void createSsaValidWithoutExpiration(final String redirectUris, final String sectorIdentifierUri) { + showTitle("createSsaValidWithoutExpiration"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Ssa create + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + Long orgId = 1L; + String description = "test description"; + String softwareId = "gluu-scan-api"; + List softwareRoles = Collections.singletonList("passwurd"); + List ssaGrantTypes = Collections.singletonList("client_credentials"); + SsaCreateResponse ssaCreateResponse = ssaCreateClient.execSsaCreate(accessToken, orgId, null, description, softwareId, softwareRoles, ssaGrantTypes); + + showClient(ssaCreateClient); + AssertBuilder.ssaCreate(ssaCreateClient.getRequest(), ssaCreateResponse).check(); + } +} \ No newline at end of file diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaGetRestTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaGetRestTest.java new file mode 100644 index 00000000000..0983fbc1cbe --- /dev/null +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/ssa/SsaGetRestTest.java @@ -0,0 +1,173 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.as.client.ssa; + +import io.jans.as.client.BaseTest; +import io.jans.as.client.RegisterResponse; +import io.jans.as.client.TokenResponse; +import io.jans.as.client.client.AssertBuilder; +import io.jans.as.client.ssa.create.SsaCreateClient; +import io.jans.as.client.ssa.create.SsaCreateResponse; +import io.jans.as.client.ssa.get.SsaGetClient; +import io.jans.as.client.ssa.get.SsaGetResponse; +import io.jans.as.model.common.GrantType; +import io.jans.as.model.common.ResponseType; +import io.jans.as.model.ssa.SsaScopeType; +import org.testng.Assert; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SsaGetRestTest extends BaseTest { + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void getSsaSearchByOrgId(final String redirectUris, final String sectorIdentifierUri) { + showTitle("getSsaSearchByOrgId"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Create ssa + Long orgId1 = 1000L; + Long orgId2 = 2000L; + List ssaCreateOrgId = Arrays.asList(orgId1, orgId1, orgId2); + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + List jtiList = createSsaList(ssaCreateClient, accessToken, ssaCreateOrgId); + + // Ssa get + SsaGetClient ssaGetClient = new SsaGetClient(ssaEndpoint); + SsaGetResponse ssaGetResponse = ssaGetClient.execSsaGet(accessToken, null, orgId1, false); + AssertBuilder.ssaGet(ssaGetResponse) + .ssaListSize(2) + .jtiList(jtiList) + .check(); + } + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void getSsaSearchByJti(final String redirectUris, final String sectorIdentifierUri) { + showTitle("getSsaSearchByJti"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Create ssa + Long orgId1 = 1000L; + List ssaCreateOrgId = Arrays.asList(orgId1, orgId1); + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + List jtiList = createSsaList(ssaCreateClient, accessToken, ssaCreateOrgId); + String jti = jtiList.get(0); + + // Ssa get + SsaGetClient ssaGetClient = new SsaGetClient(ssaEndpoint); + SsaGetResponse ssaGetResponse = ssaGetClient.execSsaGet(accessToken, jti, null, false); + AssertBuilder.ssaGet(ssaGetResponse) + .ssaListSize(1) + .jtiList(jtiList) + .check(); + } + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void getSsaSearchByOrgIdAndJti(final String redirectUris, final String sectorIdentifierUri) { + showTitle("getSsaSearchByOrgIdAndJti"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Create ssa + Long orgId1 = 1000L; + Long orgId2 = 2000L; + List ssaCreateOrgId = Arrays.asList(orgId1, orgId1, orgId2); + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + List jtiList = createSsaList(ssaCreateClient, accessToken, ssaCreateOrgId); + String jti = jtiList.get(0); + + // Ssa get + SsaGetClient ssaGetClient = new SsaGetClient(ssaEndpoint); + SsaGetResponse ssaGetResponse = ssaGetClient.execSsaGet(accessToken, jti, orgId1, false); + AssertBuilder.ssaGet(ssaGetResponse) + .ssaListSize(1) + .jtiList(jtiList) + .check(); + } + + @Parameters({"redirectUris", "sectorIdentifierUri"}) + @Test + public void getSsaSearchByJtiNotExits(final String redirectUris, final String sectorIdentifierUri) { + showTitle("getSsaSearchByJtiNotExits"); + List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + + // Register client + RegisterResponse registerResponse = registerClient(redirectUris, Collections.singletonList(ResponseType.CODE), + Collections.singletonList(GrantType.CLIENT_CREDENTIALS), scopes, sectorIdentifierUri); + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + // Access token + TokenResponse tokenResponse = tokenClientCredentialsGrant(SsaScopeType.SSA_ADMIN.getValue(), clientId, clientSecret); + String accessToken = tokenResponse.getAccessToken(); + + // Create ssa + Long orgId1 = 1000L; + List ssaCreateOrgId = Arrays.asList(orgId1, orgId1); + SsaCreateClient ssaCreateClient = new SsaCreateClient(ssaEndpoint); + List jtiList = createSsaList(ssaCreateClient, accessToken, ssaCreateOrgId); + String jti = "jti-not-found"; + + // Ssa get + SsaGetClient ssaGetClient = new SsaGetClient(ssaEndpoint); + SsaGetResponse ssaGetResponse = ssaGetClient.execSsaGet(accessToken, jti, null, false); + AssertBuilder.ssaGet(ssaGetResponse) + .ssaListSize(0) + .jtiList(jtiList) + .check(); + } + + private List createSsaList(SsaCreateClient ssaCreateClient, String accessToken, List ssaCreateRequestList) { + List jtiList = new ArrayList<>(); + for (int i = 0; i < ssaCreateRequestList.size(); i++) { + Long orgId = ssaCreateRequestList.get(i); + SsaCreateResponse ssaCreateResponse = ssaCreateClient.execSsaCreate(accessToken, orgId, null, + "test description", "gluu-scan-api", Collections.singletonList("passwurd"), + Collections.singletonList("client_credentials")); + showClient(ssaCreateClient); + Assert.assertNotNull(ssaCreateResponse, "Ssa create response is null, index: " + i); + jtiList.add(ssaCreateResponse.getJti()); + } + return jtiList; + } +} \ No newline at end of file diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SsaRestWebServiceHttpTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SsaRestWebServiceHttpTest.java deleted file mode 100644 index 92eb027b91a..00000000000 --- a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SsaRestWebServiceHttpTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. - * - * Copyright (c) 2020, Janssen Project - */ - -package io.jans.as.client.ws.rs; - -import io.jans.as.client.*; -import io.jans.as.client.client.AssertBuilder; -import io.jans.as.model.common.GrantType; -import io.jans.as.model.common.ResponseType; -import io.jans.as.model.register.ApplicationType; -import io.jans.as.model.ssa.SsaScopeType; -import io.jans.as.model.util.StringUtils; -import jakarta.ws.rs.core.Response; -import org.testng.annotations.Parameters; -import org.testng.annotations.Test; - -import java.util.*; - -import static io.jans.as.client.client.Asserter.assertRegisterResponseClaimsNotNull; -import static io.jans.as.model.register.RegisterRequestParam.*; - -public class SsaRestWebServiceHttpTest extends BaseTest { - - @Parameters({"redirectUris", "sectorIdentifierUri"}) - @Test - public void createSsaValid(final String redirectUris, final String sectorIdentifierUri) { - showTitle("createSsaValid"); - - List responseTypes = Collections.singletonList(ResponseType.CODE); - List grantTypes = Collections.singletonList(GrantType.CLIENT_CREDENTIALS); - List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); - - // 1. Register client - RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "ssa client test app", StringUtils.spaceSeparatedToList(redirectUris)); - registerRequest.setGrantTypes(grantTypes); - registerRequest.setResponseTypes(responseTypes); - registerRequest.setSectorIdentifierUri(sectorIdentifierUri); - registerRequest.setScope(scopes); - - RegisterClient registerClient = new RegisterClient(registrationEndpoint); - registerClient.setRequest(registerRequest); - RegisterResponse registerResponse = registerClient.exec(); - - showClient(registerClient); - AssertBuilder.registerResponse(registerResponse).created().check(); - - String clientId = registerResponse.getClientId(); - String registrationAccessToken = registerResponse.getRegistrationAccessToken(); - String registrationClientUri = registerResponse.getRegistrationClientUri(); - String clientSecret = registerResponse.getClientSecret(); - - // 2. Client read - RegisterRequest readClientRequest = new RegisterRequest(registrationAccessToken); - - RegisterClient readClient = new RegisterClient(registrationClientUri); - readClient.setRequest(readClientRequest); - RegisterResponse readClientResponse = readClient.exec(); - - showClient(readClient); - AssertBuilder.registerResponse(readClientResponse).ok().check(); - - assertRegisterResponseClaimsNotNull(readClientResponse, RESPONSE_TYPES, REDIRECT_URIS, APPLICATION_TYPE, ID_TOKEN_SIGNED_RESPONSE_ALG, SCOPE); - - // 3. access token - String scope = SsaScopeType.SSA_ADMIN.getValue(); - TokenClient tokenClient = new TokenClient(tokenEndpoint); - TokenResponse tokenResponse = tokenClient.execClientCredentialsGrant(scope, clientId, clientSecret); - - showClient(tokenClient); - AssertBuilder.tokenResponse(tokenResponse).ok().check(); - - String accessToken = tokenResponse.getAccessToken(); - - // 4. Ssa create - SsaClient ssaClient = new SsaClient(ssaEndpoint); - Long orgId = 1L; - Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.add(Calendar.HOUR, 24); - Long expirationDate = calendar.getTime().getTime() / 1000L; - String description = "test description"; - String softwareId = "gluu-scan-api"; - List softwareRoles = Collections.singletonList("passwurd"); - List ssaGrantTypes = Collections.singletonList("client_credentials"); - SsaResponse ssaResponse = ssaClient.execSsaCreate(accessToken, orgId, expirationDate, description, softwareId, softwareRoles, ssaGrantTypes); - - showClient(ssaClient); - AssertBuilder.ssaResponse(ssaClient.getRequest(), ssaResponse).created().check(); - } - - @Parameters({"redirectUris", "sectorIdentifierUri"}) - @Test - public void createSsaInvalidWithoutScopeAdmin(final String redirectUris, final String sectorIdentifierUri) { - showTitle("createSsaInvalidWithoutScopeAdmin"); - - List responseTypes = Collections.singletonList(ResponseType.CODE); - List grantTypes = Collections.singletonList(GrantType.CLIENT_CREDENTIALS); - List scopes = Collections.singletonList("openid"); - - // 1. Register client - RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "ssa client test app", StringUtils.spaceSeparatedToList(redirectUris)); - registerRequest.setGrantTypes(grantTypes); - registerRequest.setResponseTypes(responseTypes); - registerRequest.setSectorIdentifierUri(sectorIdentifierUri); - registerRequest.setScope(scopes); - - RegisterClient registerClient = new RegisterClient(registrationEndpoint); - registerClient.setRequest(registerRequest); - RegisterResponse registerResponse = registerClient.exec(); - - showClient(registerClient); - AssertBuilder.registerResponse(registerResponse).created().check(); - - String clientId = registerResponse.getClientId(); - String registrationAccessToken = registerResponse.getRegistrationAccessToken(); - String registrationClientUri = registerResponse.getRegistrationClientUri(); - String clientSecret = registerResponse.getClientSecret(); - - // 2. Client read - RegisterRequest readClientRequest = new RegisterRequest(registrationAccessToken); - - RegisterClient readClient = new RegisterClient(registrationClientUri); - readClient.setRequest(readClientRequest); - RegisterResponse readClientResponse = readClient.exec(); - - showClient(readClient); - AssertBuilder.registerResponse(readClientResponse).ok().check(); - - assertRegisterResponseClaimsNotNull(readClientResponse, RESPONSE_TYPES, REDIRECT_URIS, APPLICATION_TYPE, ID_TOKEN_SIGNED_RESPONSE_ALG, SCOPE); - - // 3. access token - String scope = ""; - TokenClient tokenClient = new TokenClient(tokenEndpoint); - TokenResponse tokenResponse = tokenClient.execClientCredentialsGrant(scope, clientId, clientSecret); - - showClient(tokenClient); - AssertBuilder.tokenResponse(tokenResponse).ok().check(); - - String accessToken = tokenResponse.getAccessToken(); - - // 4. Ssa create - SsaClient ssaClient = new SsaClient(ssaEndpoint); - Long orgId = 1L; - Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.add(Calendar.HOUR, 24); - Long expirationDate = calendar.getTime().getTime() / 1000L; - String description = "test description"; - String softwareId = "gluu-scan-api"; - List softwareRoles = Collections.singletonList("passwurd"); - List ssaGrantTypes = Collections.singletonList("client_credentials"); - SsaResponse ssaResponse = ssaClient.execSsaCreate(accessToken, orgId, expirationDate, description, softwareId, softwareRoles, ssaGrantTypes); - - showClient(ssaClient); - AssertBuilder.ssaResponse(ssaClient.getRequest(), ssaResponse).status(Response.Status.UNAUTHORIZED.getStatusCode()).check(); - } - - @Parameters({"redirectUris", "sectorIdentifierUri"}) - @Test - public void createSsaValidWithoutExpiration(final String redirectUris, final String sectorIdentifierUri) { - showTitle("createSsaValidWithoutExpiration"); - - List responseTypes = Collections.singletonList(ResponseType.CODE); - List grantTypes = Collections.singletonList(GrantType.CLIENT_CREDENTIALS); - List scopes = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); - - // 1. Register client - RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "ssa client test app", StringUtils.spaceSeparatedToList(redirectUris)); - registerRequest.setGrantTypes(grantTypes); - registerRequest.setResponseTypes(responseTypes); - registerRequest.setSectorIdentifierUri(sectorIdentifierUri); - registerRequest.setScope(scopes); - - RegisterClient registerClient = new RegisterClient(registrationEndpoint); - registerClient.setRequest(registerRequest); - RegisterResponse registerResponse = registerClient.exec(); - - showClient(registerClient); - AssertBuilder.registerResponse(registerResponse).created().check(); - - String clientId = registerResponse.getClientId(); - String registrationAccessToken = registerResponse.getRegistrationAccessToken(); - String registrationClientUri = registerResponse.getRegistrationClientUri(); - String clientSecret = registerResponse.getClientSecret(); - - // 2. Client read - RegisterRequest readClientRequest = new RegisterRequest(registrationAccessToken); - - RegisterClient readClient = new RegisterClient(registrationClientUri); - readClient.setRequest(readClientRequest); - RegisterResponse readClientResponse = readClient.exec(); - - showClient(readClient); - AssertBuilder.registerResponse(readClientResponse).ok().check(); - - assertRegisterResponseClaimsNotNull(readClientResponse, RESPONSE_TYPES, REDIRECT_URIS, APPLICATION_TYPE, ID_TOKEN_SIGNED_RESPONSE_ALG, SCOPE); - - // 3. access token - String scope = SsaScopeType.SSA_ADMIN.getValue(); - TokenClient tokenClient = new TokenClient(tokenEndpoint); - TokenResponse tokenResponse = tokenClient.execClientCredentialsGrant(scope, clientId, clientSecret); - - showClient(tokenClient); - AssertBuilder.tokenResponse(tokenResponse).ok().check(); - - String accessToken = tokenResponse.getAccessToken(); - - // 4. Ssa create - SsaClient ssaClient = new SsaClient(ssaEndpoint); - Long orgId = 1L; - String description = "test description"; - String softwareId = "gluu-scan-api"; - List softwareRoles = Collections.singletonList("passwurd"); - List ssaGrantTypes = Collections.singletonList("client_credentials"); - SsaResponse ssaResponse = ssaClient.execSsaCreate(accessToken, orgId, null, description, softwareId, softwareRoles, ssaGrantTypes); - - showClient(ssaClient); - AssertBuilder.ssaResponse(ssaClient.getRequest(), ssaResponse).created().check(); - } -} \ No newline at end of file diff --git a/jans-auth-server/client/src/test/resources/testng.xml b/jans-auth-server/client/src/test/resources/testng.xml index 22511197a5e..3c041b0ffc8 100644 --- a/jans-auth-server/client/src/test/resources/testng.xml +++ b/jans-auth-server/client/src/test/resources/testng.xml @@ -1169,9 +1169,14 @@ - + - + + + + + + diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaRequestParam.java b/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaRequestParam.java index 021836a315d..e1849c9898f 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaRequestParam.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaRequestParam.java @@ -16,6 +16,14 @@ public enum SsaRequestParam { GRANT_TYPES("grant_types"), ONE_TIME_USE("one_time_use"), ROTATE_SSA("rotate_ssa"), + + CREATED_AT("created_at"), + ISSUER("iss"), + JTI("jti"), + ISS("iss"), + EXP("exp"), + IAT("iat"), + SSA("ssa"), ; private final String name; diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaScopeType.java b/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaScopeType.java index c9f1e5af82e..aeca4bb2ffb 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaScopeType.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/ssa/SsaScopeType.java @@ -11,7 +11,11 @@ public enum SsaScopeType { - SSA_ADMIN("https://jans.io/auth/ssa.admin"); + SSA_ADMIN("https://jans.io/auth/ssa.admin"), + SSA_PORTAL("https://jans.io/auth/ssa.portal"), + SSA_DEVELOPER("https://jans.io/auth/ssa.developer"), + ; + private static final Map lookup = new HashMap<>(); diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/util/DateUtil.java b/jans-auth-server/model/src/main/java/io/jans/as/model/util/DateUtil.java new file mode 100644 index 00000000000..d96e3d89175 --- /dev/null +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/util/DateUtil.java @@ -0,0 +1,13 @@ +package io.jans.as.model.util; + +import java.util.Date; + +public class DateUtil { + + public static Long dateToUnixEpoch(Date date) { + if (date == null) { + return -1L; + } + return date.getTime() / 1000L; + } +} diff --git a/jans-auth-server/model/src/test/java/io/jans/as/model/util/DateUtilTest.java b/jans-auth-server/model/src/test/java/io/jans/as/model/util/DateUtilTest.java new file mode 100644 index 00000000000..51381053e8a --- /dev/null +++ b/jans-auth-server/model/src/test/java/io/jans/as/model/util/DateUtilTest.java @@ -0,0 +1,29 @@ +package io.jans.as.model.util; + +import io.jans.as.model.BaseTest; +import org.testng.annotations.Test; + +import java.util.Date; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +public class DateUtilTest extends BaseTest { + + @Test + public void dateToUnixEpoch_dateNull_zero() { + showTitle("dateToUnixEpoch_dateNull_zero"); + Long unixEpoch = DateUtil.dateToUnixEpoch(null); + assertNotNull(unixEpoch, "unix epoch is null"); + assertEquals(unixEpoch.longValue(), -1L); + } + + @Test + public void dateToUnixEpoch_validDate_correctUnixEpoch() { + showTitle("dateToUnixEpoch_validDate_correctUnixEpoch"); + Date now = new Date(); + Long unixEpoch = DateUtil.dateToUnixEpoch(now); + assertNotNull(unixEpoch, "unix epoch is null"); + assertEquals(unixEpoch.longValue(), now.getTime() / 1000L); + } +} diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/model/audit/Action.java b/jans-auth-server/server/src/main/java/io/jans/as/server/model/audit/Action.java index c13cb00bfa0..17511badb5d 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/model/audit/Action.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/model/audit/Action.java @@ -25,7 +25,9 @@ public enum Action { SESSION_AUTHENTICATED("SESSION_AUTHENTICATED"), SESSION_DESTROYED("SESSION_DESTROYED"), DEVICE_CODE_AUTHORIZATION("DEVICE_CODE_AUTHORIZATION"), - SSA_CREATE("SSA_CREATE"); + SSA_CREATE("SSA_CREATE"), + SSA_READ("SSA_READ"), + ; private final String value; diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/service/external/ModifySsaResponseService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/service/external/ModifySsaResponseService.java index 6b13fe7ceee..da5ccf34c15 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/service/external/ModifySsaResponseService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/service/external/ModifySsaResponseService.java @@ -13,6 +13,8 @@ import io.jans.model.custom.script.type.ssa.ModifySsaResponseType; import io.jans.service.custom.script.ExternalScriptService; import jakarta.enterprise.context.ApplicationScoped; +import org.jetbrains.annotations.NotNull; +import org.json.JSONArray; import java.util.List; import java.util.function.Function; @@ -28,7 +30,7 @@ public ModifySsaResponseService() { public boolean create(CustomScriptConfiguration script, JsonWebResponse jsonWebResponse, ModifySsaResponseContext context) { try { - log.trace("Executing python modify-ssa-response method, script name: {}, jwt: {}, context: {}", script.getName(), jsonWebResponse, context); + log.trace("Executing python modify-ssa-response method create, script name: {}, jwt: {}, context: {}", script.getName(), jsonWebResponse, context); context.setScript(script); ModifySsaResponseType modifySsaResponseType = (ModifySsaResponseType) script.getExternalType(); @@ -45,7 +47,7 @@ public boolean create(CustomScriptConfiguration script, JsonWebResponse jsonWebR } public boolean create(JsonWebResponse jsonWebResponse, ModifySsaResponseContext context) { - List scripts = customScriptManager.getCustomScriptConfigurationsByScriptType(CustomScriptType.MODIFY_SSA_RESPONSE); + List scripts = getCustomScript(); if (scripts.isEmpty()) { return false; } @@ -60,10 +62,40 @@ public boolean create(JsonWebResponse jsonWebResponse, ModifySsaResponseContext return true; } + public boolean get(JSONArray jsonArray, ModifySsaResponseContext context) { + List scriptList = getCustomScript(); + if (scriptList == null || scriptList.isEmpty()) { + return false; + } + for (CustomScriptConfiguration script : scriptList) { + log.trace("Executing python modify-ssa-response method get, script name: {}, jsonArray: {}, context: {}", script.getName(), jsonArray, context); + context.setScript(script); + + ModifySsaResponseType modifySsaResponseType = (ModifySsaResponseType) script.getExternalType(); + boolean result = false; + try { + result = modifySsaResponseType.get(jsonArray, context); + } catch (Exception e) { + log.error(e.getMessage(), e); + saveScriptError(script.getCustomScript(), e); + } + log.trace("Finished modify-ssa-response method, script name: {}, jsonArray: {}, context: {}, result: {}", script.getName(), jsonArray, context, result); + if (!result) { + return false; + } + } + return true; + } + public Function buildCreateProcessor(final ModifySsaResponseContext context) { return jsonWebResponse -> { create(jsonWebResponse, context); return null; }; } + + @NotNull + private List getCustomScript() { + return customScriptManager.getCustomScriptConfigurationsByScriptType(CustomScriptType.MODIFY_SSA_RESPONSE); + } } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaJsonService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaJsonService.java index d73e2de7582..fb42305883e 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaJsonService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaJsonService.java @@ -7,41 +7,69 @@ package io.jans.as.server.ssa.ws.rs; import io.jans.as.common.model.ssa.Ssa; +import io.jans.as.model.configuration.AppConfiguration; import io.jans.as.model.json.JsonApplier; +import io.jans.as.model.util.DateUtil; import io.jans.as.model.util.Util; import jakarta.ejb.Stateless; +import jakarta.inject.Inject; import jakarta.inject.Named; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.List; + import static io.jans.as.model.ssa.SsaRequestParam.*; @Stateless @Named public class SsaJsonService { + @Inject + private AppConfiguration appConfiguration; + public String jsonObjectToString(JSONObject jsonObject) throws JSONException { return jsonObject.toString(4).replace("\\/", "/"); } - public JSONObject getJSONObject(Ssa ssa) throws JSONException { - JSONObject responseJsonObject = new JSONObject(); - JsonApplier.getInstance().apply(ssa, responseJsonObject); - - Util.addToJSONObjectIfNotNull(responseJsonObject, ORG_ID.toString(), ssa.getOrgId()); - Util.addToJSONObjectIfNotNull(responseJsonObject, EXPIRATION.toString(), ssa.getExpirationDate()); - Util.addToJSONObjectIfNotNull(responseJsonObject, DESCRIPTION.toString(), ssa.getDescription()); - Util.addToJSONObjectIfNotNull(responseJsonObject, SOFTWARE_ID.toString(), ssa.getAttributes().getSoftwareId()); - Util.addToJSONObjectIfNotNull(responseJsonObject, SOFTWARE_ROLES.toString(), ssa.getAttributes().getSoftwareRoles()); - Util.addToJSONObjectIfNotNull(responseJsonObject, GRANT_TYPES.toString(), ssa.getAttributes().getGrantTypes()); - Util.addToJSONObjectIfNotNull(responseJsonObject, ONE_TIME_USE.toString(), ssa.getAttributes().getOneTimeUse()); - Util.addToJSONObjectIfNotNull(responseJsonObject, ROTATE_SSA.toString(), ssa.getAttributes().getRotateSsa()); - return responseJsonObject; + public String jsonArrayToString(JSONArray jsonArray) throws JSONException { + return jsonArray.toString(4).replace("\\/", "/"); + } + + public JSONArray getJSONArray(List ssaList) throws JSONException { + JSONArray jsonArray = new JSONArray(); + if (ssaList == null) { + return jsonArray; + } + for (Ssa ssa : ssaList) { + JSONObject responseJsonObject = new JSONObject(); + JsonApplier.getInstance().apply(ssaList, responseJsonObject); + + Util.addToJSONObjectIfNotNull(responseJsonObject, CREATED_AT.getName(), DateUtil.dateToUnixEpoch(ssa.getCreationDate())); + Util.addToJSONObjectIfNotNull(responseJsonObject, EXPIRATION.getName(), DateUtil.dateToUnixEpoch(ssa.getExpirationDate())); + Util.addToJSONObjectIfNotNull(responseJsonObject, ISSUER.getName(), ssa.getCreatorId()); + + JSONObject jsonSsa = new JSONObject(); + JsonApplier.getInstance().apply(ssa, jsonSsa); + Util.addToJSONObjectIfNotNull(jsonSsa, ORG_ID.getName(), Long.parseLong(ssa.getOrgId())); + Util.addToJSONObjectIfNotNull(jsonSsa, SOFTWARE_ID.getName(), ssa.getAttributes().getSoftwareId()); + Util.addToJSONObjectIfNotNull(jsonSsa, SOFTWARE_ROLES.getName(), ssa.getAttributes().getSoftwareRoles()); + Util.addToJSONObjectIfNotNull(jsonSsa, GRANT_TYPES.getName(), ssa.getAttributes().getGrantTypes()); + Util.addToJSONObjectIfNotNull(jsonSsa, ISS.getName(), appConfiguration.getIssuer()); + Util.addToJSONObjectIfNotNull(jsonSsa, IAT.getName(), DateUtil.dateToUnixEpoch(ssa.getCreationDate())); + Util.addToJSONObjectIfNotNull(jsonSsa, EXP.getName(), DateUtil.dateToUnixEpoch(ssa.getExpirationDate())); + Util.addToJSONObjectIfNotNull(jsonSsa, JTI.getName(), ssa.getId()); + + Util.addToJSONObjectIfNotNull(responseJsonObject, SSA.getName(), jsonSsa); + jsonArray.put(responseJsonObject); + } + return jsonArray; } public JSONObject getJSONObject(String jwt) throws JSONException { JSONObject responseJsonObject = new JSONObject(); - Util.addToJSONObjectIfNotNull(responseJsonObject, "ssa", jwt); + Util.addToJSONObjectIfNotNull(responseJsonObject, SSA.getName(), jwt); return responseJsonObject; } } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebService.java index c776e39e1af..1aa591708f9 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebService.java @@ -7,18 +7,28 @@ package io.jans.as.server.ssa.ws.rs; import jakarta.servlet.http.HttpServletRequest; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; public interface SsaRestWebService { @POST @Path("/ssa") @Produces({MediaType.APPLICATION_JSON}) - Response create(String requestParams, @Context HttpServletRequest httpRequest, @Context SecurityContext securityContext); + Response create( + String requestParams, + @Context HttpServletRequest httpRequest + ); + + @GET + @Path("/ssa") + @Produces({MediaType.APPLICATION_JSON}) + Response get( + @QueryParam("software_roles") Boolean softwareRoles, + @QueryParam("jti") String jti, + @QueryParam("org_id") String orgId, + @Context HttpServletRequest httpRequest + ); } \ No newline at end of file diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImpl.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImpl.java index 69319df73de..942de37be62 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImpl.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImpl.java @@ -7,11 +7,11 @@ package io.jans.as.server.ssa.ws.rs; import io.jans.as.server.ssa.ws.rs.action.SsaCreateAction; +import io.jans.as.server.ssa.ws.rs.action.SsaGetAction; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; @Path("/") public class SsaRestWebServiceImpl implements SsaRestWebService { @@ -19,8 +19,16 @@ public class SsaRestWebServiceImpl implements SsaRestWebService { @Inject private SsaCreateAction ssaCreateAction; + @Inject + private SsaGetAction ssaGetAction; + + @Override + public Response create(String requestParams, HttpServletRequest httpRequest) { + return ssaCreateAction.create(requestParams, httpRequest); + } + @Override - public Response create(String requestParams, HttpServletRequest httpRequest, SecurityContext securityContext) { - return ssaCreateAction.create(requestParams, httpRequest, securityContext); + public Response get(Boolean softwareRoles, String jti, String orgId, HttpServletRequest httpRequest) { + return ssaGetAction.get(softwareRoles, jti, orgId, httpRequest); } } \ No newline at end of file diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidator.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidator.java index be6a0f5c641..ccf79d94adc 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidator.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidator.java @@ -38,7 +38,7 @@ public class SsaRestWebServiceValidator { @Inject private ScopeService scopeService; - public Client validateClient() { + public Client getClientFromSession() { SessionClient sessionClient = identity.getSessionClient(); if (sessionClient != null) { log.debug("Client: {}, obtained from session", sessionClient.getClient().getClientId()); @@ -52,4 +52,14 @@ public void checkScopesPolicy(Client client, String scope) { if (!scopes.contains(scope)) throw errorResponseFactory.createWebApplicationException(Response.Status.UNAUTHORIZED, SsaErrorResponseType.UNAUTHORIZED_CLIENT, "Unauthorized client"); } + + public void checkScopesPolicy(Client client, List scopeList) { + if (client == null || scopeList == null || scopeList.isEmpty()) { + throw errorResponseFactory.createWebApplicationException(Response.Status.UNAUTHORIZED, SsaErrorResponseType.UNAUTHORIZED_CLIENT, "Unauthorized client"); + } + List scopes = scopeService.getScopeIdsByDns(Arrays.stream(client.getScopes()).collect(Collectors.toList())); + if (scopeList.stream().noneMatch(scopes::contains)) { + throw errorResponseFactory.createWebApplicationException(Response.Status.UNAUTHORIZED, SsaErrorResponseType.UNAUTHORIZED_CLIENT, "Unauthorized client"); + } + } } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaService.java index 80b1a32f8f6..6a0ba660590 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/SsaService.java @@ -6,19 +6,29 @@ package io.jans.as.server.ssa.ws.rs; import io.jans.as.common.model.ssa.Ssa; +import io.jans.as.model.config.StaticConfiguration; import io.jans.as.model.config.WebKeysConfiguration; import io.jans.as.model.configuration.AppConfiguration; import io.jans.as.model.crypto.AbstractCryptoProvider; import io.jans.as.model.crypto.signature.SignatureAlgorithm; import io.jans.as.model.jwt.Jwt; +import io.jans.as.model.ssa.SsaScopeType; import io.jans.as.server.model.common.ExecutionContext; import io.jans.as.server.model.token.JwtSigner; import io.jans.orm.PersistenceEntryManager; +import io.jans.orm.search.filter.Filter; import jakarta.ejb.Stateless; import jakarta.inject.Inject; import jakarta.inject.Named; import org.slf4j.Logger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static io.jans.as.model.ssa.SsaRequestParam.*; + @Stateless @Named public class SsaService { @@ -32,6 +42,9 @@ public class SsaService { @Inject private AppConfiguration appConfiguration; + @Inject + private StaticConfiguration staticConfiguration; + public void persist(Ssa ssa) { persistenceEntryManager.persist(ssa); } @@ -40,6 +53,27 @@ public void merge(Ssa ssa) { persistenceEntryManager.merge(ssa); } + public List getSsaList(String jti, String orgId, String clientId, String[] scopes) { + String dn = staticConfiguration.getBaseDn().getSsa(); + + List filters = new ArrayList<>(); + if (hasPortalScope(Arrays.asList(scopes))) { + filters.add(Filter.createEqualityFilter("creatorId", clientId)); + } + if (jti != null) { + filters.add(Filter.createEqualityFilter("inum", jti)); + } + if (orgId != null) { + filters.add(Filter.createEqualityFilter("o", orgId)); + } + Filter filter = null; + if (!filters.isEmpty()) { + filter = Filter.createANDFilter(filters); + log.trace("Filter with AND created: " + filters); + } + return persistenceEntryManager.findEntries(dn, Ssa.class, filter); + } + public Jwt generateJwt(Ssa ssa, ExecutionContext executionContext, WebKeysConfiguration webKeysConfiguration, AbstractCryptoProvider cryptoProvider) { try { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.fromString(appConfiguration.getSsaConfiguration().getSsaSigningAlg()); @@ -48,10 +82,10 @@ public Jwt generateJwt(Ssa ssa, ExecutionContext executionContext, WebKeysConfig jwt.getClaims().setJwtId(ssa.getId()); jwt.getClaims().setIssuedAt(ssa.getCreationDate()); jwt.getClaims().setExpirationTime(ssa.getExpirationDate()); - jwt.getClaims().setClaim("software_id", ssa.getAttributes().getSoftwareId()); - jwt.getClaims().setClaim("org_id", Long.parseLong(ssa.getOrgId())); - jwt.getClaims().setClaim("software_roles", ssa.getAttributes().getSoftwareRoles()); - jwt.getClaims().setClaim("grant_types", ssa.getAttributes().getGrantTypes()); + jwt.getClaims().setClaim(SOFTWARE_ID.getName(), ssa.getAttributes().getSoftwareId()); + jwt.getClaims().setClaim(ORG_ID.getName(), Long.parseLong(ssa.getOrgId())); + jwt.getClaims().setClaim(SOFTWARE_ROLES.getName(), ssa.getAttributes().getSoftwareRoles()); + jwt.getClaims().setClaim(GRANT_TYPES.getName(), ssa.getAttributes().getGrantTypes()); Jwt jwr = jwtSigner.sign(); if (executionContext.getPostProcessor() != null) { @@ -64,4 +98,18 @@ public Jwt generateJwt(Ssa ssa, ExecutionContext executionContext, WebKeysConfig throw new RuntimeException(e); } } + + private boolean hasPortalScope(List scopes) { + Iterator scopesIterator = scopes.iterator(); + boolean result = false; + while (scopesIterator.hasNext()) { + String scope = scopesIterator.next(); + if (scope.equals(SsaScopeType.SSA_ADMIN.getValue())) { + return false; + } else if (scope.equals(SsaScopeType.SSA_PORTAL.getValue())) { + result = true; + } + } + return result; + } } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateAction.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateAction.java index 4ae7bff1943..fcb5d40c34f 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateAction.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateAction.java @@ -6,7 +6,7 @@ package io.jans.as.server.ssa.ws.rs.action; -import io.jans.as.client.SsaRequest; +import io.jans.as.client.ssa.create.SsaCreateRequest; import io.jans.as.common.model.registration.Client; import io.jans.as.common.model.ssa.Ssa; import io.jans.as.common.service.AttributeService; @@ -38,7 +38,6 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; import org.json.JSONObject; import org.slf4j.Logger; @@ -85,37 +84,37 @@ public class SsaCreateAction { @Inject private SsaContextBuilder ssaContextBuilder; - public Response create(String requestParams, HttpServletRequest httpRequest, SecurityContext securityContext) { + public Response create(String requestParams, HttpServletRequest httpRequest) { errorResponseFactory.validateFeatureEnabled(FeatureFlagType.SSA); Response.ResponseBuilder builder = Response.status(Response.Status.CREATED); try { JSONObject jsonRequest = new JSONObject(requestParams); - final SsaRequest ssaRequest = SsaRequest.fromJson(jsonRequest); - log.debug("Attempting to create ssa: {}", ssaRequest); + final SsaCreateRequest ssaCreateRequest = SsaCreateRequest.fromJson(jsonRequest); + log.debug("Attempting to create ssa: {}", ssaCreateRequest); String ssaBaseDN = staticConfiguration.getBaseDn().getSsa(); String inum = inumService.generateDefaultId(); - Client client = ssaRestWebServiceValidator.validateClient(); + Client client = ssaRestWebServiceValidator.getClientFromSession(); ssaRestWebServiceValidator.checkScopesPolicy(client, SsaScopeType.SSA_ADMIN.getValue()); final Date creationDate = new Date(); - final Date expirationDate = getExpiration(ssaRequest); + final Date expirationDate = getExpiration(ssaCreateRequest); final Ssa ssa = new Ssa(); ssa.setDn("inum=" + inum + "," + ssaBaseDN); ssa.setId(inum); ssa.setDeletable(true); - ssa.setOrgId(ssaRequest.getOrgId() != null ? ssaRequest.getOrgId().toString() : null); // should orgId be long or string? e.g. guid as orgId sounds common + ssa.setOrgId(ssaCreateRequest.getOrgId() != null ? ssaCreateRequest.getOrgId().toString() : null); // should orgId be long or string? e.g. guid as orgId sounds common ssa.setExpirationDate(expirationDate); ssa.setTtl(ServerUtil.calculateTtl(creationDate, expirationDate)); - ssa.setDescription(ssaRequest.getDescription()); - ssa.getAttributes().setSoftwareId(ssaRequest.getSoftwareId()); - ssa.getAttributes().setSoftwareRoles(ssaRequest.getSoftwareRoles()); - ssa.getAttributes().setGrantTypes(ssaRequest.getGrantTypes()); + ssa.setDescription(ssaCreateRequest.getDescription()); + ssa.getAttributes().setSoftwareId(ssaCreateRequest.getSoftwareId()); + ssa.getAttributes().setSoftwareRoles(ssaCreateRequest.getSoftwareRoles()); + ssa.getAttributes().setGrantTypes(ssaCreateRequest.getGrantTypes()); ssa.getAttributes().setCustomAttributes(getCustomAttributes(jsonRequest)); ssa.getAttributes().setClientDn(client.getDn()); - ssa.getAttributes().setOneTimeUse(ssaRequest.getOneTimeUse()); - ssa.getAttributes().setRotateSsa(ssaRequest.getRotateSsa()); + ssa.getAttributes().setOneTimeUse(ssaCreateRequest.getOneTimeUse()); + ssa.getAttributes().setRotateSsa(ssaCreateRequest.getRotateSsa()); ssa.setCreatorType(CreatorType.CLIENT); ssa.setCreatorId(client.getClientId()); @@ -179,10 +178,10 @@ private Map getCustomAttributes(JSONObject jsonRequest) { return customAttributes; } - private Date getExpiration(SsaRequest ssaRequest) { + private Date getExpiration(SsaCreateRequest ssaCreateRequest) { Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC")); - if (ssaRequest.getExpiration() != null && ssaRequest.getExpiration() > 0) { - calendar.setTimeInMillis(ssaRequest.getExpiration() * 1000L); + if (ssaCreateRequest.getExpiration() != null && ssaCreateRequest.getExpiration() > 0) { + calendar.setTimeInMillis(ssaCreateRequest.getExpiration() * 1000L); return calendar.getTime(); } calendar.add(Calendar.DATE, appConfiguration.getSsaConfiguration().getSsaExpirationInDays()); diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaGetAction.java b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaGetAction.java new file mode 100644 index 00000000000..ad852935d29 --- /dev/null +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/ssa/ws/rs/action/SsaGetAction.java @@ -0,0 +1,108 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2022, Janssen Project + */ + +package io.jans.as.server.ssa.ws.rs.action; + +import io.jans.as.common.model.registration.Client; +import io.jans.as.common.model.ssa.Ssa; +import io.jans.as.common.service.AttributeService; +import io.jans.as.model.common.FeatureFlagType; +import io.jans.as.model.config.Constants; +import io.jans.as.model.configuration.AppConfiguration; +import io.jans.as.model.error.ErrorResponseFactory; +import io.jans.as.model.ssa.SsaErrorResponseType; +import io.jans.as.model.ssa.SsaScopeType; +import io.jans.as.server.service.external.ModifySsaResponseService; +import io.jans.as.server.service.external.context.ModifySsaResponseContext; +import io.jans.as.server.ssa.ws.rs.SsaContextBuilder; +import io.jans.as.server.ssa.ws.rs.SsaJsonService; +import io.jans.as.server.ssa.ws.rs.SsaRestWebServiceValidator; +import io.jans.as.server.ssa.ws.rs.SsaService; +import io.jans.as.server.util.ServerUtil; +import jakarta.ejb.Stateless; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.json.JSONArray; +import org.slf4j.Logger; + +import java.util.Arrays; +import java.util.List; + +@Stateless +@Named +public class SsaGetAction { + + @Inject + private Logger log; + + @Inject + private ErrorResponseFactory errorResponseFactory; + + @Inject + private SsaJsonService ssaJsonService; + + @Inject + private SsaService ssaService; + + @Inject + private AppConfiguration appConfiguration; + + @Inject + private AttributeService attributeService; + + @Inject + private ModifySsaResponseService modifySsaResponseService; + + @Inject + private SsaRestWebServiceValidator ssaRestWebServiceValidator; + + @Inject + private SsaContextBuilder ssaContextBuilder; + + public Response get(Boolean softwareRoles, String jti, String orgId, HttpServletRequest httpRequest) { + log.debug("Attempting to read ssa: softwareRoles = {}, jti = '{}', orgId = {}", softwareRoles, jti, orgId); + + errorResponseFactory.validateFeatureEnabled(FeatureFlagType.SSA); + Response.ResponseBuilder builder = Response.ok(); + try { + final Client client = ssaRestWebServiceValidator.getClientFromSession(); + ssaRestWebServiceValidator.checkScopesPolicy(client, Arrays.asList(SsaScopeType.SSA_ADMIN.getValue(), SsaScopeType.SSA_PORTAL.getValue())); + + final List ssaList = ssaService.getSsaList(jti, orgId, client.getClientId(), client.getScopes()); + + JSONArray jsonArray = ssaJsonService.getJSONArray(ssaList); + ModifySsaResponseContext context = ssaContextBuilder.buildModifySsaResponseContext(httpRequest, null, client, appConfiguration, attributeService); + jsonArray = modifyGetScript(jsonArray, context, ssaList); + builder.entity(ssaJsonService.jsonArrayToString(jsonArray)); + + } catch (WebApplicationException e) { + if (log.isErrorEnabled()) { + log.error(e.getMessage(), e); + } + throw e; + + } catch (Exception e) { + log.error(e.getMessage(), e); + throw errorResponseFactory.createWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR, SsaErrorResponseType.UNKNOWN_ERROR, "Unknown error"); + } + + builder.cacheControl(ServerUtil.cacheControl(true, false)); + builder.header(Constants.PRAGMA, Constants.NO_CACHE); + builder.type(MediaType.APPLICATION_JSON_TYPE); + return builder.build(); + } + + private JSONArray modifyGetScript(JSONArray jsonArray, ModifySsaResponseContext context, List ssaList) { + if (!modifySsaResponseService.get(jsonArray, context)) { + return ssaJsonService.getJSONArray(ssaList); + } + return jsonArray; + } +} diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaJsonServiceTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaJsonServiceTest.java index 825cee5ff53..92432c73047 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaJsonServiceTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaJsonServiceTest.java @@ -1,8 +1,13 @@ package io.jans.as.server.ssa.ws.rs; import io.jans.as.common.model.ssa.Ssa; +import io.jans.as.model.configuration.AppConfiguration; +import io.jans.as.model.util.DateUtil; +import org.json.JSONArray; import org.json.JSONObject; import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -18,6 +23,9 @@ public class SsaJsonServiceTest { @InjectMocks private SsaJsonService ssaJsonService; + @Mock + private AppConfiguration appConfiguration; + @Test public void jsonObjectToString_jsonObject_validJsonString() { JSONObject jsonObject = new JSONObject(); @@ -34,7 +42,22 @@ public void jsonObjectToString_jsonObject_validJsonString() { } @Test - public void getJSONObject_ssa_validJsonObject() { + public void jsonArrayToString_jsonArray_validJsonString() { + JSONArray jsonArray = new JSONArray(); + jsonArray.put("val1"); + jsonArray.put("val2"); + + String json = ssaJsonService.jsonArrayToString(jsonArray); + assertNotNull(json, "json response is null"); + JSONArray jsonResponse = new JSONArray(json); + assertEquals(jsonResponse.getString(0), "val1"); + assertEquals(jsonResponse.getString(1), "val2"); + } + + @Test + public void getJSONArray_ssaList_validJson() { + Mockito.when(appConfiguration.getIssuer()).thenReturn("https://jans.io"); + Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); calendar.add(Calendar.HOUR, 24); @@ -48,25 +71,53 @@ public void getJSONObject_ssa_validJsonObject() { ssa.getAttributes().setGrantTypes(Collections.singletonList("client_credentials")); ssa.getAttributes().setOneTimeUse(true); ssa.getAttributes().setRotateSsa(true); + ssa.setCreatorId("test@localhost"); + + JSONArray jsonArray = ssaJsonService.getJSONArray(Collections.singletonList(ssa)); + assertNotNull(jsonArray, "jsonObject response is null"); + assertEquals(jsonArray.length(), 1); + + JSONObject jsonObject = jsonArray.getJSONObject(0); + assertNotNull(jsonObject); + assertTrue(jsonObject.has(SSA.getName())); + assertTrue(jsonObject.has(CREATED_AT.getName())); + assertEquals(jsonObject.get(CREATED_AT.getName()), DateUtil.dateToUnixEpoch(ssa.getCreationDate())); + assertTrue(jsonObject.has(EXPIRATION.getName())); + assertEquals(jsonObject.get(EXPIRATION.getName()), DateUtil.dateToUnixEpoch(ssa.getExpirationDate())); + assertTrue(jsonObject.has(ISSUER.getName())); + + JSONObject ssaJsonObject = jsonObject.getJSONObject(SSA.getName()); + assertNotNull(ssaJsonObject); + assertTrue(ssaJsonObject.has(ORG_ID.getName())); + assertEquals(ssaJsonObject.get(ORG_ID.getName()), Long.parseLong(ssa.getOrgId())); + assertTrue(ssaJsonObject.has(SOFTWARE_ID.getName())); + assertEquals(ssaJsonObject.get(SOFTWARE_ID.getName()), ssa.getAttributes().getSoftwareId()); + assertTrue(ssaJsonObject.has(SOFTWARE_ROLES.getName())); + assertEquals(ssaJsonObject.get(SOFTWARE_ROLES.getName()), ssa.getAttributes().getSoftwareRoles()); + assertTrue(ssaJsonObject.has(GRANT_TYPES.getName())); + assertEquals(ssaJsonObject.get(GRANT_TYPES.getName()), ssa.getAttributes().getGrantTypes()); + assertTrue(ssaJsonObject.has(EXP.getName())); + assertEquals(ssaJsonObject.get(EXP.getName()), DateUtil.dateToUnixEpoch(ssa.getExpirationDate())); + assertTrue(ssaJsonObject.has(JTI.getName())); + assertEquals(ssaJsonObject.get(JTI.getName()), ssa.getId()); + assertTrue(ssaJsonObject.has(IAT.getName())); + assertEquals(ssaJsonObject.get(IAT.getName()), DateUtil.dateToUnixEpoch(ssa.getCreationDate())); + assertTrue(ssaJsonObject.has(ISS.getName())); + assertEquals(ssaJsonObject.get(ISS.getName()), appConfiguration.getIssuer()); + } - JSONObject jsonObject = ssaJsonService.getJSONObject(ssa); - assertNotNull(jsonObject, "jsonObject response is null"); - assertTrue(jsonObject.has(ORG_ID.toString())); - assertEquals(jsonObject.get(ORG_ID.toString()), ssa.getOrgId()); - assertTrue(jsonObject.has(EXPIRATION.toString())); - assertEquals(jsonObject.get(EXPIRATION.toString()), ssa.getExpirationDate()); - assertTrue(jsonObject.has(DESCRIPTION.toString())); - assertEquals(jsonObject.get(DESCRIPTION.toString()), ssa.getDescription()); - assertTrue(jsonObject.has(SOFTWARE_ID.toString())); - assertEquals(jsonObject.get(SOFTWARE_ID.toString()), ssa.getAttributes().getSoftwareId()); - assertTrue(jsonObject.has(SOFTWARE_ROLES.toString())); - assertEquals(jsonObject.get(SOFTWARE_ROLES.toString()), ssa.getAttributes().getSoftwareRoles()); - assertTrue(jsonObject.has(GRANT_TYPES.toString())); - assertEquals(jsonObject.get(GRANT_TYPES.toString()), ssa.getAttributes().getGrantTypes()); - assertTrue(jsonObject.has(ONE_TIME_USE.toString())); - assertEquals(jsonObject.get(ONE_TIME_USE.toString()), ssa.getAttributes().getOneTimeUse()); - assertTrue(jsonObject.has(ROTATE_SSA.toString())); - assertEquals(jsonObject.get(ROTATE_SSA.toString()), ssa.getAttributes().getRotateSsa()); + @Test + public void getJSONArray_emptySsaList_validEmptyJson() { + JSONArray jsonArray = ssaJsonService.getJSONArray(Collections.emptyList()); + assertNotNull(jsonArray, "jsonArray response is null"); + assertEquals(jsonArray.length(), 0); + } + + @Test + public void getJSONArray_nullSsaList_validEmptyJson() { + JSONArray jsonArray = ssaJsonService.getJSONArray(null); + assertNotNull(jsonArray, "jsonArray response is null"); + assertEquals(jsonArray.length(), 0); } @Test @@ -75,8 +126,8 @@ public void getJSONObject_jwt_validJsonObject() { JSONObject jsonObject = ssaJsonService.getJSONObject(jwt); assertNotNull(jsonObject, "jsonObject response is null"); - assertTrue(jsonObject.has("ssa")); - assertEquals(jsonObject.get("ssa"), jwt); + assertTrue(jsonObject.has(SSA.getName())); + assertEquals(jsonObject.get(SSA.getName()), jwt); } @Test @@ -94,7 +145,7 @@ public void getJSONObject_jwtBlank_validWithBlankValue() { JSONObject jsonObject = ssaJsonService.getJSONObject(jwt); assertNotNull(jsonObject, "jsonObject response is null"); - assertTrue(jsonObject.has("ssa")); - assertEquals(jsonObject.get("ssa"), ""); + assertTrue(jsonObject.has(SSA.getName())); + assertEquals(jsonObject.get(SSA.getName()), ""); } } \ No newline at end of file diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImplTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImplTest.java index d8546f6e28a..0572daef9e1 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImplTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceImplTest.java @@ -1,9 +1,9 @@ package io.jans.as.server.ssa.ws.rs; import io.jans.as.server.ssa.ws.rs.action.SsaCreateAction; +import io.jans.as.server.ssa.ws.rs.action.SsaGetAction; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -24,13 +24,26 @@ public class SsaRestWebServiceImplTest { @Mock private SsaCreateAction ssaCreateAction; + @Mock + private SsaGetAction ssaGetAction; + @Test public void create_validParams_validResponse() { - when(ssaCreateAction.create(anyString(), any(), any())).thenReturn(mock(Response.class)); - Response response = ssaRestWebService.create("test request", mock(HttpServletRequest.class), mock(SecurityContext.class)); + when(ssaCreateAction.create(anyString(), any())).thenReturn(mock(Response.class)); + Response response = ssaRestWebService.create("test request", mock(HttpServletRequest.class)); assertNotNull(response, "response is null"); - verify(ssaCreateAction).create(anyString(), any(), any()); + verify(ssaCreateAction).create(anyString(), any()); verifyNoMoreInteractions(ssaCreateAction); } + + @Test + public void get_validParams_validResponse() { + when(ssaGetAction.get(anyBoolean(), anyString(), anyString(), any())).thenReturn(mock(Response.class)); + Response response = ssaRestWebService.get(false, "testJti", "testOrgId", mock(HttpServletRequest.class)); + assertNotNull(response, "response is null"); + + verify(ssaGetAction).get(anyBoolean(), anyString(), anyString(), any()); + verifyNoMoreInteractions(ssaGetAction); + } } \ No newline at end of file diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidatorTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidatorTest.java index 848bdae92e6..297b647ebd3 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidatorTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaRestWebServiceValidatorTest.java @@ -3,6 +3,7 @@ import io.jans.as.common.model.registration.Client; import io.jans.as.model.error.ErrorResponseFactory; import io.jans.as.model.ssa.SsaErrorResponseType; +import io.jans.as.model.ssa.SsaScopeType; import io.jans.as.server.model.session.SessionClient; import io.jans.as.server.security.Identity; import io.jans.as.server.service.ScopeService; @@ -16,11 +17,13 @@ import org.testng.annotations.Listeners; import org.testng.annotations.Test; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; -import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.*; @Listeners(MockitoTestNGListener.class) public class SsaRestWebServiceValidatorTest { @@ -41,20 +44,20 @@ public class SsaRestWebServiceValidatorTest { private ScopeService scopeService; @Test - public void validateClient_sessionClient_validClient() { + public void getClientFromSession_sessionClient_validClient() { SessionClient sessionClient = new SessionClient(); Client client = new Client(); client.setClientId("test_id"); sessionClient.setClient(client); doReturn(sessionClient).when(identity).getSessionClient(); - Client clientAux = ssaRestWebServiceValidator.validateClient(); + Client clientAux = ssaRestWebServiceValidator.getClientFromSession(); assertNotNull(clientAux, "client is null"); verify(log).debug(anyString(), anyString()); } @Test - public void validateClient_sessionClientNull_invalidClientResponse() { + public void getClientFromSession_sessionClientNull_invalidClientResponse() { WebApplicationException error = new WebApplicationException(Response .status(Response.Status.BAD_REQUEST) .entity("Invalid client") @@ -65,7 +68,7 @@ public void validateClient_sessionClientNull_invalidClientResponse() { when(errorResponseFactory.createBadRequestException(eq(SsaErrorResponseType.INVALID_CLIENT), anyString())).thenThrow(error); try { - ssaRestWebServiceValidator.validateClient(); + ssaRestWebServiceValidator.getClientFromSession(); } catch (WebApplicationException e) { assertNotNull(e, "WebApplicationException is null"); assertNotNull(e.getResponse(), "WebApplicationException Response is null"); @@ -75,7 +78,7 @@ public void validateClient_sessionClientNull_invalidClientResponse() { } @Test - public void checkScopesPolicy_clientAndScopeConstains_validScope() { + public void checkScopesPolicySingleScope_clientAndScopeContains_validScope() { String scope = "test_id"; Client client = new Client(); client.setScopes(new String[]{}); @@ -86,7 +89,7 @@ public void checkScopesPolicy_clientAndScopeConstains_validScope() { } @Test - public void checkScopesPolicy_clientAndScopeNotConstains_unauthorizedResponse() { + public void checkScopesPolicySingleScope_clientAndScopeNotContains_unauthorizedResponse() { String scope = "test_id"; Client client = new Client(); client.setScopes(new String[]{}); @@ -98,11 +101,100 @@ public void checkScopesPolicy_clientAndScopeNotConstains_unauthorizedResponse() when(scopeService.getScopeIdsByDns(anyList())).thenReturn(Collections.singletonList("test_id_fail")); when(errorResponseFactory.createWebApplicationException(eq(Response.Status.UNAUTHORIZED), eq(SsaErrorResponseType.UNAUTHORIZED_CLIENT), anyString())).thenThrow(error); + WebApplicationException wae = null; try { ssaRestWebServiceValidator.checkScopesPolicy(client, scope); } catch (WebApplicationException e) { - assertNotNull(e, "WebApplicationException is null"); - assertNotNull(e.getResponse(), "WebApplicationException Response is null"); + wae = e; } + assertNotNull(wae, "WebApplicationException is null"); + assertNotNull(wae.getResponse(), "WebApplicationException Response is null"); + } + + @Test + public void checkScopesPolicyListScope_clientNull_unauthorizedResponse() { + WebApplicationException error = new WebApplicationException(Response + .status(Response.Status.UNAUTHORIZED) + .entity("Invalid client") + .type(MediaType.APPLICATION_JSON_TYPE) + .build()); + when(errorResponseFactory.createWebApplicationException(eq(Response.Status.UNAUTHORIZED), eq(SsaErrorResponseType.UNAUTHORIZED_CLIENT), anyString())).thenThrow(error); + + Client client = null; + List scopeList = Collections.singletonList(SsaScopeType.SSA_ADMIN.getValue()); + assertThrows(WebApplicationException.class, () -> ssaRestWebServiceValidator.checkScopesPolicy(client, scopeList)); + verify(errorResponseFactory).createWebApplicationException(any(), any(), anyString()); + verifyNoInteractions(scopeService); + verifyNoMoreInteractions(errorResponseFactory); + } + + @Test + public void checkScopesPolicyListScope_scopeListNull_unauthorizedResponse() { + WebApplicationException error = new WebApplicationException(Response + .status(Response.Status.UNAUTHORIZED) + .entity("Invalid client") + .type(MediaType.APPLICATION_JSON_TYPE) + .build()); + when(errorResponseFactory.createWebApplicationException(eq(Response.Status.UNAUTHORIZED), eq(SsaErrorResponseType.UNAUTHORIZED_CLIENT), anyString())).thenThrow(error); + + Client client = new Client(); + List scopeList = null; + assertThrows(WebApplicationException.class, () -> ssaRestWebServiceValidator.checkScopesPolicy(client, scopeList)); + verify(errorResponseFactory).createWebApplicationException(any(), any(), anyString()); + verifyNoInteractions(scopeService); + verifyNoMoreInteractions(errorResponseFactory); + } + + @Test + public void checkScopesPolicyListScope_scopeListEmpty_unauthorizedResponse() { + WebApplicationException error = new WebApplicationException(Response + .status(Response.Status.UNAUTHORIZED) + .entity("Invalid client") + .type(MediaType.APPLICATION_JSON_TYPE) + .build()); + when(errorResponseFactory.createWebApplicationException(eq(Response.Status.UNAUTHORIZED), eq(SsaErrorResponseType.UNAUTHORIZED_CLIENT), anyString())).thenThrow(error); + + Client client = new Client(); + List scopeList = new ArrayList<>(); + assertThrows(WebApplicationException.class, () -> ssaRestWebServiceValidator.checkScopesPolicy(client, scopeList)); + verify(errorResponseFactory).createWebApplicationException(any(), any(), anyString()); + verifyNoInteractions(scopeService); + verifyNoMoreInteractions(errorResponseFactory); + } + + @Test + public void checkScopesPolicyListScope_clientAndScopeAdmin_valid() { + String scope = SsaScopeType.SSA_ADMIN.getValue(); + Client client = new Client(); + client.setScopes(new String[]{}); + when(scopeService.getScopeIdsByDns(anyList())).thenReturn(Collections.singletonList(scope)); + + List scopeList = new ArrayList<>(); + scopeList.add(SsaScopeType.SSA_ADMIN.getValue()); + + ssaRestWebServiceValidator.checkScopesPolicy(client, scopeList); + verify(scopeService).getScopeIdsByDns(any()); + verifyNoInteractions(errorResponseFactory); + } + + @Test + public void checkScopesPolicyListScope_clientAndScopeNotContains_unauthorizedResponse() { + String scope = SsaScopeType.SSA_ADMIN.getValue(); + Client client = new Client(); + client.setScopes(new String[]{}); + when(scopeService.getScopeIdsByDns(anyList())).thenReturn(Collections.singletonList(scope)); + WebApplicationException error = new WebApplicationException(Response + .status(Response.Status.UNAUTHORIZED) + .entity("Invalid client") + .type(MediaType.APPLICATION_JSON_TYPE) + .build()); + when(errorResponseFactory.createWebApplicationException(eq(Response.Status.UNAUTHORIZED), eq(SsaErrorResponseType.UNAUTHORIZED_CLIENT), anyString())).thenThrow(error); + + List scopeList = new ArrayList<>(); + scopeList.add(SsaScopeType.SSA_PORTAL.getValue()); + assertThrows(WebApplicationException.class, () -> ssaRestWebServiceValidator.checkScopesPolicy(client, scopeList)); + verify(scopeService).getScopeIdsByDns(anyList()); + verify(errorResponseFactory).createWebApplicationException(any(), any(), anyString()); + verifyNoMoreInteractions(errorResponseFactory); } } \ No newline at end of file diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaServiceTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaServiceTest.java index 33acfc5799f..bdb0f92cd8f 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaServiceTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/SsaServiceTest.java @@ -4,6 +4,8 @@ import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.RSAKey; import io.jans.as.common.model.ssa.Ssa; +import io.jans.as.model.config.BaseDnConfiguration; +import io.jans.as.model.config.StaticConfiguration; import io.jans.as.model.config.WebKeysConfiguration; import io.jans.as.model.configuration.AppConfiguration; import io.jans.as.model.crypto.AbstractCryptoProvider; @@ -15,6 +17,7 @@ import io.jans.as.model.jwt.JwtClaims; import io.jans.as.model.jwt.JwtHeader; import io.jans.as.model.ssa.SsaConfiguration; +import io.jans.as.model.ssa.SsaScopeType; import io.jans.as.model.util.Base64Util; import io.jans.as.server.model.common.ExecutionContext; import io.jans.orm.PersistenceEntryManager; @@ -33,9 +36,9 @@ import java.text.ParseException; import java.util.*; +import static io.jans.as.model.ssa.SsaRequestParam.*; import static org.mockito.Mockito.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.*; @Listeners(MockitoTestNGListener.class) public class SsaServiceTest { @@ -64,6 +67,9 @@ public class SsaServiceTest { @Mock private PersistenceEntryManager persistenceEntryManager; + @Mock + private StaticConfiguration staticConfiguration; + private Ssa ssa; @BeforeMethod @@ -160,6 +166,74 @@ public void merge_ssa_valid() { assertSsaWithAux(ssa, ssaArgumentCaptor.getValue()); } + @Test + public void getSsaList_withPortalScope_valid() { + BaseDnConfiguration baseDnConfiguration = new BaseDnConfiguration(); + baseDnConfiguration.setSsa("ou=ssa,o=jans"); + when(staticConfiguration.getBaseDn()).thenReturn(baseDnConfiguration); + + String jti = null; + String orgId = null; + String clientId = "test-client"; + String[] scopes = new String[]{SsaScopeType.SSA_PORTAL.getValue()}; + List ssaList = ssaService.getSsaList(jti, orgId, clientId, scopes); + assertNotNull(ssaList); + verify(log).trace(eq("Filter with AND created: " + String.format("[(creatorId=%s)]", clientId))); + verify(persistenceEntryManager).findEntries(any(), any(), any()); + verifyNoMoreInteractions(log); + } + + @Test + public void getSsaList_withJti_valid() { + BaseDnConfiguration baseDnConfiguration = new BaseDnConfiguration(); + baseDnConfiguration.setSsa("ou=ssa,o=jans"); + when(staticConfiguration.getBaseDn()).thenReturn(baseDnConfiguration); + + String jti = "test-jti"; + String orgId = null; + String clientId = "test-client"; + String[] scopes = new String[]{}; + List ssaList = ssaService.getSsaList(jti, orgId, clientId, scopes); + assertNotNull(ssaList); + verify(log).trace(eq("Filter with AND created: " + String.format("[(inum=%s)]", jti))); + verify(persistenceEntryManager).findEntries(any(), any(), any()); + verifyNoMoreInteractions(log); + } + + @Test + public void getSsaList_withOrgId_valid() { + BaseDnConfiguration baseDnConfiguration = new BaseDnConfiguration(); + baseDnConfiguration.setSsa("ou=ssa,o=jans"); + when(staticConfiguration.getBaseDn()).thenReturn(baseDnConfiguration); + + String jti = null; + String orgId = "test-org"; + String clientId = "test-client"; + String[] scopes = new String[]{}; + List ssaList = ssaService.getSsaList(jti, orgId, clientId, scopes); + assertNotNull(ssaList); + verify(log).trace(eq("Filter with AND created: " + String.format("[(o=%s)]", orgId))); + verify(persistenceEntryManager).findEntries(any(), any(), any()); + verifyNoMoreInteractions(log); + } + + @Test + public void getSsaList_withNullParam_valid() { + BaseDnConfiguration baseDnConfiguration = new BaseDnConfiguration(); + baseDnConfiguration.setSsa("ou=ssa,o=jans"); + when(staticConfiguration.getBaseDn()).thenReturn(baseDnConfiguration); + + String jti = null; + String orgId = null; + String clientId = null; + String[] scopes = new String[]{}; + List ssaList = ssaService.getSsaList(jti, orgId, clientId, scopes); + assertNotNull(ssaList); + assertTrue(ssaList.isEmpty()); + verify(persistenceEntryManager).findEntries(any(), any(), any()); + verifyNoInteractions(log); + } + @Test public void generateJwt_executionContextWithPostProcessorNull_jwtValid() { JSONWebKey jsonWebKey = JSONWebKey.fromJSONObject(new JSONObject(senderJwkJson)); @@ -232,23 +306,23 @@ private static void assertSsaJwt(JSONWebKey jsonWebKey, String ssaSigningAlg, St assertEquals(jwtHeader.getType().toString(), "jwt"); JwtClaims jwtClaims = jwt.getClaims(); - assertNotNull(jwtClaims.getClaim("org_id"), "The org_id in jwt is null"); - assertEquals(jwtClaims.getClaim("org_id"), Long.parseLong(ssa.getOrgId())); - assertNotNull(jwtClaims.getClaim("software_id"), "The software_id in jwt is null"); - assertEquals(jwtClaims.getClaim("software_id"), ssa.getAttributes().getSoftwareId()); - assertNotNull(jwtClaims.getClaim("software_roles"), "The software_roles in jwt is null"); - assertEquals(jwtClaims.getClaim("software_roles"), ssa.getAttributes().getSoftwareRoles()); - assertNotNull(jwtClaims.getClaim("grant_types"), "The grant_types in jwt is null"); - assertEquals(jwtClaims.getClaim("grant_types"), ssa.getAttributes().getGrantTypes()); - - assertNotNull(jwtClaims.getClaim("jti"), "The jti in jwt is null"); - assertEquals(jwtClaims.getClaim("jti"), ssa.getId()); - assertNotNull(jwtClaims.getClaim("iss"), "The iss in jwt is null"); - assertEquals(jwtClaims.getClaim("iss"), issuer); - assertNotNull(jwtClaims.getClaim("iat"), "The iat in jwt is null"); - assertEquals(jwtClaims.getClaim("iat"), ssa.getCreationDate()); - assertNotNull(jwtClaims.getClaim("exp"), "The exp in jwt is null"); - assertEquals(jwtClaims.getClaim("exp"), ssa.getExpirationDate()); + assertNotNull(jwtClaims.getClaim(ORG_ID.getName()), "The org_id in jwt is null"); + assertEquals(jwtClaims.getClaim(ORG_ID.getName()), Long.parseLong(ssa.getOrgId())); + assertNotNull(jwtClaims.getClaim(SOFTWARE_ID.getName()), "The software_id in jwt is null"); + assertEquals(jwtClaims.getClaim(SOFTWARE_ID.getName()), ssa.getAttributes().getSoftwareId()); + assertNotNull(jwtClaims.getClaim(SOFTWARE_ROLES.getName()), "The software_roles in jwt is null"); + assertEquals(jwtClaims.getClaim(SOFTWARE_ROLES.getName()), ssa.getAttributes().getSoftwareRoles()); + assertNotNull(jwtClaims.getClaim(GRANT_TYPES.getName()), "The grant_types in jwt is null"); + assertEquals(jwtClaims.getClaim(GRANT_TYPES.getName()), ssa.getAttributes().getGrantTypes()); + + assertNotNull(jwtClaims.getClaim(JTI.getName()), "The jti in jwt is null"); + assertEquals(jwtClaims.getClaim(JTI.getName()), ssa.getId()); + assertNotNull(jwtClaims.getClaim(ISS.getName()), "The iss in jwt is null"); + assertEquals(jwtClaims.getClaim(ISS.getName()), issuer); + assertNotNull(jwtClaims.getClaim(IAT.getName()), "The iat in jwt is null"); + assertEquals(jwtClaims.getClaim(IAT.getName()), ssa.getCreationDate()); + assertNotNull(jwtClaims.getClaim(EXP.getName()), "The exp in jwt is null"); + assertEquals(jwtClaims.getClaim(EXP.getName()), ssa.getExpirationDate()); } private static void assertSsaWithAux(Ssa ssa, Ssa ssaAux) { diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateActionTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateActionTest.java index 02b8dcd10a7..f44ae9a2a92 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateActionTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaCreateActionTest.java @@ -1,6 +1,6 @@ package io.jans.as.server.ssa.ws.rs.action; -import io.jans.as.client.SsaRequest; +import io.jans.as.client.ssa.create.SsaCreateRequest; import io.jans.as.common.model.registration.Client; import io.jans.as.common.model.ssa.Ssa; import io.jans.as.common.service.AttributeService; @@ -12,6 +12,7 @@ import io.jans.as.model.jwt.Jwt; import io.jans.as.model.ssa.SsaConfiguration; import io.jans.as.model.ssa.SsaErrorResponseType; +import io.jans.as.model.util.DateUtil; import io.jans.as.server.model.common.ExecutionContext; import io.jans.as.server.service.external.ModifySsaResponseService; import io.jans.as.server.service.external.context.ModifySsaResponseContext; @@ -23,7 +24,6 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; import org.json.JSONObject; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; @@ -100,14 +100,14 @@ public void setUp() { ssa.getAttributes().setRotateSsa(true); requestJson = new JSONObject(); - requestJson.put(ORG_ID.toString(), ssa.getOrgId()); - requestJson.put(EXPIRATION.toString(), ssa.getExpirationDate().getTime() / 1000L); - requestJson.put(DESCRIPTION.toString(), ssa.getDescription()); - requestJson.put(SOFTWARE_ID.toString(), ssa.getAttributes().getSoftwareId()); - requestJson.put(SOFTWARE_ROLES.toString(), ssa.getAttributes().getSoftwareRoles()); - requestJson.put(GRANT_TYPES.toString(), ssa.getAttributes().getGrantTypes()); - requestJson.put(ONE_TIME_USE.toString(), ssa.getAttributes().getOneTimeUse()); - requestJson.put(ROTATE_SSA.toString(), ssa.getAttributes().getRotateSsa()); + requestJson.put(ORG_ID.getName(), ssa.getOrgId()); + requestJson.put(EXPIRATION.getName(), DateUtil.dateToUnixEpoch(ssa.getExpirationDate())); + requestJson.put(DESCRIPTION.getName(), ssa.getDescription()); + requestJson.put(SOFTWARE_ID.getName(), ssa.getAttributes().getSoftwareId()); + requestJson.put(SOFTWARE_ROLES.getName(), ssa.getAttributes().getSoftwareRoles()); + requestJson.put(GRANT_TYPES.getName(), ssa.getAttributes().getGrantTypes()); + requestJson.put(ONE_TIME_USE.getName(), ssa.getAttributes().getOneTimeUse()); + requestJson.put(ROTATE_SSA.getName(), ssa.getAttributes().getRotateSsa()); } @Test @@ -118,10 +118,7 @@ public void create_request_valid() { when(inumService.generateDefaultId()).thenReturn(UUID.randomUUID().toString()); Client client = new Client(); client.setDn("inum=0000,ou=clients,o=jans"); - when(ssaRestWebServiceValidator.validateClient()).thenReturn(client); - - HttpServletRequest httpRequest = mock(HttpServletRequest.class); - SecurityContext securityContext = mock(SecurityContext.class); + when(ssaRestWebServiceValidator.getClientFromSession()).thenReturn(client); ExecutionContext executionContext = mock(ExecutionContext.class); ModifySsaResponseContext context = mock(ModifySsaResponseContext.class); @@ -133,15 +130,15 @@ public void create_request_valid() { when(ssaJsonService.jsonObjectToString(any())).thenReturn("{\"ssa\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"}"); when(appConfiguration.getSsaConfiguration()).thenReturn(new SsaConfiguration()); - Response response = ssaCreateAction.create(requestJson.toString(), httpRequest, securityContext); + Response response = ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class)); assertNotNull(response, "response is null"); assertNotNull(response.getEntity(), "response entity is null"); assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode()); verify(errorResponseFactory).validateFeatureEnabled(any()); - verify(log).debug(anyString(), any(SsaRequest.class)); + verify(log).debug(anyString(), any(SsaCreateRequest.class)); verify(staticConfiguration).getBaseDn(); - verify(ssaRestWebServiceValidator).validateClient(); + verify(ssaRestWebServiceValidator).getClientFromSession(); verify(ssaRestWebServiceValidator).checkScopesPolicy(any(), anyString()); verify(ssaService).persist(any()); verify(log).info(anyString(), any(Ssa.class)); @@ -185,7 +182,7 @@ public void create_disabledSsaComponent_forbiddenResponse() { doThrow(error).when(errorResponseFactory).validateFeatureEnabled(any()); try { - ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class), mock(SecurityContext.class)); + ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class)); } catch (WebApplicationException e) { assertNotNull(e, "Exception is null"); assertNotNull(e.getResponse(), "Exception Response is null"); @@ -204,16 +201,16 @@ public void create_invalidClientAndIsErrorEnabledFalse_badRequestResponse() { Response.status(Response.Status.BAD_REQUEST) .entity("Invalid client") .build()); - doThrow(error).when(ssaRestWebServiceValidator).validateClient(); + doThrow(error).when(ssaRestWebServiceValidator).getClientFromSession(); when(log.isErrorEnabled()).thenReturn(Boolean.FALSE); try { - ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class), mock(SecurityContext.class)); + ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class)); } catch (WebApplicationException e) { assertNotNull(e, "Exception is null"); assertNotNull(e.getResponse(), "Exception Response is null"); } - verify(ssaRestWebServiceValidator).validateClient(); + verify(ssaRestWebServiceValidator).getClientFromSession(); verify(log).isErrorEnabled(); verify(log, never()).error(anyString(), any(WebApplicationException.class)); verify(ssaRestWebServiceValidator, never()).checkScopesPolicy(any(), anyString()); @@ -231,16 +228,16 @@ public void create_invalidClientAndIsErrorEnabledTrue_badRequestResponse() { Response.status(Response.Status.BAD_REQUEST) .entity("Invalid client") .build()); - doThrow(error).when(ssaRestWebServiceValidator).validateClient(); + doThrow(error).when(ssaRestWebServiceValidator).getClientFromSession(); when(log.isErrorEnabled()).thenReturn(Boolean.TRUE); try { - ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class), mock(SecurityContext.class)); + ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class)); } catch (WebApplicationException e) { assertNotNull(e, "Exception is null"); assertNotNull(e.getResponse(), "Exception Response is null"); } - verify(ssaRestWebServiceValidator).validateClient(); + verify(ssaRestWebServiceValidator).getClientFromSession(); verify(log).isErrorEnabled(); verify(log).error(anyString(), any(WebApplicationException.class)); verify(ssaRestWebServiceValidator, never()).checkScopesPolicy(any(), anyString()); @@ -257,12 +254,12 @@ public void create_invalidClient_internalServerResponse() { when(errorResponseFactory.createWebApplicationException(any(Response.Status.class), any(SsaErrorResponseType.class), anyString())).thenThrow(error); try { - ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class), mock(SecurityContext.class)); + ssaCreateAction.create(requestJson.toString(), mock(HttpServletRequest.class)); } catch (WebApplicationException e) { assertNotNull(e, "Exception is null"); } verify(staticConfiguration).getBaseDn(); - verify(log).debug(anyString(), any(SsaRequest.class)); + verify(log).debug(anyString(), any(SsaCreateRequest.class)); verify(log).error(eq(null), any(NullPointerException.class)); verify(ssaRestWebServiceValidator, never()).checkScopesPolicy(any(), anyString()); verify(ssaService, never()).persist(any(Ssa.class)); diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaGetActionTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaGetActionTest.java new file mode 100644 index 00000000000..e6253646717 --- /dev/null +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/ssa/ws/rs/action/SsaGetActionTest.java @@ -0,0 +1,136 @@ +package io.jans.as.server.ssa.ws.rs.action; + +import io.jans.as.common.model.registration.Client; +import io.jans.as.model.error.ErrorResponseFactory; +import io.jans.as.model.ssa.SsaErrorResponseType; +import io.jans.as.server.service.external.ModifySsaResponseService; +import io.jans.as.server.ssa.ws.rs.SsaContextBuilder; +import io.jans.as.server.ssa.ws.rs.SsaJsonService; +import io.jans.as.server.ssa.ws.rs.SsaRestWebServiceValidator; +import io.jans.as.server.ssa.ws.rs.SsaService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.slf4j.Logger; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; + +@Listeners(MockitoTestNGListener.class) +public class SsaGetActionTest { + + @InjectMocks + private SsaGetAction ssaGetAction; + + @Mock + private ErrorResponseFactory errorResponseFactory; + + @Mock + private SsaRestWebServiceValidator ssaRestWebServiceValidator; + + @Mock + private SsaService ssaService; + + @Mock + private SsaJsonService ssaJsonService; + + @Mock + private SsaContextBuilder ssaContextBuilder; + + @Mock + private ModifySsaResponseService modifySsaResponseService; + + @Mock + private Logger log; + + @Test + public void get_withAllParam_valid() { + when(ssaJsonService.jsonArrayToString(any())).thenReturn("my body"); + Client client = new Client(); + client.setDn("inum=0000,ou=clients,o=jans"); + when(ssaRestWebServiceValidator.getClientFromSession()).thenReturn(client); + + boolean softwareRoles = false; + String jti = "my-jti"; + String orgId = "1"; + Response response = ssaGetAction.get(softwareRoles, jti, orgId, mock(HttpServletRequest.class)); + assertNotNull(response, "response is null"); + assertNotNull(response.getEntity(), "response entity is null"); + assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + verify(log).debug(anyString(), any(), any(), any()); + verify(errorResponseFactory).validateFeatureEnabled(any()); + verify(ssaContextBuilder).buildModifySsaResponseContext(any(), any(), any(), any(), any()); + verify(ssaJsonService).jsonArrayToString(any()); + verify(modifySsaResponseService).get(any(), any()); + verifyNoMoreInteractions(log, errorResponseFactory); + } + + @Test + public void get_invalidClientAndIsErrorEnabledFalse_badRequestResponse() { + WebApplicationException error = new WebApplicationException( + Response.status(Response.Status.BAD_REQUEST) + .entity("Invalid client") + .build()); + doThrow(error).when(ssaRestWebServiceValidator).getClientFromSession(); + when(log.isErrorEnabled()).thenReturn(Boolean.FALSE); + + boolean softwareRoles = false; + String jti = "my-jti"; + String orgId = "1"; + assertThrows(WebApplicationException.class, () -> ssaGetAction.get(softwareRoles, jti, orgId, mock(HttpServletRequest.class))); + verify(log).debug(anyString(), any(), any(), any()); + verify(ssaRestWebServiceValidator).getClientFromSession(); + verify(log).isErrorEnabled(); + verify(log, never()).error(anyString(), any(WebApplicationException.class)); + verifyNoMoreInteractions(log, ssaRestWebServiceValidator); + verifyNoInteractions(ssaService, ssaContextBuilder, ssaJsonService, modifySsaResponseService); + } + + @Test + public void get_invalidClientAndIsErrorEnabledTrue_badRequestResponse() { + WebApplicationException error = new WebApplicationException( + Response.status(Response.Status.BAD_REQUEST) + .entity("Invalid client") + .build()); + doThrow(error).when(ssaRestWebServiceValidator).getClientFromSession(); + when(log.isErrorEnabled()).thenReturn(Boolean.TRUE); + + boolean softwareRoles = false; + String jti = "my-jti"; + String orgId = "1"; + assertThrows(WebApplicationException.class, () -> ssaGetAction.get(softwareRoles, jti, orgId, mock(HttpServletRequest.class))); + verify(log).debug(anyString(), any(), any(), any()); + verify(ssaRestWebServiceValidator).getClientFromSession(); + verify(log).isErrorEnabled(); + verify(log).error(anyString(), any(WebApplicationException.class)); + verifyNoMoreInteractions(log, ssaRestWebServiceValidator); + verifyNoInteractions(ssaService, ssaContextBuilder, ssaJsonService, modifySsaResponseService); + } + + @Test + public void get_invalidClientInternalServer_badRequestResponse() { + WebApplicationException error = new WebApplicationException( + Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Unknown error") + .build()); + when(errorResponseFactory.createWebApplicationException(any(Response.Status.class), any(SsaErrorResponseType.class), anyString())).thenThrow(error); + + boolean softwareRoles = false; + String jti = "my-jti"; + String orgId = "1"; + assertThrows(WebApplicationException.class, () -> ssaGetAction.get(softwareRoles, jti, orgId, mock(HttpServletRequest.class))); + verify(log).debug(anyString(), any(), any(), any()); + verify(ssaRestWebServiceValidator).getClientFromSession(); + verify(log, never()).isErrorEnabled(); + verify(log).error(any(), any(Exception.class)); + verify(log).error(eq(null), any(NullPointerException.class)); + verify(errorResponseFactory).createWebApplicationException(any(), any(), any()); + verifyNoMoreInteractions(log); + verifyNoInteractions(ssaService, ssaContextBuilder, ssaJsonService, modifySsaResponseService); + } +} \ No newline at end of file diff --git a/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/DummyModifySsaResponseType.java b/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/DummyModifySsaResponseType.java index 15cd89fc846..75762a07c71 100644 --- a/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/DummyModifySsaResponseType.java +++ b/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/DummyModifySsaResponseType.java @@ -37,4 +37,9 @@ public int getApiVersion() { public boolean create(Object jwr, Object tokenContext) { return false; } + + @Override + public boolean get(Object jsonArray, Object ssaContext) { + return true; + } } \ No newline at end of file diff --git a/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/ModifySsaResponseType.java b/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/ModifySsaResponseType.java index 7bd67126152..e7ce92ccb95 100644 --- a/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/ModifySsaResponseType.java +++ b/jans-core/script/src/main/java/io/jans/model/custom/script/type/ssa/ModifySsaResponseType.java @@ -10,5 +10,7 @@ public interface ModifySsaResponseType extends BaseExternalType { - boolean create(Object jsonWebResponse, Object tokenContext); + boolean create(Object jsonWebResponse, Object ssaContext); + + boolean get(Object jsonArray, Object ssaContext); } diff --git a/jans-linux-setup/jans_setup/static/extension/ssa_modify_response/ssa_modify_response.py b/jans-linux-setup/jans_setup/static/extension/ssa_modify_response/ssa_modify_response.py new file mode 100644 index 00000000000..067714a8474 --- /dev/null +++ b/jans-linux-setup/jans_setup/static/extension/ssa_modify_response/ssa_modify_response.py @@ -0,0 +1,32 @@ +from io.jans.model.custom.script.type.ssa import ModifySsaResponseType + +class ModifySsaResponse(ModifySsaResponseType): + def __init__(self, currentTimeMillis): + self.currentTimeMillis = currentTimeMillis + + def init(self, customScript, configurationAttributes): + print "Modify ssa response script. Initializing ..." + print "Modify ssa response script. Initialized successfully" + + return True + + def destroy(self, configurationAttributes): + print "Modify ssa response script. Destroying ..." + print "Modify ssa response script. Destroyed successfully" + return True + + def getApiVersion(self): + return 11 + + def create(self, jsonWebResponse, context): + print "Modify ssa response script. Modify idToken: %s" % jsonWebResponse + + jsonWebResponse.getHeader().setClaim("custom_header_name", "custom_header_value") + jsonWebResponse.getClaims().setClaim("custom_claim_name", "custom_claim_value") + + print "Modify ssa response script. After modify idToken: %s" % jsonWebResponse + return True + + def get(self, jsonArray, context): + print "Modify ssa response script. Modify get ssa list: %s" % jsonArray + return True \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/templates/test/jans-auth/data/oxauth-test-data.ldif b/jans-linux-setup/jans_setup/templates/test/jans-auth/data/oxauth-test-data.ldif index 461280a0ad7..c9f0a194337 100644 --- a/jans-linux-setup/jans_setup/templates/test/jans-auth/data/oxauth-test-data.ldif +++ b/jans-linux-setup/jans_setup/templates/test/jans-auth/data/oxauth-test-data.ldif @@ -238,6 +238,26 @@ objectClass: jansScope jansDefScope: true objectClass: top +dn: inum=SSA1-PTL1,ou=scopes,o=jans +displayName: SSA Portal +inum: SSA1-PTL1 +jansAttrs: {"spontaneousClientId":"","spontaneousClientScopes":[],"showInConfigurationEndpoint":true} +jansId: https://jans.io/auth/ssa.portal +jansScopeTyp: openid +objectClass: jansScope +jansDefScope: true +objectClass: top + +dn: inum=SSA1-DEV1,ou=scopes,o=jans +displayName: SSA Developer +inum: SSA1-DEV1 +jansAttrs: {"spontaneousClientId":"","spontaneousClientScopes":[],"showInConfigurationEndpoint":true} +jansId: https://jans.io/auth/ssa.developer +jansScopeTyp: openid +objectClass: jansScope +jansDefScope: true +objectClass: top + dn: jansId=a55ede29-8f5a-461d-b06e-76caee8d40b5,ou=sector_identifiers,o=jans jansId: a55ede29-8f5a-461d-b06e-76caee8d40b5 jansRedirectURI: https://www.jans.org