From 5e4b91eda6e04d7750e1d009e00fe429f19235e3 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Tue, 6 Apr 2021 10:05:48 -0500 Subject: [PATCH 1/7] Add Organizations Management API Support [SDK-2437] (#341) * Add Organizations Management API Support * Add tests for get user organizations --- .../com/auth0/client/mgmt/JobsEntity.java | 28 +- .../com/auth0/client/mgmt/ManagementAPI.java | 9 + .../client/mgmt/OrganizationsEntity.java | 562 +++++++++++ .../com/auth0/client/mgmt/UsersEntity.java | 30 + .../client/mgmt/filter/InvitationsFilter.java | 58 ++ .../com/auth0/json/mgmt/client/Client.java | 35 + .../json/mgmt/organizations/Branding.java | 51 + .../auth0/json/mgmt/organizations/Colors.java | 64 ++ .../json/mgmt/organizations/Connection.java | 51 + .../ConnectionsPageDeserializer.java | 24 + .../mgmt/organizations/EnabledConnection.java | 80 ++ .../organizations/EnabledConnectionsPage.java | 27 + .../json/mgmt/organizations/Invitation.java | 222 +++++ .../mgmt/organizations/InvitationsPage.java | 27 + .../InvitationsPageDeserializer.java | 25 + .../json/mgmt/organizations/Invitee.java | 34 + .../json/mgmt/organizations/Inviter.java | 34 + .../auth0/json/mgmt/organizations/Member.java | 78 ++ .../json/mgmt/organizations/Members.java | 38 + .../json/mgmt/organizations/MembersPage.java | 26 + .../MembersPageDeserializer.java | 25 + .../json/mgmt/organizations/Organization.java | 111 +++ .../mgmt/organizations/OrganizationsPage.java | 26 + .../OrganizationsPageDeserializer.java | 26 + .../auth0/json/mgmt/organizations/Roles.java | 36 + .../mgmt/tickets/PasswordChangeTicket.java | 22 + .../java/com/auth0/client/MockServer.java | 13 + .../com/auth0/client/mgmt/JobsEntityTest.java | 22 + .../client/mgmt/OrganizationEntityTest.java | 906 ++++++++++++++++++ .../auth0/client/mgmt/UsersEntityTest.java | 79 +- .../auth0/json/mgmt/client/ClientTest.java | 8 +- .../EnabledConnectionsPageTest.java | 79 ++ .../organizations/EnabledConnectionsTest.java | 55 ++ .../mgmt/organizations/InvitationTest.java | 79 ++ .../organizations/InvitationsPageTest.java | 109 +++ .../mgmt/organizations/MembersPageTest.java | 72 ++ .../json/mgmt/organizations/MembersTest.java | 43 + .../organizations/OrganizationsPageTest.java | 87 ++ .../mgmt/organizations/OrganizationsTest.java | 70 ++ .../tickets/PasswordChangeTicketTest.java | 2 + src/test/resources/mgmt/invitation.json | 15 + src/test/resources/mgmt/invitations_list.json | 34 + .../mgmt/invitations_paged_list.json | 38 + src/test/resources/mgmt/organization.json | 15 + .../mgmt/organization_connection.json | 4 + .../mgmt/organization_connections_list.json | 18 + .../organization_connections_paged_list.json | 23 + .../mgmt/organization_member_roles_list.json | 7 + .../organization_member_roles_paged_list.json | 12 + .../mgmt/organization_members_list.json | 20 + .../mgmt/organization_members_paged_list.json | 25 + .../resources/mgmt/organizations_list.json | 22 + .../mgmt/organizations_paged_list.json | 27 + 53 files changed, 3615 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java create mode 100644 src/main/java/com/auth0/client/mgmt/filter/InvitationsFilter.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Branding.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Colors.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Connection.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/ConnectionsPageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Invitation.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/InvitationsPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/InvitationsPageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Invitee.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Inviter.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Member.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Members.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/MembersPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/MembersPageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Organization.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/organizations/Roles.java create mode 100644 src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/InvitationTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/InvitationsPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/MembersPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/MembersTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/OrganizationsPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/organizations/OrganizationsTest.java create mode 100644 src/test/resources/mgmt/invitation.json create mode 100644 src/test/resources/mgmt/invitations_list.json create mode 100644 src/test/resources/mgmt/invitations_paged_list.json create mode 100644 src/test/resources/mgmt/organization.json create mode 100644 src/test/resources/mgmt/organization_connection.json create mode 100644 src/test/resources/mgmt/organization_connections_list.json create mode 100644 src/test/resources/mgmt/organization_connections_paged_list.json create mode 100644 src/test/resources/mgmt/organization_member_roles_list.json create mode 100644 src/test/resources/mgmt/organization_member_roles_paged_list.json create mode 100644 src/test/resources/mgmt/organization_members_list.json create mode 100644 src/test/resources/mgmt/organization_members_paged_list.json create mode 100644 src/test/resources/mgmt/organizations_list.json create mode 100644 src/test/resources/mgmt/organizations_paged_list.json diff --git a/src/main/java/com/auth0/client/mgmt/JobsEntity.java b/src/main/java/com/auth0/client/mgmt/JobsEntity.java index e2d4b48ac..adfac7a71 100644 --- a/src/main/java/com/auth0/client/mgmt/JobsEntity.java +++ b/src/main/java/com/auth0/client/mgmt/JobsEntity.java @@ -81,19 +81,39 @@ public Request sendVerificationEmail(String userId, String clientId) { * @see JobsEntity#sendVerificationEmail(String, String) */ public Request sendVerificationEmail(String userId, String clientId, EmailVerificationIdentity emailVerificationIdentity) { + return sendVerificationEmail(userId, clientId, emailVerificationIdentity, null); + } + + /** + * Sends an Email Verification. A token with scope update:users is needed. + * See https://auth0.com/docs/api/management/v2#!/Jobs/post_verification_email. + * + * @param userId The user_id of the user to whom the email will be sent. + * @param clientId The id of the client, if not provided the global one will be used. + * @param emailVerificationIdentity The identity of the user. Required to verify primary identities when using social, enterprise, or passwordless connections. It is also required to verify secondary identities. + * @param orgId The organization ID. If provided, the organization_id and organization_name will be included as query arguments in the link back to the application. + * + * @return a Request to execute. + * + * @see JobsEntity#sendVerificationEmail(String, String) + */ + public Request sendVerificationEmail(String userId, String clientId, EmailVerificationIdentity emailVerificationIdentity, String orgId) { Asserts.assertNotNull(userId, "user id"); String url = baseUrl - .newBuilder() - .addPathSegments("api/v2/jobs/verification-email") - .build() - .toString(); + .newBuilder() + .addPathSegments("api/v2/jobs/verification-email") + .build() + .toString(); Map requestBody = new HashMap<>(); requestBody.put("user_id", userId); if (clientId != null && !clientId.isEmpty()) { requestBody.put("client_id", clientId); } + if (orgId != null && !orgId.isEmpty()) { + requestBody.put("organization_id", orgId); + } if (emailVerificationIdentity != null) { Asserts.assertNotNull(emailVerificationIdentity.getProvider(), "identity provider"); Asserts.assertNotNull(emailVerificationIdentity.getUserId(), "identity user id"); diff --git a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java index 983c56aec..17efb8406 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java @@ -348,4 +348,13 @@ public JobsEntity jobs() { public RolesEntity roles() { return new RolesEntity(client, baseUrl, apiToken); } + + /** + * Getter for the Organizations entity. + * + * @return the Organizations entity. + */ + public OrganizationsEntity organizations() { + return new OrganizationsEntity(client, baseUrl, apiToken); + } } diff --git a/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java new file mode 100644 index 000000000..4a118d6ad --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java @@ -0,0 +1,562 @@ +package com.auth0.client.mgmt; + +import com.auth0.client.mgmt.filter.BaseFilter; +import com.auth0.client.mgmt.filter.FieldsFilter; +import com.auth0.client.mgmt.filter.InvitationsFilter; +import com.auth0.client.mgmt.filter.PageFilter; +import com.auth0.json.mgmt.RolesPage; +import com.auth0.json.mgmt.organizations.*; +import com.auth0.net.CustomRequest; +import com.auth0.net.Request; +import com.auth0.net.VoidRequest; +import com.auth0.utils.Asserts; +import com.fasterxml.jackson.core.type.TypeReference; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; + +import java.util.Map; + +/** + * Class that provides an implementation of the Organization endpoints of the Management API. + *

+ * This class is not thread-safe. + * + * @see ManagementAPI + */ +public class OrganizationsEntity extends BaseManagementEntity { + + private final static String ORGS_PATH = "api/v2/organizations"; + private final static String AUTHORIZATION_HEADER = "Authorization"; + + OrganizationsEntity(OkHttpClient client, HttpUrl baseUrl, String apiToken) { + super(client, baseUrl, apiToken); + } + + // Organizations Entity + + /** + * Get all organizations. A token with read:organizations scope is required. + * + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request list(PageFilter filter) { + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Get an organization. A token with read:organizations scope is required. + * + * @param orgId the ID of the organization to retrieve + * @return a Request to execute + */ + public Request get(String orgId) { + Asserts.assertNotNull(orgId, "organization ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Get an organization. A token with read:organizations scope is required. + * + * @param orgName the name of the organization to retrieve + * @return a Request to execute + */ + public Request getByName(String orgName) { + Asserts.assertNotNull(orgName, "organization name"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment("name") + .addPathSegment(orgName) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Create an organization. A token with create:organizations scope is required. + * + * @param organization the organization to create + * @return a Request to execute + */ + public Request create(Organization organization) { + Asserts.assertNotNull(organization, "organization"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "POST", new TypeReference() { + }); + + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(organization); + return request; + } + + /** + * Update an organization. A token with update:organizations scope is required. + * + * @param orgId the ID of the organization to update + * @param organization the updated organization + * @return a Request to execute + */ + public Request update(String orgId, Organization organization) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(organization, "organization"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "PATCH", new TypeReference() { + }); + + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(organization); + return request; + } + + /** + * Delete an organization. A token with delete:organizations scope is required. + * + * @param orgId the ID of the organization to delete + * @return a Request to execute + */ + public Request delete(String orgId) { + Asserts.assertNotNull(orgId, "organization ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .build() + .toString(); + + VoidRequest voidRequest = new VoidRequest(client, url, "DELETE"); + voidRequest.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return voidRequest; + } + + // Organization members + + /** + * Get the members of an organization. A token with read:organization_members scope is required. + * + * @param orgId the ID of the organization + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request getMembers(String orgId, PageFilter filter) { + Asserts.assertNotNull(orgId, "organization ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members"); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Add members to an organization. A token with create:organization_members scope is required. + * + * @param orgId the ID of the organization + * @param members The members to add + * @return a Request to execute + */ + public Request addMembers(String orgId, Members members) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(members, "members"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members") + .build() + .toString(); + + VoidRequest request = new VoidRequest(client, url, "POST"); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(members); + return request; + } + + /** + * Delete members from an organization. A token with delete:organization_members scope is required. + * + * @param orgId the ID of the organization + * @param members The members to remove + * @return a Request to execute + */ + public Request deleteMembers(String orgId, Members members) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(members, "members"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members") + .build() + .toString(); + + VoidRequest request = new VoidRequest(client, url, "DELETE"); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(members); + return request; + } + + // Organization connections + + /** + * Get the connections of an organization. A token with read:organization_connections scope is required. + * + * @param orgId the ID of the organization + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request getConnections(String orgId, PageFilter filter) { + Asserts.assertNotNull(orgId, "organization ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("enabled_connections"); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Add a connection to an organization. A token with create:organization_connections scope is required. + * + * @param orgId the ID of the organization + * @param connection The connection to add + * @return a Request to execute + */ + public Request addConnection(String orgId, EnabledConnection connection) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(connection, "connection"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("enabled_connections") + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "POST", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(connection); + return request; + } + + /** + * Delete a connection from an organization. A token with delete:organization_connections scope is required. + * + * @param orgId the ID of the organization + * @param connectionId the ID of the connection to delete + * @return a Request to execute + */ + public Request deleteConnection(String orgId, String connectionId) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(connectionId, "connection ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("enabled_connections") + .addPathSegment(connectionId) + .build() + .toString(); + + VoidRequest voidRequest = new VoidRequest(client, url, "DELETE"); + voidRequest.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return voidRequest; + } + + /** + * Update a connection of an organization. A token with update:organization_connections scope is required. + * + * @param orgId the ID of the organization + * @param connectionId the ID of the connection to update + * @param connection the connection to update + * @return a Request to execute + */ + public Request updateConnection(String orgId, String connectionId, EnabledConnection connection) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(connectionId, "connection ID"); + Asserts.assertNotNull(connection, "connection"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("enabled_connections") + .addPathSegment(connectionId) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "PATCH", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(connection); + return request; + } + + // Org roles + + /** + * Get the roles for a member of an organization. A token with read:organization_members scope is required. + * + * @param orgId the ID of the organization + * @param userId the ID of the user + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request getRoles(String orgId, String userId, PageFilter filter) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(userId, "user ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members") + .addPathSegment(userId) + .addPathSegment("roles"); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Add roles for a member of an organization. A token with create:organization_member_roles scope is required. + * + * @param orgId the ID of the organization + * @param userId the ID of the user + * @param roles the roles to add + * @return a Request to execute + */ + public Request addRoles(String orgId, String userId, Roles roles) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(userId, "user ID"); + Asserts.assertNotNull(roles, "roles"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members") + .addPathSegment(userId) + .addPathSegment("roles") + .build() + .toString(); + + VoidRequest request = new VoidRequest(client, url, "POST"); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(roles); + return request; + } + + /** + * Delete roles from a member of an organization. A token with delete:organization_member_roles scope is required. + * + * @param orgId the ID of the organization + * @param userId the ID of the user + * @param roles the roles to delete + * @return a Request to execute + */ + public Request deleteRoles(String orgId, String userId, Roles roles) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(userId, "user ID"); + Asserts.assertNotNull(roles, "roles"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("members") + .addPathSegment(userId) + .addPathSegment("roles") + .build() + .toString(); + + VoidRequest request = new VoidRequest(client, url, "DELETE"); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(roles); + return request; + } + + // Organization invitations + + /** + * Create an invitation. A token with create:organization_invitations scope is required. + * + * @param orgId the ID of the organization + * @param invitation the invitation to create + * @return a Request to execute + */ + public Request createInvitation(String orgId, Invitation invitation) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(invitation, "invitation"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("invitations") + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "POST", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + request.setBody(invitation); + return request; + + } + + /** + * Get an invitation. A token with read:organization_invitations scope is required. + * + * @param orgId the ID of the organization + * @param invitationId the ID of the invitation + * @param filter an optional result filter + * @return a Request to execute + */ + public Request getInvitation(String orgId, String invitationId, FieldsFilter filter) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(invitationId, "invitation ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("invitations") + .addPathSegment(invitationId); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Gets all invitations for an organization. A token with read:organization_invitations scope is required. + * + * @param orgId the ID of the organization + * @param filter an optional result filter + * @return a Request to execute + */ + public Request getInvitations(String orgId, InvitationsFilter filter) { + Asserts.assertNotNull(orgId, "organization ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("invitations"); + + applyFilter(filter, builder); + + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + /** + * Delete an invitation. A token with delete:organization_invitations scope is required. + * + * @param orgId the ID of the organization + * @param invitationId the ID of the invitation to delete + * @return a Request to execute + */ + public Request deleteInvitation(String orgId, String invitationId) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(invitationId, "invitation ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("invitations") + .addPathSegment(invitationId) + .build() + .toString(); + + VoidRequest request = new VoidRequest(client, url, "DELETE"); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + + private void applyFilter(BaseFilter filter, HttpUrl.Builder builder) { + if (filter != null) { + for (Map.Entry e : filter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + } +} diff --git a/src/main/java/com/auth0/client/mgmt/UsersEntity.java b/src/main/java/com/auth0/client/mgmt/UsersEntity.java index 5c0078cd1..6a25d9bf3 100644 --- a/src/main/java/com/auth0/client/mgmt/UsersEntity.java +++ b/src/main/java/com/auth0/client/mgmt/UsersEntity.java @@ -9,6 +9,7 @@ import com.auth0.json.mgmt.RolesPage; import com.auth0.json.mgmt.guardian.Enrollment; import com.auth0.json.mgmt.logevents.LogEventsPage; +import com.auth0.json.mgmt.organizations.OrganizationsPage; import com.auth0.json.mgmt.users.Identity; import com.auth0.json.mgmt.users.RecoveryCode; import com.auth0.json.mgmt.users.User; @@ -575,4 +576,33 @@ public Request addRoles(String userId, List roleIds) { request.addHeader("Authorization", "Bearer " + apiToken); return request; } + + /** + * Get the organizations a user belongs to. + * A token with read:users and read:organizations is required. + * + * @param userId the user ID + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request getOrganizations(String userId, PageFilter filter) { + Asserts.assertNotNull(userId, "user ID"); + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments("api/v2/users") + .addPathSegment(userId) + .addPathSegment("organizations"); + + if (filter != null) { + for (Map.Entry e : filter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + String url = builder.build().toString(); + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader("Authorization", "Bearer " + apiToken); + return request; + } } diff --git a/src/main/java/com/auth0/client/mgmt/filter/InvitationsFilter.java b/src/main/java/com/auth0/client/mgmt/filter/InvitationsFilter.java new file mode 100644 index 000000000..6ac8b0160 --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/filter/InvitationsFilter.java @@ -0,0 +1,58 @@ +package com.auth0.client.mgmt.filter; + +/** + * Class used to filter the results received when fetching invitations. Related to the {@linkplain com.auth0.client.mgmt.OrganizationsEntity}. + *

+ * This class is not thread-safe. + */ +public class InvitationsFilter extends BaseFilter { + + /** + * Filter by page + * + * @param pageNumber the page number to retrieve. + * @param amountPerPage the amount of items per page to retrieve. + * @return this filter instance + */ + public InvitationsFilter withPage(int pageNumber, int amountPerPage) { + parameters.put("page", pageNumber); + parameters.put("per_page", amountPerPage); + return this; + } + + /** + * Include the query summary + * + * @param includeTotals whether to include or not the query summary. + * @return this filter instance + */ + public InvitationsFilter withTotals(boolean includeTotals) { + parameters.put("include_totals", includeTotals); + return this; + } + + /** + * Only retrieve certain fields from the item. + * + * @param fields a list of comma separated fields to retrieve. + * @param includeFields whether to include or exclude in the response the fields that were given. + * @return this filter instance + */ + public InvitationsFilter withFields(String fields, boolean includeFields) { + parameters.put("fields", fields); + parameters.put("include_fields", includeFields); + return this; + } + + /** + * Sort the query + * + * @param sort the field to use for sorting. Use 'field:order' where order is 1 for ascending and -1 for descending. + * @return this filter instance + */ + public InvitationsFilter withSort(String sort) { + parameters.put("sort", sort); + return this; + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/client/Client.java b/src/main/java/com/auth0/json/mgmt/client/Client.java index 6afdbc667..7621cd47c 100644 --- a/src/main/java/com/auth0/json/mgmt/client/Client.java +++ b/src/main/java/com/auth0/json/mgmt/client/Client.java @@ -78,6 +78,10 @@ public class Client { private Mobile mobile; @JsonProperty("refresh_token") private RefreshToken refreshToken; + @JsonProperty("organization_usage") + private String organizationUsage; + @JsonProperty("organization_require_behavior") + private String organizationRequireBehavior; /** * Creates a new Application instance setting the name property. @@ -677,5 +681,36 @@ public RefreshToken getRefreshToken() { public void setRefreshToken(RefreshToken refreshToken) { this.refreshToken = refreshToken; } + + /** + * @return the organization usage value + */ + public String getOrganizationUsage() { + return organizationUsage; + } + + /** + * Sets the value of the organization_usage field + * + * @param organizationUsage the organization_usage value + */ + public void setOrganizationUsage(String organizationUsage) { + this.organizationUsage = organizationUsage; + } + + /** + * @return the organization require behavior value + */ + public String getOrganizationRequireBehavior() { + return organizationRequireBehavior; + } + + /** + * Sets the value of the organization_require_behavior field + * @param organizationRequireBehavior the organization_require_behavior value + */ + public void setOrganizationRequireBehavior(String organizationRequireBehavior) { + this.organizationRequireBehavior = organizationRequireBehavior; + } } diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Branding.java b/src/main/java/com/auth0/json/mgmt/organizations/Branding.java new file mode 100644 index 000000000..c901a8b2e --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Branding.java @@ -0,0 +1,51 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the branding object of an {@linkplain Organization}. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Branding { + + @JsonProperty("logo_url") + private String logoUrl; + @JsonProperty("colors") + private Colors colors; + + /** + * @return the value of the logo URL + */ + public String getLogoUrl() { + return logoUrl; + } + + /** + * Sets the value of the logo URL to display on the login page + * + * @param logoUrl the logo URL to display on the login page. Must be an HTTPS URL or null. + */ + public void setLogoUrl(String logoUrl) { + this.logoUrl = logoUrl; + } + + /** + * @return the {@linkplain Colors} for this Branding instance. + */ + public Colors getColors() { + return colors; + } + + /** + * Sets the value of the {@linkplain Colors} for this Branding instance. + * + * @param colors the colors associated with this Branding instance. + */ + public void setColors(Colors colors) { + this.colors = colors; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Colors.java b/src/main/java/com/auth0/json/mgmt/organizations/Colors.java new file mode 100644 index 000000000..82c2b8bee --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Colors.java @@ -0,0 +1,64 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the colors object of a {@linkplain Branding}. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Colors { + + @JsonProperty("primary") + private String primary; + @JsonProperty("page_background") + private String pageBackground; + + public Colors() {} + + /** + * Create a new instance. + * + * @param primary the HEX color for primary elements. + * @param pageBackground the HEX color for background. + */ + public Colors(@JsonProperty("primary") String primary, @JsonProperty("page_background") String pageBackground) { + this.primary = primary; + this.pageBackground = pageBackground; + } + + /** + * @return the primary color value. + */ + public String getPrimary() { + return primary; + } + + /** + * Sets the color for primary elements. + * + * @param primary the HEX color for primary elements. + */ + public void setPrimary(String primary) { + this.primary = primary; + } + + /** + * @return the background color value. + */ + public String getPageBackground() { + return pageBackground; + } + + /** + * Sets the color for the background. + * + * @param pageBackground the HEX color for the background. + */ + public void setPageBackground(String pageBackground) { + this.pageBackground = pageBackground; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Connection.java b/src/main/java/com/auth0/json/mgmt/organizations/Connection.java new file mode 100644 index 000000000..e37b38617 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Connection.java @@ -0,0 +1,51 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the Connection object of an {@linkplain EnabledConnection}. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Connection { + + @JsonProperty("name") + private String name; + @JsonProperty("strategy") + private String strategy; + + /** + * @return the name of the connection. + */ + public String getName() { + return this.name; + } + + /** + * Sets the name of the connection. + * + * @param name the name of the connection. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the strategy of the connection + */ + public String getStrategy() { + return this.strategy; + } + + /** + * Sets the strategy of this connection. + * + * @param strategy the strategy of the connection. + */ + public void setStrategy(String strategy) { + this.strategy = strategy; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/ConnectionsPageDeserializer.java b/src/main/java/com/auth0/json/mgmt/organizations/ConnectionsPageDeserializer.java new file mode 100644 index 000000000..bf08def5d --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/ConnectionsPageDeserializer.java @@ -0,0 +1,24 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.PageDeserializer; + +import java.util.List; + +/** + * Parses a paged response into its {@linkplain EnabledConnectionsPage} representation. + */ +public class ConnectionsPageDeserializer extends PageDeserializer { + protected ConnectionsPageDeserializer() { + super(EnabledConnection.class, "enabled_connections"); + } + + @Override + protected EnabledConnectionsPage createPage(List items) { + return new EnabledConnectionsPage(items); + } + + @Override + protected EnabledConnectionsPage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new EnabledConnectionsPage(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java new file mode 100644 index 000000000..1233e6077 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java @@ -0,0 +1,80 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the enabled connection object for an organization. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class EnabledConnection { + + @JsonProperty("connection") + private Connection connection; + @JsonProperty("assign_membership_on_login") + private boolean assignMembershipOnLogin; + @JsonProperty("connection_id") + private String connectionId; + + public EnabledConnection() {} + + /** + * Create a new instance. + * + * @param connectionId the ID of the connection + */ + public EnabledConnection(@JsonProperty("connection_id") String connectionId) { + this.connectionId = connectionId; + } + + /** + * @return the value of the {@linkplain Connection}. + */ + public Connection getConnection() { + return connection; + } + + /** + * Sets the value of the {@linkplain Connection}. + * + * @param connection the {@linkplain Connection} to set. + */ + public void setConnection(Connection connection) { + this.connection = connection; + } + + /** + * @return whether users will automatically granted membership in the organization when logging in. + */ + public boolean isAssignMembershipOnLogin() { + return assignMembershipOnLogin; + } + + /** + * Sets whether users will be automatically granted membership in the organization when logging in. + * + * @param assignMembershipOnLogin {@code true} to grant membership in the organization automatically when logging in, {@code false} to require membership to be granted prior to logging with this connection. + */ + public void setAssignMembershipOnLogin(boolean assignMembershipOnLogin) { + this.assignMembershipOnLogin = assignMembershipOnLogin; + } + + /** + * @return the value of the connection ID. + */ + public String getConnectionId() { + return connectionId; + } + + /** + * Sets the connection ID. + * + * @param connectionId the connection ID. + */ + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPage.java b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPage.java new file mode 100644 index 000000000..7410e2e3b --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPage.java @@ -0,0 +1,27 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +/** + * Represents a page of the enabled connections for an organization. + * @see EnabledConnection + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = ConnectionsPageDeserializer.class) +public class EnabledConnectionsPage extends Page { + + public EnabledConnectionsPage(List items) { + super(items); + } + + public EnabledConnectionsPage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Invitation.java b/src/main/java/com/auth0/json/mgmt/organizations/Invitation.java new file mode 100644 index 000000000..7c5560e60 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Invitation.java @@ -0,0 +1,222 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.*; + +import java.util.Date; +import java.util.Map; + +/** + * Represents the Invitation object for an organization. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Invitation { + + @JsonProperty("id") + private String id; + @JsonProperty("inviter") + private Inviter inviter; + @JsonProperty("invitee") + private Invitee invitee; + @JsonProperty("ttl_sec") + private Integer ttlInSeconds; + @JsonProperty("client_id") + private String clientId; + @JsonProperty("connection_id") + private String connectionId; + @JsonProperty("app_metadata") + private Map appMetadata; + @JsonProperty("user_metadata") + private Map userMetadata; + @JsonProperty("send_invitation_email") + private Boolean sendInvitationEmail; + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JsonProperty("created_at") + private Date createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JsonProperty("expires_at") + private Date expiresAt; + @JsonProperty("ticket_id") + private String ticketId; + @JsonProperty("invitation_url") + private String invitationUrl; + @JsonProperty("organization_id") + private String organizationId; + @JsonProperty("roles") + private Roles roles; + + /** + * Create a new instance. + * + * @param inviter the {@linkplain Inviter} of this invitation. + * @param invitee the {@linkplain Invitee} of this invitation. + * @param clientId The id of the connection the invitee will authenticate with.\ + */ + @JsonCreator + public Invitation(@JsonProperty("inviter") Inviter inviter, @JsonProperty("invitee") Invitee invitee, @JsonProperty("client_id") String clientId) { + this.inviter = inviter; + this.invitee = invitee; + this.clientId = clientId; + } + + /** + * @return the ID of this invitation. + */ + public String getId() { + return id; + } + + /** + * @return the {@linkplain Inviter} of this invitation. + */ + public Inviter getInviter() { + return inviter; + } + + /** + * @return the {@linkplain Invitee} of this invitation. + */ + public Invitee getInvitee() { + return invitee; + } + + /** + * @return the number of seconds before this invitation expires. + */ + public Integer getTtlInSeconds() { + return ttlInSeconds; + } + + /** + * Sets the number of seconds before this invitation expires. + * If unspecified or set to 0, this value defaults to 604800 seconds (7 days). Max value: 2592000 seconds (30 days). + * + * @param ttlInSeconds the number of seconds before this invitation expires. + */ + public void setTtlInSeconds(Integer ttlInSeconds) { + this.ttlInSeconds = ttlInSeconds; + } + + /** + * @return the client ID of this invitation. + */ + public String getClientId() { + return clientId; + } + + /** + * @return the connection ID of this invitation. + */ + public String getConnectionId() { + return connectionId; + } + + /** + * Sets the ID of the connection for the inviter to authenticate with. + * + * @param connectionId the ID of the connection. + */ + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } + + /** + * @return the app metadata of this invitation. + */ + public Map getAppMetadata() { + return appMetadata; + } + + /** + * Sets the app metadata associated with this invitation. + * + * @param appMetadata the app metadata. + */ + public void setAppMetadata(Map appMetadata) { + this.appMetadata = appMetadata; + } + + /** + * @return the user metadata of this invitation. + */ + public Map getUserMetadata() { + return userMetadata; + } + + /** + * Sets the user metadata associated with this invitation. + * + * @param userMetadata the user metadata. + */ + public void setUserMetadata(Map userMetadata) { + this.userMetadata = userMetadata; + } + + /** + * @return whether the user will receive an invitation email (true) or no email (false). + */ + public Boolean isSendInvitationEmail() { + return sendInvitationEmail; + } + + /** + * Whether the user will receive an invitation email (true) or no email (false). If not specified, default value is true. + * + * @param sendInvitationEmail whether to send the user an invitation email or not. + */ + public void setSendInvitationEmail(Boolean sendInvitationEmail) { + this.sendInvitationEmail = sendInvitationEmail; + } + + /** + * @return the date this invitation was created at. + */ + public Date getCreatedAt() { + return createdAt; + } + + /** + * @return the date this invitation expires. + */ + public Date getExpiresAt() { + return expiresAt; + } + + /** + * @return the ID of the invitation ticket. + */ + public String getTicketId() { + return ticketId; + } + + /** + * @return the roles associated with the user invited. + */ + public Roles getRoles() { + return roles; + } + + /** + * Sets the roles to be associated with the user invited. + * + * @param roles the {@linkplain Roles} to associated with the user invited. + */ + public void setRoles(Roles roles) { + this.roles = roles; + } + + /** + * @return the invitation url to be send to the invitee. + */ + public String getInvitationUrl() { + return invitationUrl; + } + + /** + * @return the ID of the organization for this invitation. + */ + public String getOrganizationId() { + return organizationId; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPage.java b/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPage.java new file mode 100644 index 000000000..223d7f89f --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPage.java @@ -0,0 +1,27 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +/** + * Represents a page of Invitations. + * @see Invitation + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = InvitationsPageDeserializer.class) +public class InvitationsPage extends Page { + + public InvitationsPage(List items) { + super(items); + } + + public InvitationsPage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPageDeserializer.java b/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPageDeserializer.java new file mode 100644 index 000000000..94408ccdb --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/InvitationsPageDeserializer.java @@ -0,0 +1,25 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.PageDeserializer; + +import java.util.List; + +/** + * Parses a paged response into its {@linkplain InvitationsPage} representation. + */ +public class InvitationsPageDeserializer extends PageDeserializer { + + protected InvitationsPageDeserializer() { + super(Invitation.class, "invitations"); + } + + @Override + protected InvitationsPage createPage(List items) { + return new InvitationsPage(items); + } + + @Override + protected InvitationsPage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new InvitationsPage(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Invitee.java b/src/main/java/com/auth0/json/mgmt/organizations/Invitee.java new file mode 100644 index 000000000..145c43936 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Invitee.java @@ -0,0 +1,34 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the Invitee object for an Invitation. + * @see Invitation + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Invitee { + + @JsonProperty("email") + private String email; + + /** + * Create a new instance. + * + * @param email the email of the Invitee. + */ + public Invitee(@JsonProperty("email") String email) { + this.email = email; + } + + /** + * @return the email of this Invitee. + */ + public String getEmail() { + return email; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Inviter.java b/src/main/java/com/auth0/json/mgmt/organizations/Inviter.java new file mode 100644 index 000000000..fb8091ce9 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Inviter.java @@ -0,0 +1,34 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the Inviter object for an Invitation. + * @see Invitation + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Inviter { + + @JsonProperty("name") + private String name; + + /** + * Create a new instance. + * + * @param name the name of the Inviter. + */ + public Inviter(@JsonProperty("name") String name) { + this.name = name; + } + + /** + * @return the name of this Inviter. + */ + public String getName() { + return name; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Member.java b/src/main/java/com/auth0/json/mgmt/organizations/Member.java new file mode 100644 index 000000000..74a4fbbe4 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Member.java @@ -0,0 +1,78 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the member of an organization. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Member { + + @JsonProperty("user_id") + private String userId; + @JsonProperty("email") + private String email; + @JsonProperty("picture") + private String picture; + @JsonProperty("name") + private String name; + + /** + * @return the user ID of this Member. + */ + public String getUserId() { + return userId; + } + + /** + * @return the user ID of this Member. + */ + public String getEmail() { + return email; + } + + /** + * Sets the email of this Member. + * + * @param email the email of this Member. + */ + public void setEmail(String email) { + this.email = email; + } + + /** + * @return the URL for this Member's picture. + */ + public String getPicture() { + return picture; + } + + /** + * Sets the URL for this Member's picture. + * + * @param picture the URL of this Member's picture. + */ + public void setPicture(String picture) { + this.picture = picture; + } + + /** + * @return the name of this Member. + */ + public String getName() { + return name; + } + + /** + * Sets the name of this Member. + * + * @param name the name of this Member. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Members.java b/src/main/java/com/auth0/json/mgmt/organizations/Members.java new file mode 100644 index 000000000..d5a68bade --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Members.java @@ -0,0 +1,38 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * Represents the request body when adding or deleting members from an organization. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Members { + + @JsonProperty("members") + private List members; + + /** + * Create a new instance. + * + * @param members a list of {@linkplain Member} + */ + @JsonCreator + public Members(@JsonProperty("members") List members) { + this.members = members; + } + + /** + * @return the list of members. + */ + public List getMembers() { + return members; + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/MembersPage.java b/src/main/java/com/auth0/json/mgmt/organizations/MembersPage.java new file mode 100644 index 000000000..e84102dc0 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/MembersPage.java @@ -0,0 +1,26 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +/** + * Represents a page of Members of an organization. + * @see Member + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = MembersPageDeserializer.class) +public class MembersPage extends Page { + public MembersPage(List items) { + super(items); + } + + public MembersPage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/MembersPageDeserializer.java b/src/main/java/com/auth0/json/mgmt/organizations/MembersPageDeserializer.java new file mode 100644 index 000000000..188a49be4 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/MembersPageDeserializer.java @@ -0,0 +1,25 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.PageDeserializer; + +import java.util.List; + +/** + * Parses a paged response into its {@linkplain MembersPage} representation. + */ +public class MembersPageDeserializer extends PageDeserializer { + + protected MembersPageDeserializer() { + super(Member.class, "members"); + } + + @Override + protected MembersPage createPage(List items) { + return new MembersPage(items); + } + + @Override + protected MembersPage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new MembersPage(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Organization.java b/src/main/java/com/auth0/json/mgmt/organizations/Organization.java new file mode 100644 index 000000000..fcf33f653 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Organization.java @@ -0,0 +1,111 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; + +/** + * Represents the organization object. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Organization { + + @JsonProperty("id") + private String id; + @JsonProperty("name") + private String name; + @JsonProperty("display_name") + private String displayName; + @JsonProperty("metadata") + private Map metadata; + @JsonProperty("branding") + private Branding branding; + + public Organization() {} + + /** + * Create a new instance. + * + * @param name the name of this organization. + */ + @JsonCreator + public Organization(@JsonProperty("name") String name) { + this.name = name; + } + + /** + * @return the ID of this organization. + */ + public String getId() { + return id; + } + + /** + * @return the name of this Organization. + */ + public String getName() { + return name; + } + + /** + * Sets the name of this Organization. + * + * @param name the name of the Organization. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the display name of this Organization. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Sets the display name of this Organization. + * + * @param displayName the display name of this Organization. + */ + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + /** + * @return the {@linkplain Branding} of this Organization. + */ + public Branding getBranding() { + return branding; + } + + /** + * Sets the {@linkplain Branding} of this Organization. + * + * @param branding the {@linkplain Branding} of this Organization. + */ + public void setBranding(Branding branding) { + this.branding = branding; + } + + /** + * @return the metadata of this Organization. + */ + public Map getMetadata() { + return metadata; + } + + /** + * Sets the metadata of this Organization. + * + * @param metadata the metadata of this Organization. + */ + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPage.java b/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPage.java new file mode 100644 index 000000000..6ccc9e7a2 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPage.java @@ -0,0 +1,26 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +/** + * Represents a page of an Organization. + * @see Organization + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = OrganizationsPageDeserializer.class) +public class OrganizationsPage extends Page { + public OrganizationsPage(List items) { + super(items); + } + + public OrganizationsPage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPageDeserializer.java b/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPageDeserializer.java new file mode 100644 index 000000000..eb955f4b4 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/OrganizationsPageDeserializer.java @@ -0,0 +1,26 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.mgmt.PageDeserializer; +import com.auth0.json.mgmt.logevents.LogEvent; + +import java.util.List; + +/** + * Parses a paged response into its {@linkplain OrganizationsPage} representation. + */ +public class OrganizationsPageDeserializer extends PageDeserializer { + + protected OrganizationsPageDeserializer() { + super(Organization.class, "organizations"); + } + + @Override + protected OrganizationsPage createPage(List items) { + return new OrganizationsPage(items); + } + + @Override + protected OrganizationsPage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new OrganizationsPage(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/organizations/Roles.java b/src/main/java/com/auth0/json/mgmt/organizations/Roles.java new file mode 100644 index 000000000..2ef99ce8d --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/organizations/Roles.java @@ -0,0 +1,36 @@ +package com.auth0.json.mgmt.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * Represents the request body when adding or deleting roles from a member of an organization. + * @see com.auth0.client.mgmt.OrganizationsEntity + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Roles { + + @JsonProperty("roles") + private List roles; + + /** + * Create a new instance. + * + * @param roles the list of Role IDs to associate with the member. + */ + public Roles(List roles) { + this.roles = roles; + } + + /** + * @return the list of Role IDs associated with the member. + */ + public List getRoles() { + return roles; + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/tickets/PasswordChangeTicket.java b/src/main/java/com/auth0/json/mgmt/tickets/PasswordChangeTicket.java index 53eb205dc..b6ef52d2a 100644 --- a/src/main/java/com/auth0/json/mgmt/tickets/PasswordChangeTicket.java +++ b/src/main/java/com/auth0/json/mgmt/tickets/PasswordChangeTicket.java @@ -30,6 +30,8 @@ public class PasswordChangeTicket { private String ticket; @JsonProperty("mark_email_as_verified") private Boolean markEmailAsVerified; + @JsonProperty("organization_id") + private String orgId; @JsonCreator public PasswordChangeTicket(@JsonProperty("user_id") String userId) { @@ -119,6 +121,26 @@ public void setMarkEmailAsVerified(Boolean markEmailAsVerified){ this.markEmailAsVerified = markEmailAsVerified; } + /** + * Sets the organization ID. This allows the organization_id and organization_name to be included in the redirect URL query. + * + * @param orgId the ID of the organization + */ + @JsonProperty("organization_id") + public void setOrganizationId(String orgId) { + this.orgId = orgId; + } + + /** + * Gets the organization ID + * + * @return the organization ID + */ + @JsonProperty("organization_id") + public String getOrganizationId() { + return orgId; + } + /** * Getter for the ticket url. * diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 037ffcafb..9993f5916 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -94,6 +94,19 @@ public class MockServer { public static final String MULTIPART_SAMPLE = "src/test/resources/mgmt/multipart_sample.json"; public static final String PASSWORDLESS_EMAIL_RESPONSE = "src/test/resources/auth/passwordless_email.json"; public static final String PASSWORDLESS_SMS_RESPONSE = "src/test/resources/auth/passwordless_sms.json"; + public static final String ORGANIZATION = "src/test/resources/mgmt/organization.json"; + public static final String ORGANIZATIONS_LIST = "src/test/resources/mgmt/organizations_list.json"; + public static final String ORGANIZATIONS_PAGED_LIST = "src/test/resources/mgmt/organizations_paged_list.json"; + public static final String ORGANIZATION_MEMBERS_LIST = "src/test/resources/mgmt/organization_members_list.json"; + public static final String ORGANIZATION_MEMBERS_PAGED_LIST = "src/test/resources/mgmt/organization_members_paged_list.json"; + public static final String ORGANIZATION_CONNECTIONS_LIST = "src/test/resources/mgmt/organization_connections_list.json"; + public static final String ORGANIZATION_CONNECTIONS_PAGED_LIST = "src/test/resources/mgmt/organization_connections_paged_list.json"; + public static final String ORGANIZATION_CONNECTION = "src/test/resources/mgmt/organization_connection.json"; + public static final String ORGANIZATION_MEMBER_ROLES_LIST = "src/test/resources/mgmt/organization_member_roles_list.json"; + public static final String ORGANIZATION_MEMBER_ROLES_PAGED_LIST = "src/test/resources/mgmt/organization_member_roles_paged_list.json"; + public static final String INVITATION = "src/test/resources/mgmt/invitation.json"; + public static final String INVITATIONS_LIST = "src/test/resources/mgmt/invitations_list.json"; + public static final String INVITATIONS_PAGED_LIST = "src/test/resources/mgmt/invitations_paged_list.json"; private final MockWebServer server; diff --git a/src/test/java/com/auth0/client/mgmt/JobsEntityTest.java b/src/test/java/com/auth0/client/mgmt/JobsEntityTest.java index 3b96731de..5cd69761c 100644 --- a/src/test/java/com/auth0/client/mgmt/JobsEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/JobsEntityTest.java @@ -233,6 +233,28 @@ public void shouldSendUserVerificationEmailWithIdentity() throws Exception { assertThat(response, is(notNullValue())); } + @Test + public void shouldSendUserVerificationEmailWithOrgId() throws Exception { + Request request = api.jobs().sendVerificationEmail("google-oauth2|1234", "client_abc", null, "org_abc"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_JOB_POST_VERIFICATION_EMAIL, 200); + Job response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/jobs/verification-email")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body.size(), is(3)); + assertThat(body, hasEntry("user_id", "google-oauth2|1234")); + assertThat(body, hasEntry("client_id", "client_abc")); + assertThat(body, hasEntry("organization_id", "org_abc")); + + assertThat(response, is(notNullValue())); + } + @Test public void shouldThrowOnSendUserVerificationEmailWithNullIdentityProvider() { exception.expect(IllegalArgumentException.class); diff --git a/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java new file mode 100644 index 000000000..fa7f80f96 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java @@ -0,0 +1,906 @@ +package com.auth0.client.mgmt; + +import com.auth0.client.MockServer; +import com.auth0.client.mgmt.filter.FieldsFilter; +import com.auth0.client.mgmt.filter.InvitationsFilter; +import com.auth0.client.mgmt.filter.PageFilter; +import com.auth0.json.mgmt.RolesPage; +import com.auth0.json.mgmt.organizations.*; +import com.auth0.net.Request; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.Test; + +import java.util.*; + +import static com.auth0.client.MockServer.*; +import static com.auth0.client.RecordedRequestMatcher.*; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +public class OrganizationEntityTest extends BaseMgmtEntityTest { + + // Organizations entity + + @Test + public void shouldListOrgsWithoutFilter() throws Exception { + Request request = api.organizations().list(null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATIONS_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldListOrgsWithPage() throws Exception { + PageFilter filter = new PageFilter().withPage(2, 30); + Request request = api.organizations().list(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATIONS_PAGED_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "2")); + assertThat(recordedRequest, hasQueryParameter("per_page", "30")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldListOrgsWithTotals() throws Exception { + PageFilter filter = new PageFilter().withTotals(true); + Request request = api.organizations().list(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATIONS_PAGED_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldThrowOnGetOrgWithNullId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().get(null); + } + + @Test + public void shouldGetOrganization() throws Exception { + Request request = api.organizations().get("org_123"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION, 200); + Organization response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnGetOrgWithNullName() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization name"); + api.organizations().getByName(null); + } + + @Test + public void shouldGetOrganizationByName() throws Exception { + Request request = api.organizations().getByName("org-1"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION, 200); + Organization response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/name/org-1")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnCreateOrgWithNullOrg() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization"); + api.organizations().create(null); + } + + @Test + public void shouldCreateOrganization() throws Exception { + Organization orgToCreate = new Organization("test-org"); + orgToCreate.setDisplayName("display name"); + + Colors colors = new Colors(); + colors.setPageBackground("#FF0000"); + colors.setPrimary("#FF0000"); + Branding branding = new Branding(); + branding.setColors(colors); + branding.setLogoUrl("https://some-uri.com"); + orgToCreate.setBranding(branding); + + Map metadata = new HashMap<>(); + metadata.put("key1", "val1"); + orgToCreate.setMetadata(metadata); + + Request request = api.organizations().create(orgToCreate); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION, 200); + Organization response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(4)); + assertThat(body, hasEntry("name", "test-org")); + assertThat(body, hasEntry("display_name", "display name")); + assertThat(body, hasEntry("metadata", metadata)); + assertThat(body, hasEntry(is("branding"), is(notNullValue()))); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnUpdateOrgWithNullOrgId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().update(null, new Organization()); + } + + @Test + public void shouldThrowOnUpdateOrgWithNullOrg() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization"); + api.organizations().update("org_123", null); + } + + @Test + public void shouldUpdateOrganization() throws Exception { + Organization orgToUpdate = new Organization("test-org"); + orgToUpdate.setDisplayName("display name"); + + Colors colors = new Colors(); + colors.setPageBackground("#FF0000"); + colors.setPrimary("#FF0000"); + Branding branding = new Branding(); + branding.setColors(colors); + branding.setLogoUrl("https://some-uri.com"); + orgToUpdate.setBranding(branding); + + Map metadata = new HashMap<>(); + metadata.put("key1", "val1"); + orgToUpdate.setMetadata(metadata); + + Request request = api.organizations().update("org_abc", orgToUpdate); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION, 200); + Organization response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("PATCH", "/api/v2/organizations/org_abc")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(4)); + assertThat(body, hasEntry("name", "test-org")); + assertThat(body, hasEntry("display_name", "display name")); + assertThat(body, hasEntry("metadata", metadata)); + assertThat(body, hasEntry(is("branding"), is(notNullValue()))); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnDeleteOrgWithNullId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().delete(null); + } + + @Test + public void shouldDeleteOrganization() throws Exception { + Request request = api.organizations().delete("org_abc"); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("DELETE", "/api/v2/organizations/org_abc")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + // Organization members entity + + @Test + public void shouldThrowOnGetMembersWithNullId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().getMembers(null, null); + } + + @Test + public void shouldListOrgMembersWithoutFilter() throws Exception { + Request request = api.organizations().getMembers("org_abc", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_MEMBERS_LIST, 200); + MembersPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldListOrgMembersWithPage() throws Exception { + PageFilter filter = new PageFilter().withPage(0, 20); + Request request = api.organizations().getMembers("org_abc", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_MEMBERS_LIST, 200); + MembersPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "0")); + assertThat(recordedRequest, hasQueryParameter("per_page", "20")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldListOrgMembersWithTotals() throws Exception { + PageFilter filter = new PageFilter().withTotals(true); + Request request = api.organizations().getMembers("org_abc", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_MEMBERS_PAGED_LIST, 200); + MembersPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldThrowOnAddMembersWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().addMembers(null, new Members(Collections.singletonList("user1"))); + } + + @Test + public void shouldThrowOnAddMembersWhenMembersIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("members"); + api.organizations().addMembers("org_abc", null); + } + + @Test + public void shouldAddMembersToOrganization() throws Exception { + List membersList = Arrays.asList("user1", "user2"); + Members members = new Members(membersList); + Request request = api.organizations().addMembers("org_abc", members); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/organizations/org_abc/members")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(1)); + assertThat(body, hasEntry("members", membersList)); + } + + @Test + public void shouldThrowOnDeleteMembersWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().deleteMembers(null, new Members(Collections.singletonList("user1"))); + } + + @Test + public void shouldThrowOnDeleteMembersWhenMembersIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("members"); + api.organizations().deleteMembers("org_abc", null); + } + + @Test + public void shouldDeleteMembersFromOrganization() throws Exception { + List membersList = Collections.singletonList("user1"); + Members members = new Members(membersList); + Request request = api.organizations().deleteMembers("org_abc", members); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("DELETE", "/api/v2/organizations/org_abc/members")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(1)); + assertThat(body, hasEntry("members", membersList)); + } + + // Organization connections + + @Test + public void shouldThrowOnGetConnectionsWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().deleteMembers(null, null); + } + + @Test + public void shouldListOrganizationConnectionsWithoutFilter() throws Exception { + Request request = api.organizations().getConnections("org_abc", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_CONNECTIONS_LIST, 200); + EnabledConnectionsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/enabled_connections")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldGetOrganizationConnectionsWithPage() throws Exception { + PageFilter filter = new PageFilter().withPage(2, 30); + Request request = api.organizations().getConnections("org_abc", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_CONNECTIONS_LIST, 200); + EnabledConnectionsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/enabled_connections")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "2")); + assertThat(recordedRequest, hasQueryParameter("per_page", "30")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldGetOrganizationConnectionsWithTotals() throws Exception { + PageFilter filter = new PageFilter().withTotals(true); + Request request = api.organizations().getConnections("org_abc", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MockServer.ORGANIZATION_CONNECTIONS_PAGED_LIST, 200); + EnabledConnectionsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/enabled_connections")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + + @Test + public void shouldThrowOnAddConnectionWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().addConnection(null, new EnabledConnection()); + } + + @Test + public void shouldThrowOnAddConnectionWhenConnectionIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("connection"); + api.organizations().addConnection("org_abc", null); + } + + @Test + public void shouldAddConnection() throws Exception { + EnabledConnection connection = new EnabledConnection(); + connection.setAssignMembershipOnLogin(false); + connection.setConnectionId("con_123"); + + Request request = api.organizations().addConnection("org_abc", connection); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_CONNECTION, 201); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/organizations/org_abc/enabled_connections")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(2)); + assertThat(body, hasEntry("connection_id", "con_123")); + assertThat(body, hasEntry("assign_membership_on_login", false)); + } + + @Test + public void shouldThrowOnDeleteConnectionWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().deleteConnection(null, "con_123"); + } + + @Test + public void shouldThrowOnDeleteConnectionWhenConnectionIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("connection"); + api.organizations().deleteConnection("org_abc", null); + } + + @Test + public void shouldDeleteConnection() throws Exception { + Request request = api.organizations().deleteConnection("org_abc", "con_123"); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("DELETE", "/api/v2/organizations/org_abc/enabled_connections/con_123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + @Test + public void shouldThrowOnUpdateConnectionWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().updateConnection(null, "con_123", new EnabledConnection()); + } + + @Test + public void shouldThrowOnUpdateConnectionWhenUserIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("connection"); + api.organizations().updateConnection("org_abc", null, new EnabledConnection()); + } + + @Test + public void shouldThrowOnUpdateConnectionWhenConnectionIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("connection"); + api.organizations().updateConnection("org_abc", "con_123", null); + } + + @Test + public void shouldUpdateOrgConnection() throws Exception { + EnabledConnection connection = new EnabledConnection(); + connection.setAssignMembershipOnLogin(true); + + Request request = api.organizations().updateConnection("org_abc", "con_123", connection); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_CONNECTION, 201); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("PATCH", "/api/v2/organizations/org_abc/enabled_connections/con_123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(1)); + assertThat(body, hasEntry("assign_membership_on_login", true)); + } + + // Organization roles + + @Test + public void shouldThrowOnGetOrgRolesWhenOrgIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().getRoles(null, "user_123",null); + } + + @Test + public void shouldThrowOnGetOrgRolesWhenUserIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("user ID"); + api.organizations().getRoles("org_abc", null, null); + } + + @Test + public void shouldGetOrgRolesWithoutPaging() throws Exception { + Request request = api.organizations().getRoles("org_abc", "user_123", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_MEMBER_ROLES_LIST, 200); + RolesPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members/user_123/roles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(1)); + } + + @Test + public void shouldGetOrgRolesWithPaging() throws Exception { + Request request = api.organizations().getRoles("org_abc", "user_123", new PageFilter().withPage(0, 20)); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_MEMBER_ROLES_LIST, 200); + RolesPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members/user_123/roles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "0")); + assertThat(recordedRequest, hasQueryParameter("per_page", "20")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(1)); + } + + @Test + public void shouldGetOrgRolesWithIncludeTotals() throws Exception { + Request request = api.organizations().getRoles("org_abc", "user_123", new PageFilter().withTotals(true)); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_MEMBER_ROLES_PAGED_LIST, 200); + RolesPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_abc/members/user_123/roles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(1)); + } + + @Test + public void shouldThrowOnAddOrgRolesWhenOrgIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().addRoles(null, "user_123", new Roles(Collections.singletonList("role_id"))); + } + + @Test + public void shouldThrowOnAddOrgRolesWhenUserIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("user ID"); + api.organizations().addRoles("org_abc", null, new Roles(Collections.singletonList("role_id"))); + } + + @Test + public void shouldThrowOnAddOrgRolesWhenRolesIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("roles"); + api.organizations().addRoles("org_abc", "user_123", null); + } + + @Test + public void shouldAddOrgRoles() throws Exception { + List rolesList = Arrays.asList("role_1", "role_2"); + Request request = api.organizations().addRoles("org_abc", "user_123", new Roles(rolesList)); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/organizations/org_abc/members/user_123/roles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(1)); + assertThat(body, hasEntry("roles", rolesList)); + } + + @Test + public void shouldThrowOnDeleteOrgRolesWhenOrgIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().deleteRoles(null, "user_123", new Roles(Collections.singletonList("role_id"))); + } + + @Test + public void shouldThrowDeleteOrgRolesWhenUserIdIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("user ID"); + api.organizations().deleteRoles("org_abc", null, new Roles(Collections.singletonList("role_id"))); + } + + @Test + public void shouldThrowOnDeleteOrgRolesWhenRolesIsNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("roles"); + api.organizations().deleteRoles("org_abc", "user_123", null); + } + + @Test + public void shouldDeleteOrgRoles() throws Exception { + List rolesList = Arrays.asList("role_1", "role_2"); + Request request = api.organizations().deleteRoles("org_abc", "user_123", new Roles(rolesList)); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("DELETE", "/api/v2/organizations/org_abc/members/user_123/roles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(1)); + assertThat(body, hasEntry("roles", rolesList)); + } + + // Invitations + + @Test + public void shouldThrowOnGetInvitationWithNullOrgId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().getInvitation(null, "invitation_id", null); + } + + @Test + public void shouldThrowOnGetInvitationWithNullInvitationId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("invitation ID"); + api.organizations().getInvitation("org_id", null, null); + } + + @Test + public void shouldGetInvitationWithoutFilter() throws Exception { + Request request = api.organizations().getInvitation("org_123", "invitation_id", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATION, 200); + Invitation response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations/invitation_id")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetInvitationWithFilter() throws Exception { + Request request = api.organizations().getInvitation("org_123", "invitation_id", + new FieldsFilter().withFields("id,invitation_url,invitee", true)); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATION, 200); + Invitation response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations/invitation_id")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("fields", "id,invitation_url,invitee")); + assertThat(recordedRequest, hasQueryParameter("include_fields", "true")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnGetInvitationsWithNullOrgId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().getInvitations(null, null); + } + + @Test + public void shouldGetInvitationsWithoutFilter() throws Exception { + Request request = api.organizations().getInvitations("org_123", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATIONS_LIST, 200); + InvitationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetInvitationsWithFilter() throws Exception { + InvitationsFilter filter = new InvitationsFilter() + .withSort("created_at:1") + .withFields("invitee,inviter,created_at", true); + + Request request = api.organizations().getInvitations("org_123", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATIONS_LIST, 200); + InvitationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("fields", "invitee,inviter,created_at")); + assertThat(recordedRequest, hasQueryParameter("include_fields", "true")); + assertThat(recordedRequest, hasQueryParameter("sort", "created_at:1")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetInvitationsWithPaging() throws Exception { + InvitationsFilter filter = new InvitationsFilter().withPage(0, 20); + + Request request = api.organizations().getInvitations("org_123", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATIONS_LIST, 200); + InvitationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("per_page", "20")); + assertThat(recordedRequest, hasQueryParameter("page", "0")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetInvitationsWithTotals() throws Exception { + InvitationsFilter filter = new InvitationsFilter().withTotals(true); + + Request request = api.organizations().getInvitations("org_123", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATIONS_PAGED_LIST, 200); + InvitationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/invitations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnCreateInvitationWithNullOrgId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().createInvitation(null, null); + } + + @Test + public void shouldThrowOnCreateInvitationWithNullInvitation() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("invitation"); + api.organizations().createInvitation("org_abc", null); + } + + @Test + public void shouldCreateInvitation() throws Exception { + Invitation invitation = new Invitation(new Inviter("name"), new Invitee("name@domain.com"), "con_id"); + invitation.setTtlInSeconds(300); + invitation.setConnectionId("con_id"); + invitation.setSendInvitationEmail(true); + + Request request = api.organizations().createInvitation("org_123", invitation); + + assertThat(request, is(notNullValue())); + + server.jsonResponse(INVITATION, 201); + Invitation response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("POST", "/api/v2/organizations/org_123/invitations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, aMapWithSize(6)); + assertThat(body, hasEntry("send_invitation_email", true)); + assertThat(body, hasEntry("connection_id", "con_id")); + assertThat(body, hasEntry("ttl_sec", 300)); + assertThat(body, hasEntry("inviter", Collections.singletonMap("name", "name"))); + assertThat(body, hasEntry("invitee", Collections.singletonMap("email", "name@domain.com"))); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnDeleteInvitationWithNullOrgId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().deleteInvitation(null, "inv_123"); + } + + @Test + public void shouldThrowOnDeleteInvitationWithNullInvitationId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("invitation ID"); + api.organizations().deleteInvitation("org_abc", null); + } + + @Test + public void shouldDeleteInvitation() throws Exception { + Request request = api.organizations().deleteInvitation("org_abc", "inv_123"); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("DELETE", "/api/v2/organizations/org_abc/invitations/inv_123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } +} diff --git a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java index b4f2d7cca..3e3483b33 100644 --- a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java @@ -1,18 +1,6 @@ package com.auth0.client.mgmt; -import static com.auth0.client.MockServer.MGMT_EMAIL_PROVIDER; -import static com.auth0.client.MockServer.MGMT_EMPTY_LIST; -import static com.auth0.client.MockServer.MGMT_GUARDIAN_ENROLLMENTS_LIST; -import static com.auth0.client.MockServer.MGMT_IDENTITIES_LIST; -import static com.auth0.client.MockServer.MGMT_LOG_EVENTS_LIST; -import static com.auth0.client.MockServer.MGMT_LOG_EVENTS_PAGED_LIST; -import static com.auth0.client.MockServer.MGMT_RECOVERY_CODE; -import static com.auth0.client.MockServer.MGMT_USER; -import static com.auth0.client.MockServer.MGMT_USERS_LIST; -import static com.auth0.client.MockServer.MGMT_USERS_PAGED_LIST; -import static com.auth0.client.MockServer.MGMT_USER_PERMISSIONS_PAGED_LIST; -import static com.auth0.client.MockServer.MGMT_USER_ROLES_PAGED_LIST; -import static com.auth0.client.MockServer.bodyFromRequest; +import static com.auth0.client.MockServer.*; import static com.auth0.client.RecordedRequestMatcher.hasHeader; import static com.auth0.client.RecordedRequestMatcher.hasMethodAndPath; import static com.auth0.client.RecordedRequestMatcher.hasQueryParameter; @@ -36,6 +24,7 @@ import com.auth0.json.mgmt.guardian.Enrollment; import com.auth0.json.mgmt.logevents.LogEvent; import com.auth0.json.mgmt.logevents.LogEventsPage; +import com.auth0.json.mgmt.organizations.OrganizationsPage; import com.auth0.json.mgmt.users.Identity; import com.auth0.json.mgmt.users.RecoveryCode; import com.auth0.json.mgmt.users.User; @@ -993,4 +982,68 @@ public void shouldRemovePermissions() throws Exception { assertThat(response, is(nullValue())); } + + @Test + public void shouldThrowOnGetOrganizationsWithNullUserId() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("user ID"); + api.users().getOrganizations(null, null); + } + + @Test + public void shouldGetUserOrganizationsWithoutFilter() throws Exception { + Request request = api.users().getOrganizations("1", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATIONS_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/users/1/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetUserOrganizationsWithPaging() throws Exception { + Request request = api.users().getOrganizations("1", + new PageFilter().withPage(0, 20)); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATIONS_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/users/1/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "0")); + assertThat(recordedRequest, hasQueryParameter("per_page", "20")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldGetUserOrganizationsWithTotals() throws Exception { + Request request = api.users().getOrganizations("1", + new PageFilter().withTotals(true)); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATIONS_PAGED_LIST, 200); + OrganizationsPage response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/users/1/organizations")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + assertThat(response.getStart(), is(0)); + assertThat(response.getTotal(), is(2)); + assertThat(response.getLimit(), is(20)); + } } diff --git a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java index 1e8f73d86..b46155a1c 100644 --- a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java +++ b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java @@ -15,7 +15,7 @@ public class ClientTest extends JsonTest { private static final String readOnlyJson = "{\"client_id\":\"clientId\",\"is_heroku_app\":true,\"signing_keys\":[{\"cert\":\"ce\",\"pkcs7\":\"pk\",\"subject\":\"su\"}]}"; - private static final String json = "{\"name\":\"name\",\"description\":\"description\",\"client_secret\":\"secret\",\"app_type\":\"type\",\"logo_uri\":\"uri\",\"oidc_conformant\":true,\"is_first_party\":true,\"initiate_login_uri\":\"https://myhome.com/login\",\"callbacks\":[\"value\"],\"allowed_origins\":[\"value\"],\"web_origins\":[\"value\"],\"grant_types\":[\"value\"],\"client_aliases\":[\"value\"],\"allowed_clients\":[\"value\"],\"allowed_logout_urls\":[\"value\"],\"jwt_configuration\":{\"lifetime_in_seconds\":100,\"scopes\":\"openid\",\"alg\":\"alg\"},\"encryption_key\":{\"pub\":\"pub\",\"cert\":\"cert\"},\"sso\":true,\"sso_disabled\":true,\"custom_login_page_on\":true,\"custom_login_page\":\"custom\",\"custom_login_page_preview\":\"preview\",\"form_template\":\"template\",\"addons\":{\"rms\":{},\"mscrm\":{},\"slack\":{},\"layer\":{}},\"token_endpoint_auth_method\":\"method\",\"client_metadata\":{\"key\":\"value\"},\"mobile\":{\"android\":{\"app_package_name\":\"pkg\",\"sha256_cert_fingerprints\":[\"256\"]},\"ios\":{\"team_id\":\"team\",\"app_bundle_identifier\":\"id\"}},\"refresh_token\":{\"rotation_type\":\"non-rotating\"}}"; + private static final String json = "{\"name\":\"name\",\"description\":\"description\",\"client_secret\":\"secret\",\"app_type\":\"type\",\"logo_uri\":\"uri\",\"oidc_conformant\":true,\"is_first_party\":true,\"initiate_login_uri\":\"https://myhome.com/login\",\"callbacks\":[\"value\"],\"allowed_origins\":[\"value\"],\"web_origins\":[\"value\"],\"grant_types\":[\"value\"],\"client_aliases\":[\"value\"],\"allowed_clients\":[\"value\"],\"allowed_logout_urls\":[\"value\"],\"organization_usage\":\"allow\",\"organization_require_behavior\":\"no_prompt\",\"jwt_configuration\":{\"lifetime_in_seconds\":100,\"scopes\":\"openid\",\"alg\":\"alg\"},\"encryption_key\":{\"pub\":\"pub\",\"cert\":\"cert\"},\"sso\":true,\"sso_disabled\":true,\"custom_login_page_on\":true,\"custom_login_page\":\"custom\",\"custom_login_page_preview\":\"preview\",\"form_template\":\"template\",\"addons\":{\"rms\":{},\"mscrm\":{},\"slack\":{},\"layer\":{}},\"token_endpoint_auth_method\":\"method\",\"client_metadata\":{\"key\":\"value\"},\"mobile\":{\"android\":{\"app_package_name\":\"pkg\",\"sha256_cert_fingerprints\":[\"256\"]},\"ios\":{\"team_id\":\"team\",\"app_bundle_identifier\":\"id\"}},\"refresh_token\":{\"rotation_type\":\"non-rotating\"}}"; @Test public void shouldSerialize() throws Exception { @@ -56,6 +56,8 @@ public void shouldSerialize() throws Exception { client.setMobile(mobile); RefreshToken refreshToken = new RefreshToken(); client.setRefreshToken(refreshToken); + client.setOrganizationUsage("require"); + client.setOrganizationRequireBehavior("pre_login_prompt"); String serialized = toJSON(client); assertThat(serialized, is(notNullValue())); @@ -87,6 +89,8 @@ public void shouldSerialize() throws Exception { assertThat(serialized, JsonMatcher.hasEntry("client_metadata", notNullValue())); assertThat(serialized, JsonMatcher.hasEntry("mobile", notNullValue())); assertThat(serialized, JsonMatcher.hasEntry("refresh_token", notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("organization_usage", "require")); + assertThat(serialized, JsonMatcher.hasEntry("organization_require_behavior", "pre_login_prompt")); } @Test @@ -128,6 +132,8 @@ public void shouldDeserialize() throws Exception { assertThat(client.getClientMetadata(), IsMapContaining.hasEntry("key", "value")); assertThat(client.getMobile(), is(notNullValue())); assertThat(client.getRefreshToken(), is(notNullValue())); + assertThat(client.getOrganizationUsage(), is("allow")); + assertThat(client.getOrganizationRequireBehavior(), is("no_prompt")); } @Test diff --git a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java new file mode 100644 index 000000000..ad3c92524 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java @@ -0,0 +1,79 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonTest; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class EnabledConnectionsPageTest extends JsonTest { + + private static String jsonWithoutTotals = "[\n" + + " {\n" + + " \"connection_id\": \"con_1\",\n" + + " \"assign_membership_on_login\": false,\n" + + " \"connection\": {\n" + + " \"name\": \"google-oauth2\",\n" + + " \"strategy\": \"google-oauth2\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"connection_id\": \"con_2\",\n" + + " \"assign_membership_on_login\": true,\n" + + " \"connection\": {\n" + + " \"name\": \"Username-Password-Authentication\",\n" + + " \"strategy\": \"auth0\"\n" + + " }\n" + + " }\n" + + "]"; + + private static String jsonWithTotals = "{\n" + + " \"enabled_connections\": [\n" + + " {\n" + + " \"connection_id\": \"con_1\",\n" + + " \"assign_membership_on_login\": false,\n" + + " \"connection\": {\n" + + " \"name\": \"google-oauth2\",\n" + + " \"strategy\": \"google-oauth2\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"connection_id\": \"con_2\",\n" + + " \"assign_membership_on_login\": true,\n" + + " \"connection\": {\n" + + " \"name\": \"Username-Password-Authentication\",\n" + + " \"strategy\": \"auth0\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"start\": 0,\n" + + " \"limit\": 2,\n" + + " \"total\": 2\n" + + "}"; + + @Test + public void shouldDeserializeWithoutTotals() throws Exception { + EnabledConnectionsPage page = fromJSON(jsonWithoutTotals, EnabledConnectionsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(nullValue())); + assertThat(page.getLength(), is(nullValue())); + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getLimit(), is(nullValue())); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + EnabledConnectionsPage page = fromJSON(jsonWithTotals, EnabledConnectionsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getTotal(), is(2)); + assertThat(page.getLimit(), is(2)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java new file mode 100644 index 000000000..e45d085b7 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java @@ -0,0 +1,55 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class EnabledConnectionsTest extends JsonTest { + + @Test + public void shouldSerialize() throws Exception { + Connection connection = new Connection(); + connection.setName("con_1"); + connection.setStrategy("strategy"); + + EnabledConnection enabledConnection = new EnabledConnection(); + enabledConnection.setAssignMembershipOnLogin(true); + enabledConnection.setConnection(connection); + + String serialized = toJSON(enabledConnection); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("assign_membership_on_login", true)); + assertThat(serialized, JsonMatcher.hasEntry("connection", is(notNullValue()))); + + Map connectionMap = new HashMap<>(); + connectionMap.put("name", "con_1"); + connectionMap.put("strategy", "strategy"); + assertThat(serialized, JsonMatcher.hasEntry("connection", connectionMap)); + } + + @Test + public void shouldDeserialize() throws Exception { + String json = "{\n" + + " \"connection_id\": \"con_id\",\n" + + " \"assign_membership_on_login\": false,\n" + + " \"connection\": {\n" + + " \"name\": \"google-oauth2\",\n" + + " \"strategy\": \"google-oauth2\"\n" + + " }\n" + + " }"; + + EnabledConnection enabledConnection = fromJSON(json, EnabledConnection.class); + assertThat(enabledConnection, is(notNullValue())); + assertThat(enabledConnection.getConnectionId(), is("con_id")); + assertThat(enabledConnection.isAssignMembershipOnLogin(), is(false)); + assertThat(enabledConnection.getConnection(), is(notNullValue())); + assertThat(enabledConnection.getConnection().getName(), is("google-oauth2")); + assertThat(enabledConnection.getConnection().getStrategy(), is("google-oauth2")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/InvitationTest.java b/src/test/java/com/auth0/json/mgmt/organizations/InvitationTest.java new file mode 100644 index 000000000..a5fc65bef --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/InvitationTest.java @@ -0,0 +1,79 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class InvitationTest extends JsonTest { + + @Test + public void shouldDeserialize() throws Exception { + String json = "{\n" + + " \"id\": \"inv_1\",\n" + + " \"client_id\": \"client-id\",\n" + + " \"inviter\": {\n" + + " \"name\": \"timmy\"\n" + + " },\n" + + " \"invitee\": {\n" + + " \"email\": \"timmy@domain.com\"\n" + + " },\n" + + " \"invitation_url\": \"https://somedomain.com\",\n" + + " \"ticket_id\": \"ticket-id\",\n" + + " \"created_at\": \"2021-03-31T19:08:40.295Z\",\n" + + " \"expires_at\": \"2021-04-07T19:08:40.295Z\",\n" + + " \"organization_id\": \"org_abc\"\n" + + "}\n"; + + Invitation invitation = fromJSON(json, Invitation.class); + + assertThat(invitation, is(notNullValue())); + assertThat(invitation.getId(), is("inv_1")); + assertThat(invitation.getClientId(), is("client-id")); + assertThat(invitation.getInviter(), is(notNullValue())); + assertThat(invitation.getInviter().getName(), is("timmy")); + assertThat(invitation.getInvitee(), is(notNullValue())); + assertThat(invitation.getInvitee().getEmail(), is("timmy@domain.com")); + assertThat(invitation.getInvitationUrl(), is("https://somedomain.com")); + assertThat(invitation.getTicketId(), is("ticket-id")); + assertThat(invitation.getCreatedAt(), is(parseJSONDate("2021-03-31T19:08:40.295Z"))); + assertThat(invitation.getExpiresAt(), is(parseJSONDate("2021-04-07T19:08:40.295Z"))); + assertThat(invitation.getOrganizationId(), is("org_abc")); + } + + @Test + public void shouldSerialize() throws Exception { + Map appMetadata = Collections.singletonMap("app1", "val1"); + Map userMetadata = Collections.singletonMap("user1", "val1"); + List rolesList = Arrays.asList("role-1", "role-2"); + + Invitation invitation = new Invitation(new Inviter("name"), new Invitee("joe@domain.com"), "client-id"); + invitation.setSendInvitationEmail(true); + invitation.setAppMetadata(appMetadata); + invitation.setUserMetadata(userMetadata); + invitation.setConnectionId("connId"); + invitation.setRoles(new Roles(rolesList)); + invitation.setTtlInSeconds(41); + + String serialized = toJSON(invitation); + + assertThat(serialized, is(notNullValue())); + System.out.println(serialized); + assertThat(serialized, JsonMatcher.hasEntry("client_id", "client-id")); + assertThat(serialized, JsonMatcher.hasEntry("ttl_sec", 41)); + assertThat(serialized, JsonMatcher.hasEntry("connection_id", "connId")); + assertThat(serialized, JsonMatcher.hasEntry("send_invitation_email", true)); + assertThat(serialized, JsonMatcher.hasEntry("roles", rolesList)); + assertThat(serialized, JsonMatcher.hasEntry("app_metadata", appMetadata)); + assertThat(serialized, JsonMatcher.hasEntry("user_metadata", userMetadata)); + assertThat(serialized, JsonMatcher.hasEntry("inviter", is(notNullValue()))); + assertThat(serialized, JsonMatcher.hasEntry("invitee", is(notNullValue()))); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/InvitationsPageTest.java b/src/test/java/com/auth0/json/mgmt/organizations/InvitationsPageTest.java new file mode 100644 index 000000000..ccb8534a0 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/InvitationsPageTest.java @@ -0,0 +1,109 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonTest; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; + +public class InvitationsPageTest extends JsonTest { + + private static final String jsonWithoutTotals = "[\n" + + " {\n" + + " \"id\": \"uinv_Q3lgZ0a99aY7Rqs3\",\n" + + " \"client_id\": \"klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb\",\n" + + " \"inviter\": {\n" + + " \"name\": \"dave!\"\n" + + " },\n" + + " \"invitee\": {\n" + + " \"email\": \"dave@domain.com\"\n" + + " },\n" + + " \"invitation_url\": \"https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org\",\n" + + " \"ticket_id\": \"U0o1uoXAl1VPkKbZla0a833soMUMOo1E\",\n" + + " \"created_at\": \"2021-03-31T19:08:40.295Z\",\n" + + " \"expires_at\": \"2021-04-07T19:08:40.295Z\",\n" + + " \"organization_id\": \"org_W30s833MRbjhHuWK\"\n" + + " },\n" + + " {\n" + + " \"id\": \"uinv_Q3lgZ0a99aY7Rqs3\",\n" + + " \"client_id\": \"klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb\",\n" + + " \"inviter\": {\n" + + " \"name\": \"jim.anderson@auth0.com\"\n" + + " },\n" + + " \"invitee\": {\n" + + " \"email\": \"jim.anderson+android@auth0.com\"\n" + + " },\n" + + " \"app_metadata\": {},\n" + + " \"user_metadata\": {},\n" + + " \"invitation_url\": \"https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org\",\n" + + " \"ticket_id\": \"U0o1uoXAl1VPkK0a940a833soMUMOo1E\",\n" + + " \"created_at\": \"2021-03-31T17:59:23.132Z\",\n" + + " \"expires_at\": \"2021-04-07T17:59:23.132Z\",\n" + + " \"organization_id\": \"org_W30s833MRbjhHuWK\"\n" + + " }\n" + + "]\n"; + + private static final String jsonWithTotals = "{\n" + + " \"invitations\": [\n" + + " {\n" + + " \"id\": \"uinv_Q3lgZ0a99aY7Rqs3\",\n" + + " \"client_id\": \"klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb\",\n" + + " \"inviter\": {\n" + + " \"name\": \"dave!\"\n" + + " },\n" + + " \"invitee\": {\n" + + " \"email\": \"dave@domain.com\"\n" + + " },\n" + + " \"invitation_url\": \"https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org\",\n" + + " \"ticket_id\": \"U0o1uoXAl1VPkKbZla0a833soMUMOo1E\",\n" + + " \"created_at\": \"2021-03-31T19:08:40.295Z\",\n" + + " \"expires_at\": \"2021-04-07T19:08:40.295Z\",\n" + + " \"organization_id\": \"org_W30s833MRbjhHuWK\"\n" + + " },\n" + + " {\n" + + " \"id\": \"uinv_Q3lgZ0a99aY7Rqs3\",\n" + + " \"client_id\": \"klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb\",\n" + + " \"inviter\": {\n" + + " \"name\": \"jim.anderson@auth0.com\"\n" + + " },\n" + + " \"invitee\": {\n" + + " \"email\": \"jim.anderson+android@auth0.com\"\n" + + " },\n" + + " \"app_metadata\": {},\n" + + " \"user_metadata\": {},\n" + + " \"invitation_url\": \"https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org\",\n" + + " \"ticket_id\": \"U0o1uoXAl1VPkK0a940a833soMUMOo1E\",\n" + + " \"created_at\": \"2021-03-31T17:59:23.132Z\",\n" + + " \"expires_at\": \"2021-04-07T17:59:23.132Z\",\n" + + " \"organization_id\": \"org_W30s833MRbjhHuWK\"\n" + + " }\n" + + " ],\n" + + " \"start\": 0,\n" + + " \"limit\": 4\n" + + "}\n"; + + @Test + public void shouldDeserializeWithoutTotals() throws Exception { + InvitationsPage page = fromJSON(jsonWithoutTotals, InvitationsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(nullValue())); + assertThat(page.getLength(), is(nullValue())); + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getLimit(), is(nullValue())); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + InvitationsPage page = fromJSON(jsonWithTotals, InvitationsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getLimit(), is(4)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/MembersPageTest.java b/src/test/java/com/auth0/json/mgmt/organizations/MembersPageTest.java new file mode 100644 index 000000000..e2599536f --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/MembersPageTest.java @@ -0,0 +1,72 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonTest; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class MembersPageTest extends JsonTest { + private static final String jsonWithoutTotals = "[\n" + + " {\n" + + " \"user_id\": \"auth0|605a1f57cbeb2c0070fdf123\",\n" + + " \"email\": \"dave@domain.com\",\n" + + " \"picture\": \"https://domain.com/img.png\",\n" + + " \"name\": \"dave\"\n" + + " },\n" + + " {\n" + + " \"user_id\": \"auth0|605a0fc1bef67f006851a123\",\n" + + " \"email\": \"eric@domain.com\",\n" + + " \"picture\": \"https://domain.com/img.png\",\n" + + " \"name\": \"eric\"\n" + + " }\n" + + "]\n"; + + private static final String jsonWithTotals = "{\n" + + " \"members\": [\n" + + " {\n" + + " \"user_id\": \"auth0|605a1f57cbeb2c0070fdf123\",\n" + + " \"email\": \"dave@domain.com\",\n" + + " \"picture\": \"https://domain.com/img.png\",\n" + + " \"name\": \"dave\"\n" + + " },\n" + + " {\n" + + " \"user_id\": \"auth0|605a0fc1bef67f006851a123\",\n" + + " \"email\": \"eric@domain.com\",\n" + + " \"picture\": \"https://domain.com/img.png\",\n" + + " \"name\": \"eric\"\n" + + " }\n" + + " ],\n" + + " \"start\": 0,\n" + + " \"limit\": 20,\n" + + " \"total\": 2\n" + + "}\n"; + + + @Test + public void shouldDeserializeWithoutTotals() throws Exception { + MembersPage page = fromJSON(jsonWithoutTotals, MembersPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(nullValue())); + assertThat(page.getLength(), is(nullValue())); + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getLimit(), is(nullValue())); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + MembersPage page = fromJSON(jsonWithTotals, MembersPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getTotal(), is(2)); + assertThat(page.getLimit(), is(20)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } +} + diff --git a/src/test/java/com/auth0/json/mgmt/organizations/MembersTest.java b/src/test/java/com/auth0/json/mgmt/organizations/MembersTest.java new file mode 100644 index 000000000..7ae6f8807 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/MembersTest.java @@ -0,0 +1,43 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class MembersTest extends JsonTest { + + @Test + public void shouldSerialize() throws Exception { + Member member = new Member(); + member.setEmail("email@domain.com"); + member.setName("name"); + member.setPicture("https://myprofilepic.com"); + + String serialized = toJSON(member); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("email", "email@domain.com")); + assertThat(serialized, JsonMatcher.hasEntry("name", "name")); + assertThat(serialized, JsonMatcher.hasEntry("picture", "https://myprofilepic.com")); + } + + @Test + public void shouldDeserialize() throws Exception { + String memberJson = "{\n" + + " \"user_id\": \"user_123\",\n" + + " \"email\": \"fred@domain.com\",\n" + + " \"picture\": \"https://profilepic.com/mypic.png\",\n" + + " \"name\": \"fred\"\n" + + "}"; + + Member member = fromJSON(memberJson, Member.class); + assertThat(member, is(notNullValue())); + assertThat(member.getUserId(), is("user_123")); + assertThat(member.getEmail(), is("fred@domain.com")); + assertThat(member.getPicture(), is("https://profilepic.com/mypic.png")); + assertThat(member.getName(), is("fred")); + + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsPageTest.java b/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsPageTest.java new file mode 100644 index 000000000..a05335d2f --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsPageTest.java @@ -0,0 +1,87 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonTest; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; + +public class OrganizationsPageTest extends JsonTest { + + private static final String jsonWithoutTotals = "[\n" + + " {\n" + + " \"id\": \"org_1\",\n" + + " \"name\": \"org-1\",\n" + + " \"display_name\": \"org 1\",\n" + + " \"branding\": {\n" + + " \"logo_url\": \"https://some-url.com/\",\n" + + " \"colors\": {\n" + + " \"primary\": \"#FF0000\",\n" + + " \"page_background\": \"#FF0000\"\n" + + " }\n" + + " },\n" + + " \"metadata\": {\n" + + " \"key1\": \"val1\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": \"org_2\",\n" + + " \"name\": \"org-2\",\n" + + " \"display_name\": \"org 2\"\n" + + " }\n" + + "]"; + + private static final String jsonWithTotals = "{\n" + + " \"organizations\": [\n" + + " {\n" + + " \"id\": \"org_2\",\n" + + " \"name\": \"org-1\",\n" + + " \"display_name\": \"org 1\",\n" + + " \"branding\": {\n" + + " \"logo_url\": \"https://some-url.com/\",\n" + + " \"colors\": {\n" + + " \"primary\": \"#FF0000\",\n" + + " \"page_background\": \"#FF0000\"\n" + + " }\n" + + " },\n" + + " \"metadata\": {\n" + + " \"key1\": \"val1\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": \"org_2\",\n" + + " \"name\": \"org-2\",\n" + + " \"display_name\": \"org 2\"\n" + + " }\n" + + " ],\n" + + " \"start\": 0,\n" + + " \"limit\": 20,\n" + + " \"total\": 2\n" + + "}"; + + @Test + public void shouldDeserializeWithoutTotals() throws Exception { + OrganizationsPage page = fromJSON(jsonWithoutTotals, OrganizationsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(nullValue())); + assertThat(page.getLength(), is(nullValue())); + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getLimit(), is(nullValue())); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + OrganizationsPage page = fromJSON(jsonWithTotals, OrganizationsPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getTotal(), is(2)); + assertThat(page.getLimit(), is(20)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsTest.java b/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsTest.java new file mode 100644 index 000000000..8f3936061 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/organizations/OrganizationsTest.java @@ -0,0 +1,70 @@ +package com.auth0.json.mgmt.organizations; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.Test; + +import java.util.Collections; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class OrganizationsTest extends JsonTest { + + @Test + public void shouldDeserialize() throws Exception { + String orgJson = "{\n" + + " \"id\": \"org_abc\",\n" + + " \"name\": \"org-name\",\n" + + " \"display_name\": \"display name\",\n" + + " \"branding\": {\n" + + " \"logo_url\": \"https://some-url.com/\",\n" + + " \"colors\": {\n" + + " \"primary\": \"#FF0000\",\n" + + " \"page_background\": \"#FF0000\"\n" + + " }\n" + + " },\n" + + " \"metadata\": {\n" + + " \"key1\": \"val1\"\n" + + " }\n" + + " }"; + + Organization org = fromJSON(orgJson, Organization.class); + assertThat(org, is(notNullValue())); + assertThat(org.getId(), is("org_abc")); + assertThat(org.getName(), is("org-name")); + assertThat(org.getDisplayName(), is("display name")); + assertThat(org.getBranding(), is(notNullValue())); + assertThat(org.getBranding().getLogoUrl(), is("https://some-url.com/")); + assertThat(org.getBranding().getColors(), is(notNullValue())); + assertThat(org.getBranding().getColors().getPrimary(), is("#FF0000")); + assertThat(org.getBranding().getColors().getPageBackground(), is("#FF0000")); + assertThat(org.getMetadata(), is(notNullValue())); + assertThat(org.getMetadata().get("key1"), is("val1")); + } + + @Test + public void shouldSerialize() throws Exception { + Colors colors = new Colors(); + colors.setPrimary("#FF0000"); + colors.setPageBackground("#DD0000"); + + Branding branding = new Branding(); + branding.setLogoUrl("https://some-url.com"); + branding.setColors(colors); + + Map metadata = Collections.singletonMap("key1", "val1"); + Organization organization = new Organization("org-name"); + organization.setDisplayName("display name"); + organization.setBranding(branding); + organization.setMetadata(metadata); + + String serialized = toJSON(organization); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("name", "org-name")); + assertThat(serialized, JsonMatcher.hasEntry("display_name", "display name")); + assertThat(serialized, JsonMatcher.hasEntry("metadata", metadata)); + assertThat(serialized, JsonMatcher.hasEntry("branding", is(notNullValue()))); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/tickets/PasswordChangeTicketTest.java b/src/test/java/com/auth0/json/mgmt/tickets/PasswordChangeTicketTest.java index 348c4e81b..024ab1b89 100644 --- a/src/test/java/com/auth0/json/mgmt/tickets/PasswordChangeTicketTest.java +++ b/src/test/java/com/auth0/json/mgmt/tickets/PasswordChangeTicketTest.java @@ -22,6 +22,7 @@ public void shouldSerialize() throws Exception { ticket.setEmail("me@auth0.com"); ticket.setNewPassword("pass123"); ticket.setMarkEmailAsVerified(true); + ticket.setOrganizationId("org_abc"); String serialized = toJSON(ticket); assertThat(serialized, is(notNullValue())); @@ -32,6 +33,7 @@ public void shouldSerialize() throws Exception { assertThat(serialized, JsonMatcher.hasEntry("connection_id", "12")); assertThat(serialized, JsonMatcher.hasEntry("email", "me@auth0.com")); assertThat(serialized, JsonMatcher.hasEntry("mark_email_as_verified", true)); + assertThat(serialized, JsonMatcher.hasEntry("organization_id", "org_abc")); } @SuppressWarnings("deprecation") diff --git a/src/test/resources/mgmt/invitation.json b/src/test/resources/mgmt/invitation.json new file mode 100644 index 000000000..01ccff852 --- /dev/null +++ b/src/test/resources/mgmt/invitation.json @@ -0,0 +1,15 @@ +{ + "id": "uinv_Q3lgZXkis997Rqs3", + "client_id": "klCnbSD1U1YAIeLRdvEAFMwDoOX5bfsb", + "inviter": { + "name": "timmy" + }, + "invitee": { + "email": "timmy@domain.com" + }, + "invitation_url": "https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org", + "ticket_id": "U0o1uoXAl1VPkKbZla0a833soMUMOo1E", + "created_at": "2021-03-31T19:08:40.295Z", + "expires_at": "2021-04-07T19:08:40.295Z", + "organization_id": "org_W30s833MRbjhHuWK" +} diff --git a/src/test/resources/mgmt/invitations_list.json b/src/test/resources/mgmt/invitations_list.json new file mode 100644 index 000000000..f36767fce --- /dev/null +++ b/src/test/resources/mgmt/invitations_list.json @@ -0,0 +1,34 @@ +[ + { + "id": "uinv_Q3lgZ0a99aY7Rqs3", + "client_id": "klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb", + "inviter": { + "name": "dave!" + }, + "invitee": { + "email": "dave@domain.com" + }, + "invitation_url": "https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org", + "ticket_id": "U0o1uoXAl1VPkKbZla0a833soMUMOo1E", + "created_at": "2021-03-31T19:08:40.295Z", + "expires_at": "2021-04-07T19:08:40.295Z", + "organization_id": "org_W30s833MRbjhHuWK" + }, + { + "id": "uinv_Q3lgZ0a99aY7Rqs3", + "client_id": "klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb", + "inviter": { + "name": "jim.anderson@auth0.com" + }, + "invitee": { + "email": "jim.anderson+android@auth0.com" + }, + "app_metadata": {}, + "user_metadata": {}, + "invitation_url": "https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org", + "ticket_id": "U0o1uoXAl1VPkK0a940a833soMUMOo1E", + "created_at": "2021-03-31T17:59:23.132Z", + "expires_at": "2021-04-07T17:59:23.132Z", + "organization_id": "org_W30s833MRbjhHuWK" + } +] diff --git a/src/test/resources/mgmt/invitations_paged_list.json b/src/test/resources/mgmt/invitations_paged_list.json new file mode 100644 index 000000000..c17c7fe10 --- /dev/null +++ b/src/test/resources/mgmt/invitations_paged_list.json @@ -0,0 +1,38 @@ +{ + "invitations": [ + { + "id": "uinv_Q3lgZ0a99aY7Rqs3", + "client_id": "klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb", + "inviter": { + "name": "dave!" + }, + "invitee": { + "email": "dave@domain.com" + }, + "invitation_url": "https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org", + "ticket_id": "U0o1uoXAl1VPkKbZla0a833soMUMOo1E", + "created_at": "2021-03-31T19:08:40.295Z", + "expires_at": "2021-04-07T19:08:40.295Z", + "organization_id": "org_W30s833MRbjhHuWK" + }, + { + "id": "uinv_Q3lgZ0a99aY7Rqs3", + "client_id": "klCnbSD1U1Yd0333dvEAFMwDoOX5bfsb", + "inviter": { + "name": "jim.anderson@auth0.com" + }, + "invitee": { + "email": "jim.anderson+android@auth0.com" + }, + "app_metadata": {}, + "user_metadata": {}, + "invitation_url": "https://some-domain.auth0.com/login?invitation=U0o1uoXAl1VPkKbZlaRWEWJadkeed1E&organization=org_W3OHp07dfbjhHuWK&organization_name=timmy-org", + "ticket_id": "U0o1uoXAl1VPkK0a940a833soMUMOo1E", + "created_at": "2021-03-31T17:59:23.132Z", + "expires_at": "2021-04-07T17:59:23.132Z", + "organization_id": "org_W30s833MRbjhHuWK" + } + ], + "start": 0, + "limit": 4 +} diff --git a/src/test/resources/mgmt/organization.json b/src/test/resources/mgmt/organization.json new file mode 100644 index 000000000..0a3e0e87e --- /dev/null +++ b/src/test/resources/mgmt/organization.json @@ -0,0 +1,15 @@ +{ + "id": "org_VSZmSnzd0m9ITBZ7", + "name": "org-1", + "display_name": "org 1", + "branding": { + "logo_uri": "https://some-url.com/", + "colors": { + "primary": "#FF0000", + "page_background": "#FF0000" + } + }, + "metadata": { + "key1": "val1" + } +} diff --git a/src/test/resources/mgmt/organization_connection.json b/src/test/resources/mgmt/organization_connection.json new file mode 100644 index 000000000..fc1c51418 --- /dev/null +++ b/src/test/resources/mgmt/organization_connection.json @@ -0,0 +1,4 @@ +{ + "connection_id": "con_At4BWXhV3lKv82jd", + "assign_membership_on_login": false +} diff --git a/src/test/resources/mgmt/organization_connections_list.json b/src/test/resources/mgmt/organization_connections_list.json new file mode 100644 index 000000000..9c602251b --- /dev/null +++ b/src/test/resources/mgmt/organization_connections_list.json @@ -0,0 +1,18 @@ +[ + { + "connection_id": "con_At4BWXhV3lKv82jd", + "assign_membership_on_login": false, + "connection": { + "name": "google-oauth2", + "strategy": "google-oauth2" + } + }, + { + "connection_id": "con_kai93HmEDCs8ai3d", + "assign_membership_on_login": true, + "connection": { + "name": "Username-Password-Authentication", + "strategy": "auth0" + } + } +] diff --git a/src/test/resources/mgmt/organization_connections_paged_list.json b/src/test/resources/mgmt/organization_connections_paged_list.json new file mode 100644 index 000000000..4772fe118 --- /dev/null +++ b/src/test/resources/mgmt/organization_connections_paged_list.json @@ -0,0 +1,23 @@ +{ + "enabled_connections": [ + { + "connection_id": "con_At4BWXhV3lKv82jd", + "assign_membership_on_login": false, + "connection": { + "name": "google-oauth2", + "strategy": "google-oauth2" + } + }, + { + "connection_id": "con_kai93HmEDCs8ai3d", + "assign_membership_on_login": true, + "connection": { + "name": "Username-Password-Authentication", + "strategy": "auth0" + } + } + ], + "start": 0, + "limit": 20, + "total": 2 +} diff --git a/src/test/resources/mgmt/organization_member_roles_list.json b/src/test/resources/mgmt/organization_member_roles_list.json new file mode 100644 index 000000000..0cd341389 --- /dev/null +++ b/src/test/resources/mgmt/organization_member_roles_list.json @@ -0,0 +1,7 @@ +[ + { + "id": "rol_YMmM7zN6kqtus91", + "name": "test role", + "description": "role for testing" + } +] diff --git a/src/test/resources/mgmt/organization_member_roles_paged_list.json b/src/test/resources/mgmt/organization_member_roles_paged_list.json new file mode 100644 index 000000000..e86eee8a5 --- /dev/null +++ b/src/test/resources/mgmt/organization_member_roles_paged_list.json @@ -0,0 +1,12 @@ +{ + "roles": [ + { + "id": "rol_YMmM7zN6kqtus91", + "name": "test role", + "description": "role for testing" + } + ], + "start": 0, + "limit": 50, + "total": 1 +} diff --git a/src/test/resources/mgmt/organization_members_list.json b/src/test/resources/mgmt/organization_members_list.json new file mode 100644 index 000000000..817b2063d --- /dev/null +++ b/src/test/resources/mgmt/organization_members_list.json @@ -0,0 +1,20 @@ +[ + { + "user_id": "auth0|605a1f57cbeb2c0070fdf123", + "email": "dave@domain.com", + "picture": "https://domain.com/img.png", + "name": "dave" + }, + { + "user_id": "auth0|605a0fc1bef67f006851a123", + "email": "eric@domain.com", + "picture": "https://domain.com/img.png", + "name": "eric" + }, + { + "user_id": "auth0|5f5103d20e634f006d25a123", + "email": "john@domain.com", + "picture": "https://domain.com/img.png", + "name": "john" + } +] diff --git a/src/test/resources/mgmt/organization_members_paged_list.json b/src/test/resources/mgmt/organization_members_paged_list.json new file mode 100644 index 000000000..c3aefa9c1 --- /dev/null +++ b/src/test/resources/mgmt/organization_members_paged_list.json @@ -0,0 +1,25 @@ +{ + "members": [ + { + "user_id": "auth0|605a1f57cbeb2c0070fdf123", + "email": "dave@domain.com", + "picture": "https://domain.com/img.png", + "name": "dave" + }, + { + "user_id": "auth0|605a0fc1bef67f006851a123", + "email": "eric@domain.com", + "picture": "https://domain.com/img.png", + "name": "eric" + }, + { + "user_id": "auth0|5f5103d20e634f006d25a123", + "email": "john@domain.com", + "picture": "https://domain.com/img.png", + "name": "john" + } + ], + "start": 0, + "limit": 20, + "total": 3 +} diff --git a/src/test/resources/mgmt/organizations_list.json b/src/test/resources/mgmt/organizations_list.json new file mode 100644 index 000000000..504f7fd21 --- /dev/null +++ b/src/test/resources/mgmt/organizations_list.json @@ -0,0 +1,22 @@ +[ + { + "id": "org_VSZmSnzd0m9ITBZ7", + "name": "org-1", + "display_name": "org 1", + "branding": { + "logo_uri": "https://some-url.com/", + "colors": { + "primary": "#FF0000", + "page_background": "#FF0000" + } + }, + "metadata": { + "key1": "val1" + } + }, + { + "id": "org_W3OH9wtMRbjhHuWK", + "name": "org-2", + "display_name": "org 2" + } +] diff --git a/src/test/resources/mgmt/organizations_paged_list.json b/src/test/resources/mgmt/organizations_paged_list.json new file mode 100644 index 000000000..fb7697708 --- /dev/null +++ b/src/test/resources/mgmt/organizations_paged_list.json @@ -0,0 +1,27 @@ +{ + "organizations": [ + { + "id": "org_VSZmSnzd0m9ITBZ7", + "name": "org-1", + "display_name": "org 1", + "branding": { + "logo_uri": "https://some-url.com/", + "colors": { + "primary": "#FF0000", + "page_background": "#FF0000" + } + }, + "metadata": { + "key1": "val1" + } + }, + { + "id": "org_W3OH9wtMRbjhHuWK", + "name": "org-2", + "display_name": "org 2" + } + ], + "start": 0, + "limit": 20, + "total": 2 +} From 939f8b64eeb4211d5d76334354d46224fc2cbc78 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 7 Apr 2021 12:31:57 -0500 Subject: [PATCH 2/7] Add Management API Links to Organizations JavaDocs --- .../client/mgmt/OrganizationsEntity.java | 80 ++++++++++++++----- .../com/auth0/client/mgmt/UsersEntity.java | 4 +- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java index 4a118d6ad..2fe4455f6 100644 --- a/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java +++ b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java @@ -35,10 +35,12 @@ public class OrganizationsEntity extends BaseManagementEntity { // Organizations Entity /** - * Get all organizations. A token with read:organizations scope is required. + * Get all organizations. A token with {@code read:organizations} scope is required. * * @param filter an optional pagination filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_organizations */ public Request list(PageFilter filter) { HttpUrl.Builder builder = baseUrl @@ -56,10 +58,12 @@ public Request list(PageFilter filter) { } /** - * Get an organization. A token with read:organizations scope is required. + * Get an organization. A token with {@code read:organizations} scope is required. * * @param orgId the ID of the organization to retrieve * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_organizations_by_id */ public Request get(String orgId) { Asserts.assertNotNull(orgId, "organization ID"); @@ -79,10 +83,12 @@ public Request get(String orgId) { } /** - * Get an organization. A token with read:organizations scope is required. + * Get an organization. A token with {@code read:organizations} scope is required. * * @param orgName the name of the organization to retrieve * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_name_by_name */ public Request getByName(String orgName) { Asserts.assertNotNull(orgName, "organization name"); @@ -103,10 +109,12 @@ public Request getByName(String orgName) { } /** - * Create an organization. A token with create:organizations scope is required. + * Create an organization. A token with {@code create:organizations} scope is required. * * @param organization the organization to create * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/post_organizations */ public Request create(Organization organization) { Asserts.assertNotNull(organization, "organization"); @@ -126,11 +134,13 @@ public Request create(Organization organization) { } /** - * Update an organization. A token with update:organizations scope is required. + * Update an organization. A token with {@code update:organizations} scope is required. * * @param orgId the ID of the organization to update * @param organization the updated organization * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/patch_organizations_by_id */ public Request update(String orgId, Organization organization) { Asserts.assertNotNull(orgId, "organization ID"); @@ -152,10 +162,12 @@ public Request update(String orgId, Organization organization) { } /** - * Delete an organization. A token with delete:organizations scope is required. + * Delete an organization. A token with {@code delete:organizations} scope is required. * * @param orgId the ID of the organization to delete * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/delete_organizations_by_id */ public Request delete(String orgId) { Asserts.assertNotNull(orgId, "organization ID"); @@ -175,11 +187,13 @@ public Request delete(String orgId) { // Organization members /** - * Get the members of an organization. A token with read:organization_members scope is required. + * Get the members of an organization. A token with {@code read:organization_members} scope is required. * * @param orgId the ID of the organization * @param filter an optional pagination filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_members */ public Request getMembers(String orgId, PageFilter filter) { Asserts.assertNotNull(orgId, "organization ID"); @@ -200,11 +214,13 @@ public Request getMembers(String orgId, PageFilter filter) { } /** - * Add members to an organization. A token with create:organization_members scope is required. + * Add members to an organization. A token with {@code create:organization_members} scope is required. * * @param orgId the ID of the organization * @param members The members to add * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/post_members */ public Request addMembers(String orgId, Members members) { Asserts.assertNotNull(orgId, "organization ID"); @@ -225,11 +241,13 @@ public Request addMembers(String orgId, Members members) { } /** - * Delete members from an organization. A token with delete:organization_members scope is required. + * Delete members from an organization. A token with {@code delete:organization_members} scope is required. * * @param orgId the ID of the organization * @param members The members to remove * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/delete_members */ public Request deleteMembers(String orgId, Members members) { Asserts.assertNotNull(orgId, "organization ID"); @@ -252,11 +270,13 @@ public Request deleteMembers(String orgId, Members members) { // Organization connections /** - * Get the connections of an organization. A token with read:organization_connections scope is required. + * Get the connections of an organization. A token with {@code read:organization_connections} scope is required. * * @param orgId the ID of the organization * @param filter an optional pagination filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_enabled_connections */ public Request getConnections(String orgId, PageFilter filter) { Asserts.assertNotNull(orgId, "organization ID"); @@ -277,11 +297,13 @@ public Request getConnections(String orgId, PageFilter f } /** - * Add a connection to an organization. A token with create:organization_connections scope is required. + * Add a connection to an organization. A token with {@code create:organization_connections} scope is required. * * @param orgId the ID of the organization * @param connection The connection to add * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/post_enabled_connections */ public Request addConnection(String orgId, EnabledConnection connection) { Asserts.assertNotNull(orgId, "organization ID"); @@ -303,11 +325,13 @@ public Request addConnection(String orgId, EnabledConnection } /** - * Delete a connection from an organization. A token with delete:organization_connections scope is required. + * Delete a connection from an organization. A token with {@code delete:organization_connections} scope is required. * * @param orgId the ID of the organization * @param connectionId the ID of the connection to delete * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/delete_enabled_connections_by_connectionId */ public Request deleteConnection(String orgId, String connectionId) { Asserts.assertNotNull(orgId, "organization ID"); @@ -328,12 +352,14 @@ public Request deleteConnection(String orgId, String connectionId) { } /** - * Update a connection of an organization. A token with update:organization_connections scope is required. + * Update a connection of an organization. A token with {@code update:organization_connections} scope is required. * * @param orgId the ID of the organization * @param connectionId the ID of the connection to update * @param connection the connection to update * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/patch_enabled_connections_by_connectionId */ public Request updateConnection(String orgId, String connectionId, EnabledConnection connection) { Asserts.assertNotNull(orgId, "organization ID"); @@ -359,12 +385,14 @@ public Request updateConnection(String orgId, String connecti // Org roles /** - * Get the roles for a member of an organization. A token with read:organization_members scope is required. + * Get the roles for a member of an organization. A token with {@code read:organization_members} scope is required. * * @param orgId the ID of the organization * @param userId the ID of the user * @param filter an optional pagination filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_organization_member_roles */ public Request getRoles(String orgId, String userId, PageFilter filter) { Asserts.assertNotNull(orgId, "organization ID"); @@ -388,12 +416,14 @@ public Request getRoles(String orgId, String userId, PageFilter filte } /** - * Add roles for a member of an organization. A token with create:organization_member_roles scope is required. + * Add roles for a member of an organization. A token with {@code create:organization_member_roles} scope is required. * * @param orgId the ID of the organization * @param userId the ID of the user * @param roles the roles to add * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/post_organization_member_roles */ public Request addRoles(String orgId, String userId, Roles roles) { Asserts.assertNotNull(orgId, "organization ID"); @@ -417,12 +447,14 @@ public Request addRoles(String orgId, String userId, Roles roles) { } /** - * Delete roles from a member of an organization. A token with delete:organization_member_roles scope is required. + * Delete roles from a member of an organization. A token with {@code delete:organization_member_roles} scope is required. * * @param orgId the ID of the organization * @param userId the ID of the user * @param roles the roles to delete * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/delete_organization_member_roles */ public Request deleteRoles(String orgId, String userId, Roles roles) { Asserts.assertNotNull(orgId, "organization ID"); @@ -448,11 +480,13 @@ public Request deleteRoles(String orgId, String userId, Roles roles) { // Organization invitations /** - * Create an invitation. A token with create:organization_invitations scope is required. + * Create an invitation. A token with {@code create:organization_invitations} scope is required. * * @param orgId the ID of the organization * @param invitation the invitation to create * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/post_invitations */ public Request createInvitation(String orgId, Invitation invitation) { Asserts.assertNotNull(orgId, "organization ID"); @@ -475,12 +509,14 @@ public Request createInvitation(String orgId, Invitation invitation) } /** - * Get an invitation. A token with read:organization_invitations scope is required. + * Get an invitation. A token with {@code read:organization_invitations} scope is required. * * @param orgId the ID of the organization * @param invitationId the ID of the invitation * @param filter an optional result filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_invitations_by_invitation_id */ public Request getInvitation(String orgId, String invitationId, FieldsFilter filter) { Asserts.assertNotNull(orgId, "organization ID"); @@ -503,11 +539,13 @@ public Request getInvitation(String orgId, String invitationId, Fiel } /** - * Gets all invitations for an organization. A token with read:organization_invitations scope is required. + * Gets all invitations for an organization. A token with {@code read:organization_invitations} scope is required. * * @param orgId the ID of the organization * @param filter an optional result filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_invitations */ public Request getInvitations(String orgId, InvitationsFilter filter) { Asserts.assertNotNull(orgId, "organization ID"); @@ -528,11 +566,13 @@ public Request getInvitations(String orgId, InvitationsFilter f } /** - * Delete an invitation. A token with delete:organization_invitations scope is required. + * Delete an invitation. A token with {@code delete:organization_invitations`} scope is required. * * @param orgId the ID of the organization * @param invitationId the ID of the invitation to delete * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/delete_invitations_by_invitation_id */ public Request deleteInvitation(String orgId, String invitationId) { Asserts.assertNotNull(orgId, "organization ID"); diff --git a/src/main/java/com/auth0/client/mgmt/UsersEntity.java b/src/main/java/com/auth0/client/mgmt/UsersEntity.java index 6a25d9bf3..b9af3dc22 100644 --- a/src/main/java/com/auth0/client/mgmt/UsersEntity.java +++ b/src/main/java/com/auth0/client/mgmt/UsersEntity.java @@ -579,11 +579,13 @@ public Request addRoles(String userId, List roleIds) { /** * Get the organizations a user belongs to. - * A token with read:users and read:organizations is required. + * A token with {@code read:users} and {@code read:organizations} is required. * * @param userId the user ID * @param filter an optional pagination filter * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Users/get_organizations */ public Request getOrganizations(String userId, PageFilter filter) { Asserts.assertNotNull(userId, "user ID"); From fa12b6da76bfd72d1ee51e226f5fec17ad98b61e Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 7 Apr 2021 12:47:25 -0500 Subject: [PATCH 3/7] Add method to get an organization connection by ID --- .../client/mgmt/OrganizationsEntity.java | 28 +++++++++++++++++ .../client/mgmt/OrganizationEntityTest.java | 30 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java index 2fe4455f6..b61288aa5 100644 --- a/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java +++ b/src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java @@ -296,6 +296,34 @@ public Request getConnections(String orgId, PageFilter f return request; } + /** + * Get an organization's connection. + * + * @param orgId the ID of the organization + * @param connectionId the ID of the connection + * @return a Request to execute + * + * @see https://auth0.com/docs/api/management/v2#!/Organizations/get_enabled_connections_by_connectionId + */ + public Request getConnection(String orgId, String connectionId) { + Asserts.assertNotNull(orgId, "organization ID"); + Asserts.assertNotNull(connectionId, "connection ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(orgId) + .addPathSegment("enabled_connections") + .addPathSegment(connectionId) + .build() + .toString(); + + CustomRequest request = new CustomRequest<>(client, url, "GET", new TypeReference() { + }); + request.addHeader(AUTHORIZATION_HEADER, "Bearer " + apiToken); + return request; + } + /** * Add a connection to an organization. A token with {@code create:organization_connections} scope is required. * diff --git a/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java index fa7f80f96..c4a548c01 100644 --- a/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java @@ -439,6 +439,36 @@ public void shouldGetOrganizationConnectionsWithTotals() throws Exception { assertThat(response.getItems(), hasSize(2)); } + @Test + public void shouldThrowOnGetConnectionWhenOrgIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("organization ID"); + api.organizations().getConnection(null, "con_id"); + } + + @Test + public void shouldThrowOnGetConnectionWhenConnectionIdNull() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("connection ID"); + api.organizations().getConnection("org_abc", null); + } + + @Test + public void shouldGetConnection() throws Exception { + Request request = api.organizations().getConnection("org_123", "con_abc"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_CONNECTION, 200); + EnabledConnection response = request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath("GET", "/api/v2/organizations/org_123/enabled_connections/con_abc")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + @Test public void shouldThrowOnAddConnectionWhenOrgIdNull() { exception.expect(IllegalArgumentException.class); From d225c9f81dd45a8408ebaf7063a17639b79c3b35 Mon Sep 17 00:00:00 2001 From: Adam Mcgrath Date: Thu, 8 Apr 2021 12:22:42 +0100 Subject: [PATCH 4/7] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3114d1dba..53e481adb 100644 --- a/README.md +++ b/README.md @@ -280,9 +280,9 @@ try { } ``` -### Organizations (Closed Beta) +### Organizations -Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. +[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. Using Organizations, you can: From f355922f242e7a97d39babb82f2395aac8d39089 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Thu, 8 Apr 2021 10:02:07 -0500 Subject: [PATCH 5/7] Remove blockquote from org ID Token validation guidance --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 53e481adb..f893e6808 100644 --- a/README.md +++ b/README.md @@ -305,13 +305,13 @@ String url = auth.authorizeUrl("https://me.auth0.com/callback") .build(); ``` -> When logging into an organization, it is important to ensure the `org_id` claim of the ID Token matches the expected organization value. The `IdTokenVerifier` can be configured with an expected `org_id` claim value: ->```java ->IdTokenVerifier.init("{ISSUER}", "{AUDIENCE}", signatureVerifier) -> .withOrganization("{ORG_ID}") -> .build() -> .verify(jwt); ->``` +**Important!** When logging into an organization, it is important to ensure the `org_id` claim of the ID Token matches the expected organization value. The `IdTokenVerifier` can be configured with an expected `org_id` claim value: +```java +IdTokenVerifier.init("{ISSUER}", "{AUDIENCE}", signatureVerifier) + .withOrganization("{ORG_ID}") + .build() + .verify(jwt); +``` ### Accept user invitations From f3022cf9d04aedbf0d230521ebfacfb605809da3 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Thu, 8 Apr 2021 10:05:11 -0500 Subject: [PATCH 6/7] Add link to tokens with orgs docs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f893e6808..0d19039e4 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,8 @@ String url = auth.authorizeUrl("https://me.auth0.com/callback") .build(); ``` -**Important!** When logging into an organization, it is important to ensure the `org_id` claim of the ID Token matches the expected organization value. The `IdTokenVerifier` can be configured with an expected `org_id` claim value: +**Important!** When logging into an organization, it is important to ensure the `org_id` claim of the ID Token matches the expected organization value. The `IdTokenVerifier` can be configured with an expected `org_id` claim value, as the example below demonstrates. +For more information, please read [Work with Tokens and Organizations](https://auth0.com/docs/organizations/using-tokens) on Auth0 Docs. ```java IdTokenVerifier.init("{ISSUER}", "{AUDIENCE}", signatureVerifier) .withOrganization("{ORG_ID}") From b5eeda4e74bcf76d0f46757a13ad84d99b49b43c Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Fri, 9 Apr 2021 11:59:32 +0200 Subject: [PATCH 7/7] Release 1.29.0 --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2ab6c8e..53bff6e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [1.29.0](https://github.com/auth0/auth0-java/tree/1.29.0) (2021-04-09) +[Full Changelog](https://github.com/auth0/auth0-java/compare/1.28.1...1.29.0) + +**Added** +- Adds method to get an organization's enabled connection and update JavaDocs [\#344](https://github.com/auth0/auth0-java/pull/344) ([jimmyjames](https://github.com/jimmyjames)) +- Add Organizations Management API Support [SDK-2437] [\#341](https://github.com/auth0/auth0-java/pull/341) ([jimmyjames](https://github.com/jimmyjames)) + ## [1.28.1](https://github.com/auth0/auth0-java/tree/1.28.1) (2021-04-05) [Full Changelog](https://github.com/auth0/auth0-java/compare/1.28.0...1.28.1) diff --git a/README.md b/README.md index 0d19039e4..9595a64b2 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,14 @@ Get Auth0 Java via Maven: com.auth0 auth0 - 1.28.1 + 1.29.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:1.28.1' +implementation 'com.auth0:auth0:1.29.0' ```