diff --git a/src/main/java/com/auth0/client/mgmt/ConnectionsEntity.java b/src/main/java/com/auth0/client/mgmt/ConnectionsEntity.java index 2add53c93..8e8a1b7c9 100644 --- a/src/main/java/com/auth0/client/mgmt/ConnectionsEntity.java +++ b/src/main/java/com/auth0/client/mgmt/ConnectionsEntity.java @@ -4,6 +4,7 @@ import com.auth0.client.mgmt.filter.EnabledClientsFilter; import com.auth0.json.mgmt.connections.*; import com.auth0.net.BaseRequest; +import com.auth0.net.EmptyBodyRequest; import com.auth0.net.Request; import com.auth0.net.VoidRequest; import com.auth0.net.client.Auth0HttpClient; @@ -424,4 +425,42 @@ public Request updateEnabledClients(String connectionId, List> getKeys(String connectionId) { + Asserts.assertNotNull(connectionId, "connection id"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/connections") + .addPathSegment(connectionId) + .addPathSegment("keys") + .build() + .toString(); + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference>() { + }); + } + + /** * Rotate the Connection Keys. + * A token with scope create:connections_keys and update:connections_keys is needed. + * @param connectionId the connection id. + * @return a Request to execute. + */ + public Request rotateKey(String connectionId) { + Asserts.assertNotNull(connectionId, "connection id"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/connections") + .addPathSegment(connectionId) + .addPathSegments("keys/rotate") + .build() + .toString(); + + return new EmptyBodyRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference() {}); + } } diff --git a/src/main/java/com/auth0/json/mgmt/connections/ConnectionKeys.java b/src/main/java/com/auth0/json/mgmt/connections/ConnectionKeys.java new file mode 100644 index 000000000..b1bca6e0f --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/connections/ConnectionKeys.java @@ -0,0 +1,218 @@ +package com.auth0.json.mgmt.connections; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ConnectionKeys { + @JsonProperty("kid") + private String kid; + + @JsonProperty("algorithm") + private String algorithm; + + @JsonProperty("key_use") + private String keyUse; + + @JsonProperty("subject_dn") + private String subjectDn; + + @JsonProperty("cert") + private String cert; + + @JsonProperty("fingerprint") + private String fingerprint; + + @JsonProperty("thumbprint") + private String thumbprint; + + @JsonProperty("pkcs") + private String pkcs; + + @JsonProperty("current") + private Boolean current; + + @JsonProperty("current_since") + private String currentSince; + + @JsonProperty("next") + private Boolean next; + + /** + * Getter for the Key ID (kid). + * @return the Key ID (kid). + */ + public String getKid() { + return kid; + } + + /** + * Setter for the Key ID (kid). + * @param kid the Key ID (kid). + */ + public void setKid(String kid) { + this.kid = kid; + } + + /** + * Getter for the algorithm used by the key. + * @return the algorithm used by the key. + */ + public String getAlgorithm() { + return algorithm; + } + + /** + * Setter for the algorithm used by the key. + * @param algorithm the algorithm used by the key. + */ + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + /** + * Getter for the key use (e.g., "sig" for signature). + * @return the key use. + */ + public String getKeyUse() { + return keyUse; + } + + /** + * Setter for the key use. + * @param keyUse the key use (e.g., "sig" for signature). + */ + public void setKeyUse(String keyUse) { + this.keyUse = keyUse; + } + + /** + * Getter for the subject distinguished name (DN). + * @return the subject DN. + */ + public String getSubjectDn() { + return subjectDn; + } + + /** + * Setter for the subject distinguished name (DN). + * @param subjectDn the subject DN. + */ + public void setSubjectDn(String subjectDn) { + this.subjectDn = subjectDn; + } + + /** + * Getter for the certificate associated with the key. + * @return the certificate. + */ + public String getCert() { + return cert; + } + + /** + * Setter for the certificate associated with the key. + * @param cert the certificate. + */ + public void setCert(String cert) { + this.cert = cert; + } + + /** + * Getter for the fingerprint of the key. + * @return the fingerprint. + */ + public String getFingerprint() { + return fingerprint; + } + + /** + * Setter for the fingerprint of the key. + * @param fingerprint the fingerprint. + */ + public void setFingerprint(String fingerprint) { + this.fingerprint = fingerprint; + } + + /** + * Getter for the thumbprint of the key. + * @return the thumbprint. + */ + public String getThumbprint() { + return thumbprint; + } + + /** + * Setter for the thumbprint of the key. + * @param thumbprint the thumbprint. + */ + public void setThumbprint(String thumbprint) { + this.thumbprint = thumbprint; + } + + /** + * Getter for the PKCS#8 representation of the key. + * @return the PKCS#8 representation. + */ + public String getPkcs() { + return pkcs; + } + + /** + * Setter for the PKCS#8 representation of the key. + * @param pkcs the PKCS#8 representation. + */ + public void setPkcs(String pkcs) { + this.pkcs = pkcs; + } + + /** + * Getter for whether the key is currently active. + * @return true if the key is current, false otherwise. + */ + public Boolean getCurrent() { + return current; + } + + /** + * Setter for whether the key is currently active. + * @param current true if the key is current, false otherwise. + */ + public void setCurrent(Boolean current) { + this.current = current; + } + + /** + * Getter for the timestamp when the key became current. + * @return the timestamp in ISO 8601 format. + */ + public String getCurrentSince() { + return currentSince; + } + + /** + * Setter for the timestamp when the key became current. + * @param currentSince the timestamp in ISO 8601 format. + */ + public void setCurrentSince(String currentSince) { + this.currentSince = currentSince; + } + + /** + * Getter for whether there is a next key available. + * @return true if there is a next key, false otherwise. + */ + public Boolean getNext() { + return next; + } + + /** + * Setter for whether there is a next key available. + * @param next true if there is a next key, false otherwise. + */ + public void setNext(Boolean next) { + this.next = next; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/connections/RotateKey.java b/src/main/java/com/auth0/json/mgmt/connections/RotateKey.java new file mode 100644 index 000000000..d83bc656a --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/connections/RotateKey.java @@ -0,0 +1,46 @@ +package com.auth0.json.mgmt.connections; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RotateKey { + @JsonProperty("cert") + private String cert; + @JsonProperty("kid") + private String kid; + + /** + * Returns the certificate used for the key rotation. + * @return the certificate as a String. + */ + public String getCert() { + return cert; + } + + /** + * Sets the certificate used for the key rotation. + * @param cert the certificate as a String. + */ + public void setCert(String cert) { + this.cert = cert; + } + + /** + * Returns the Key ID (kid) of the key being rotated. + * @return the Key ID as a String. + */ + public String getKid() { + return kid; + } + + /** + * Sets the Key ID (kid) of the key being rotated. + * @param kid the Key ID as a String. + */ + public void setKid(String kid) { + this.kid = kid; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 54a6b440d..4e059da14 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -50,6 +50,8 @@ public class MockServer { public static final String MGMT_CONNECTION_SCIM_TOKENS = "src/test/resources/mgmt/connection_scim_tokens.json"; public static final String MGMT_CONNECTION_SCIM_TOKEN = "src/test/resources/mgmt/connection_scim_token.json"; public static final String MGMT_ENABLED_CLIENTS_FOR_CONNECTION = "src/test/resources/mgmt/enabled_clients_for_connection.json"; + public static final String MGMT_CONNECTION_KEY = "src/test/resources/mgmt/connection_key.json"; + public static final String MGMT_ROTATE_KEY = "src/test/resources/mgmt/rotate_key.json"; public static final String MGMT_DEVICE_CREDENTIALS_LIST = "src/test/resources/mgmt/device_credentials_list.json"; public static final String MGMT_DEVICE_CREDENTIALS = "src/test/resources/mgmt/device_credentials.json"; public static final String MGMT_GRANTS_LIST = "src/test/resources/mgmt/grants_list.json"; diff --git a/src/test/java/com/auth0/client/mgmt/ConnectionsEntityTest.java b/src/test/java/com/auth0/client/mgmt/ConnectionsEntityTest.java index d6ded9060..bf19b4908 100644 --- a/src/test/java/com/auth0/client/mgmt/ConnectionsEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/ConnectionsEntityTest.java @@ -618,35 +618,79 @@ public void shouldThrowOnUpdateEnabledClientsWithNullId() { "'connection id' cannot be null!"); } -// @Test -// public void shouldThrowOnUpdateEnabledClientsWithNullRequest() { -//; verifyThrows(IllegalArgumentException.class, -// () -> api.connections().updateEnabledClients("1", null), -// "'client id' cannot be null!"); -// } - - -// @Test -// public void shouldUpdateEnabledClients() throws Exception { -// EnabledClientRequest clientRequest = new EnabledClientRequest("clientId", true); -// List enabledClientRequests = new ArrayList<>(); -// enabledClientRequests.add(clientRequest); -// Request request = api.connections().updateEnabledClients("1", enabledClientRequests); -// assertThat(request, is(notNullValue())); -// -// server.jsonResponse(MGMT_ENABLED_CLIENTS_FOR_CONNECTION, 200); -// request.execute().getBody(); -// RecordedRequest recordedRequest = server.takeRequest(); -// -// assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PATCH, "/api/v2/connections/1/clients")); -// assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); -// assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); -// -// Map body = bodyFromRequest(recordedRequest); -// assertThat(body.size(), is(2)); -// assertThat(body, hasEntry("client_id", "clientId")); -// assertThat(body, hasEntry("status", true)); -// } + @Test + public void shouldThrowOnUpdateEnabledClientsWithNullRequest() { +; verifyThrows(IllegalArgumentException.class, + () -> api.connections().updateEnabledClients("1", null), + "'enabled client Request' cannot be null!"); + } + + + @Test + public void shouldUpdateEnabledClients() throws Exception { + EnabledClientRequest clientRequest = new EnabledClientRequest("clientId", true); + List enabledClientRequests = new ArrayList<>(); + enabledClientRequests.add(clientRequest); + Request request = api.connections().updateEnabledClients("1", enabledClientRequests); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_ENABLED_CLIENTS_FOR_CONNECTION, 200); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PATCH, "/api/v2/connections/1/clients")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + List body = bodyListFromRequest(recordedRequest); + assertThat(body, is(notNullValue())); + } + + @Test + public void shouldThrowOnGetKeysWithNullId() { + verifyThrows(IllegalArgumentException.class, + () -> api.connections().getKeys(null), + "'connection id' cannot be null!"); + } + + @Test + public void shouldGetKeys() throws Exception { + Request> request = api.connections().getKeys("1"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_CONNECTION_KEY, 200); + List response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/connections/1/keys")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnRotateKeyWithNullId() { + verifyThrows(IllegalArgumentException.class, + () -> api.connections().rotateKey(null), + "'connection id' cannot be null!"); + } + + @Test + public void shouldRotateKey() throws Exception { + Request request = api.connections().rotateKey("1"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_ROTATE_KEY, 200); + RotateKey response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/connections/1/keys/rotate")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } private ScimTokenRequest getScimToken() { ScimTokenRequest request = new ScimTokenRequest(); diff --git a/src/test/java/com/auth0/json/mgmt/connections/ConnectionKeysTest.java b/src/test/java/com/auth0/json/mgmt/connections/ConnectionKeysTest.java new file mode 100644 index 000000000..764e58a5c --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/connections/ConnectionKeysTest.java @@ -0,0 +1,66 @@ +package com.auth0.json.mgmt.connections; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class ConnectionKeysTest extends JsonTest { + private static final String json = "{\n" + + " \"kid\": \"kid-1\",\n" + + " \"algorithm\": \"RS256\",\n" + + " \"key_use\": \"signing\",\n" + + " \"subject_dn\": \"/CN=cajwt\",\n" + + " \"cert\": \"-----BEGIN CERTIFICATE-----\\r\\ncert-key-1\\r\\n-----END CERTIFICATE-----\\r\\n\",\n" + + " \"fingerprint\": \"F1\",\n" + + " \"thumbprint\": \"example-print\",\n" + + " \"pkcs\": \"-----BEGIN PKCS7-----\\r\\npkcs-1\\r\\n-----END PKCS7-----\\r\\n\",\n" + + " \"current\": true,\n" + + " \"current_since\": \"2025-05-29T13:17:24.850Z\"\n" + + " }"; + + @Test + public void shouldSerialize() throws Exception { + ConnectionKeys connectionKeys = new ConnectionKeys(); + connectionKeys.setKid("kid-1"); + connectionKeys.setAlgorithm("RS256"); + connectionKeys.setKeyUse("signing"); + connectionKeys.setSubjectDn("/CN=cajwt"); + connectionKeys.setFingerprint("F1"); + connectionKeys.setThumbprint("example-print"); + connectionKeys.setPkcs("pkcs"); + connectionKeys.setCurrent(true); + connectionKeys.setCurrentSince("2025-05-29T13:17:24.850Z"); + + String serialized = toJSON(connectionKeys); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("kid", "kid-1")); + assertThat(serialized, JsonMatcher.hasEntry("algorithm", "RS256")); + assertThat(serialized, JsonMatcher.hasEntry("key_use", "signing")); + assertThat(serialized, JsonMatcher.hasEntry("subject_dn", "/CN=cajwt")); + assertThat(serialized, JsonMatcher.hasEntry("fingerprint", "F1")); + assertThat(serialized, JsonMatcher.hasEntry("thumbprint", "example-print")); + assertThat(serialized, JsonMatcher.hasEntry("pkcs", "pkcs")); + assertThat(serialized, JsonMatcher.hasEntry("current", true)); + assertThat(serialized, JsonMatcher.hasEntry("current_since", "2025-05-29T13:17:24.850Z")); + } + + @Test + public void shouldDeserialize() throws Exception { + ConnectionKeys connectionKey = fromJSON(json, ConnectionKeys.class); + assertThat(connectionKey, is(notNullValue())); + assertThat(connectionKey.getKid(), is("kid-1")); + assertThat(connectionKey.getAlgorithm(), is("RS256")); + assertThat(connectionKey.getKeyUse(), is("signing")); + assertThat(connectionKey.getSubjectDn(), is("/CN=cajwt")); + assertThat(connectionKey.getCert(), is("-----BEGIN CERTIFICATE-----\r\ncert-key-1\r\n-----END CERTIFICATE-----\r\n")); + assertThat(connectionKey.getFingerprint(), is("F1")); + assertThat(connectionKey.getThumbprint(), is("example-print")); + assertThat(connectionKey.getPkcs(), is("-----BEGIN PKCS7-----\r\npkcs-1\r\n-----END PKCS7-----\r\n")); + assertThat(connectionKey.getCurrent(), is(true)); + assertThat(connectionKey.getCurrentSince(), is("2025-05-29T13:17:24.850Z")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/connections/RotateKeyTest.java b/src/test/java/com/auth0/json/mgmt/connections/RotateKeyTest.java new file mode 100644 index 000000000..570e163d2 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/connections/RotateKeyTest.java @@ -0,0 +1,35 @@ +package com.auth0.json.mgmt.connections; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class RotateKeyTest extends JsonTest { + private static final String json = "src/test/resources/mgmt/rotate_key.json"; + + @Test + public void shouldSerialize() throws Exception { + RotateKey rotateKey = new RotateKey(); + rotateKey.setCert("-----BEGIN CERTIFICATE-----cert-key-----END CERTIFICATE-----"); + rotateKey.setKid("kid-1"); + + String serialized = toJSON(rotateKey); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("cert", "-----BEGIN CERTIFICATE-----cert-key-----END CERTIFICATE-----")); + assertThat(serialized, JsonMatcher.hasEntry("kid", "kid-1")); + } + + @Test + public void shouldDeserialize() throws Exception { + RotateKey deserialized = fromJSON(readTextFile(json), RotateKey.class); + + assertThat(deserialized, is(notNullValue())); + assertThat(deserialized.getCert(), is("-----BEGIN CERTIFICATE-----cert-key-----END CERTIFICATE-----")); + assertThat(deserialized.getKid(), is("kid-1")); + + } +} diff --git a/src/test/resources/mgmt/connection_key.json b/src/test/resources/mgmt/connection_key.json new file mode 100644 index 000000000..0e4a30720 --- /dev/null +++ b/src/test/resources/mgmt/connection_key.json @@ -0,0 +1,25 @@ +[ + { + "kid": "kid-1", + "algorithm": "RS256", + "key_use": "signing", + "subject_dn": "/CN=cajwt", + "cert": "-----BEGIN CERTIFICATE-----\r\ncert-key-1\r\n-----END CERTIFICATE-----\r\n", + "fingerprint": "F1", + "thumbprint": "example-print", + "pkcs": "-----BEGIN PKCS7-----\r\npkcs-1\r\n-----END PKCS7-----\r\n", + "current": true, + "current_since": "2025-05-29T13:17:24.850Z" + }, + { + "kid": "kid-2", + "algorithm": "RS256", + "key_use": "signing", + "subject_dn": "/CN=cajwt", + "cert": "-----BEGIN CERTIFICATE-----\r\ncert-key-2\r\n-----END CERTIFICATE-----\r\n", + "fingerprint": "F2", + "thumbprint": "example-print", + "pkcs": "-----BEGIN PKCS7-----\r\npkcs-2\r\n-----END PKCS7-----\r\n", + "next": true + } +] diff --git a/src/test/resources/mgmt/rotate_key.json b/src/test/resources/mgmt/rotate_key.json new file mode 100644 index 000000000..706ea8235 --- /dev/null +++ b/src/test/resources/mgmt/rotate_key.json @@ -0,0 +1,4 @@ +{ + "kid": "kid-1", + "cert": "-----BEGIN CERTIFICATE-----cert-key-----END CERTIFICATE-----" +}