Skip to content

Commit

Permalink
[SDK-4542] Support organization in client credentials (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
jimmyjames committed Nov 17, 2023
1 parent b31f779 commit c117f3c
Show file tree
Hide file tree
Showing 20 changed files with 934 additions and 15 deletions.
29 changes: 29 additions & 0 deletions src/main/java/com/auth0/client/auth/AuthAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class AuthAPI {
private static final String PATH_REVOKE = "revoke";
private static final String PATH_PASSWORDLESS = "passwordless";
private static final String PATH_START = "start";
private static final String KEY_ORGANIZATION = "organization";

private final Auth0HttpClient client;
private final String clientId;
Expand Down Expand Up @@ -715,12 +716,40 @@ public TokenRequest exchangePasswordlessOtp(String emailOrPhone, String realm, c
* @return a Request to configure and execute.
*/
public TokenRequest requestToken(String audience) {
return requestToken(audience, null);
}

/**
* Creates a request to get a Token for the given audience using the 'Client Credentials' grant.
* Default used realm is defined in the "API Authorization Settings" in the account's advanced settings in the Auth0 Dashboard.
* <strong>This operation requires that a client secret be configured for the {@code AuthAPI} client.</strong>
* <pre>
* {@code
* try {
* TokenHolder result = authAPI.requestToken("https://myapi.me.auth0.com/users", "org_123")
* .execute()
* .getBody();
* } catch (Auth0Exception e) {
* //Something happened
* }
* }
* </pre>
*
* @see <a href="https://auth0.com/docs/api/authentication#client-credentials-flow">Client Credentials Flow API docs</a>
* @param audience the audience of the API to request access to.
* @param org the organization name or ID to be included in the request.
* @return a Request to configure and execute.
*/
public TokenRequest requestToken(String audience, String org) {
Asserts.assertNotNull(audience, "audience");

TokenRequest request = new TokenRequest(client, getTokenUrl());
request.addParameter(KEY_CLIENT_ID, clientId);
request.addParameter(KEY_GRANT_TYPE, "client_credentials");
request.addParameter(KEY_AUDIENCE, audience);
if (org != null && !org.trim().isEmpty()) {
request.addParameter(KEY_ORGANIZATION, org);
}
addClientAuthentication(request, true);
return request;
}
Expand Down
87 changes: 77 additions & 10 deletions src/main/java/com/auth0/client/mgmt/ClientGrantsEntity.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.auth0.client.mgmt;

import com.auth0.client.mgmt.filter.ClientGrantsFilter;
import com.auth0.client.mgmt.filter.PageFilter;
import com.auth0.json.mgmt.clientgrants.ClientGrant;
import com.auth0.json.mgmt.clientgrants.ClientGrantsPage;
import com.auth0.json.mgmt.organizations.OrganizationsPage;
import com.auth0.net.BaseRequest;
import com.auth0.net.Request;
import com.auth0.net.VoidRequest;
Expand Down Expand Up @@ -61,24 +63,44 @@ public Request<ClientGrantsPage> list(ClientGrantsFilter filter) {
* @return a Request to execute.
*/
public Request<ClientGrant> create(String clientId, String audience, String[] scope) {
return create(clientId, audience, scope, null, null);
}

/**
* Create a Client Grant. A token with scope create:client_grants is needed.
* See https://auth0.com/docs/api/management/v2#!/Client_Grants/post_client_grants
*
* @param clientId the application's client id to associate this grant with.
* @param audience the audience of the grant.
* @param scope the scope to grant.
* @param orgUsage Defines whether organizations can be used with client credentials exchanges for this grant. (defaults to deny when not defined)
* @param allowAnyOrg If true, any organization can be used with this grant. If disabled (default), the grant must be explicitly assigned to the desired organizations.
* @return a Request to execute.
*/
public Request<ClientGrant> create(String clientId, String audience, String[] scope, String orgUsage, Boolean allowAnyOrg) {
Asserts.assertNotNull(clientId, "client id");
Asserts.assertNotNull(audience, "audience");
Asserts.assertNotNull(scope, "scope");

String url = baseUrl
.newBuilder()
.addPathSegments("api/v2/client-grants")
.build()
.toString();
.newBuilder()
.addPathSegments("api/v2/client-grants")
.build()
.toString();
BaseRequest<ClientGrant> request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference<ClientGrant>() {
});
request.addParameter("client_id", clientId);
request.addParameter("audience", audience);
request.addParameter("scope", scope);
if (orgUsage != null && !orgUsage.trim().isEmpty()) {
request.addParameter("organization_usage", orgUsage);
}
if (allowAnyOrg != null) {
request.addParameter("allow_any_organization", allowAnyOrg);
}
return request;
}


/**
* Delete an existing Client Grant. A token with scope delete:client_grants is needed.
* See https://auth0.com/docs/api/management/v2#!/Client_Grants/delete_client_grants_by_id
Expand Down Expand Up @@ -107,18 +129,63 @@ public Request<Void> delete(String clientGrantId) {
* @return a Request to execute.
*/
public Request<ClientGrant> update(String clientGrantId, String[] scope) {
return update(clientGrantId, scope, null, null);
}

/**
* Update an existing Client Grant. A token with scope update:client_grants is needed.
* See https://auth0.com/docs/api/management/v2#!/Client_Grants/patch_client_grants_by_id
*
* @param clientGrantId the client grant id.
* @param scope the scope to grant.
* @param orgUsage Defines whether organizations can be used with client credentials exchanges for this grant. (defaults to deny when not defined)
* @param allowAnyOrg If true, any organization can be used with this grant. If disabled (default), the grant must be explicitly assigned to the desired organizations.
* @return a Request to execute.
*/
public Request<ClientGrant> update(String clientGrantId, String[] scope, String orgUsage, Boolean allowAnyOrg) {
Asserts.assertNotNull(clientGrantId, "client grant id");
Asserts.assertNotNull(scope, "scope");

String url = baseUrl
.newBuilder()
.addPathSegments("api/v2/client-grants")
.addPathSegment(clientGrantId)
.build()
.toString();
.newBuilder()
.addPathSegments("api/v2/client-grants")
.addPathSegment(clientGrantId)
.build()
.toString();
BaseRequest<ClientGrant> request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.PATCH, new TypeReference<ClientGrant>() {
});
request.addParameter("scope", scope);
if (orgUsage != null && !orgUsage.trim().isEmpty()) {
request.addParameter("organization_usage", orgUsage);
}
if (allowAnyOrg != null) {
request.addParameter("allow_any_organization", allowAnyOrg);
}
return request;
}

/**
* Returns the organizations associated with this client grant. A token with scope {@code read:organization_client_grants} is required.
* @param clientGrantId the client grant ID.
* @param filter an optional filter to limit results.
* @return a request to execute.
*/
public Request<OrganizationsPage> listOrganizations(String clientGrantId, PageFilter filter) {
Asserts.assertNotNull(clientGrantId, "client grant ID");
HttpUrl.Builder builder = baseUrl
.newBuilder()
.addPathSegments("api/v2/client-grants")
.addPathSegment(clientGrantId)
.addPathSegment("organizations");

if (filter != null) {
for (Map.Entry<String, Object> e : filter.getAsMap().entrySet()) {
builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue()));
}
}

String url = builder.build().toString();
return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference<OrganizationsPage>() {
});
}
}
72 changes: 68 additions & 4 deletions src/main/java/com/auth0/client/mgmt/OrganizationsEntity.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
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.client.mgmt.filter.*;
import com.auth0.json.mgmt.roles.RolesPage;
import com.auth0.json.mgmt.organizations.*;
import com.auth0.net.BaseRequest;
Expand Down Expand Up @@ -602,6 +599,73 @@ public Request<Void> deleteInvitation(String orgId, String invitationId) {
return new VoidRequest(client, tokenProvider, url, HttpMethod.DELETE);
}

/**
* Get the client grants associated with this organization. A token with scope {@code read:organization_client_grants} is required.
* @param orgId the organization ID.
* @param filter an optional filter to refine results.
* @return a request to execute.
*/
public Request<OrganizationClientGrantsPage> listClientGrants(String orgId, OrganizationClientGrantsFilter filter) {
Asserts.assertNotNull(orgId, "organization ID");

HttpUrl.Builder builder = baseUrl
.newBuilder()
.addPathSegments(ORGS_PATH)
.addPathSegments(orgId)
.addPathSegment("client-grants");

applyFilter(filter, builder);

String url = builder.build().toString();

return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference<OrganizationClientGrantsPage>() {});
}

/**
* Associate a client grant with an organization. A token with scope {@code create:organization_client_grants} is required.
* @param orgId the organization ID.
* @param addOrganizationClientGrantRequestBody the body of the request containing information about the client grant to associate.
* @return a request to execute.
*/
public Request<OrganizationClientGrant> addClientGrant(String orgId, CreateOrganizationClientGrantRequestBody addOrganizationClientGrantRequestBody) {
Asserts.assertNotNull(orgId, "organization ID");
Asserts.assertNotNull(addOrganizationClientGrantRequestBody, "client grant");

String url = baseUrl
.newBuilder()
.addPathSegments(ORGS_PATH)
.addPathSegment(orgId)
.addPathSegment("client-grants")
.build()
.toString();

BaseRequest<OrganizationClientGrant> request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference<OrganizationClientGrant>() {});
request.setBody(addOrganizationClientGrantRequestBody);
return request;
}

/**
* Remove a client grant from an organization. A token with scope {@code delete:organization_client_grants} is required.
* @param orgId the organization ID.
* @param grantId the client grant ID.
* @return a request to execute.
*/
public Request<Void> deleteClientGrant(String orgId, String grantId) {
Asserts.assertNotNull(orgId, "organization ID");
Asserts.assertNotNull(grantId, "client grant ID");

String url = baseUrl
.newBuilder()
.addPathSegments(ORGS_PATH)
.addPathSegment(orgId)
.addPathSegment("client-grants")
.addPathSegment(grantId)
.build()
.toString();

return new VoidRequest(client, tokenProvider, url, HttpMethod.DELETE);
}

private void applyFilter(BaseFilter filter, HttpUrl.Builder builder) {
if (filter != null) {
for (Map.Entry<String, Object> e : filter.getAsMap().entrySet()) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/auth0/client/mgmt/filter/ClientGrantsFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ public ClientGrantsFilter withAudience(String audience) {
return this;
}

/**
* Filter by {@code allow_any_organization}
* @param allowAnyOrganization only retrieve items with the {@code allow_any_organization} value specfied.
* @return this filter instance.
*/
public ClientGrantsFilter withAllowAnyOrganization(Boolean allowAnyOrganization) {
parameters.put("allow_any_organization", allowAnyOrganization);
return this;
}

/**
* Filter by page
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.auth0.client.mgmt.filter;

/**
* Class used to filter the results received when listing the client grants associated with an organization.
* Related to the {@link com.auth0.client.mgmt.OrganizationsEntity} entity.
*/
public class OrganizationClientGrantsFilter extends BaseFilter {

/**
* Filter by client id
*
* @param clientId only retrieve items with this client id.
* @return this filter instance
*/
public OrganizationClientGrantsFilter withClientId(String clientId) {
parameters.put("client_id", clientId);
return this;
}

/**
* Filter by audience
*
* @param audience only retrieve the item with this audience.
* @return this filter instance
*/
public OrganizationClientGrantsFilter withAudience(String audience) {
parameters.put("audience", audience);
return this;
}

/**
* 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 OrganizationClientGrantsFilter 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 OrganizationClientGrantsFilter withTotals(boolean includeTotals) {
parameters.put("include_totals", includeTotals);
return this;
}
}
32 changes: 32 additions & 0 deletions src/main/java/com/auth0/json/mgmt/clientgrants/ClientGrant.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public class ClientGrant {
private String audience;
@JsonProperty("scope")
private List<String> scope;
@JsonProperty("organization_usage")
private String organizationUsage;
@JsonProperty("allow_any_organization")
private Boolean allowAnyOrganization;

/**
* Getter for the id of the client grant.
Expand Down Expand Up @@ -92,4 +96,32 @@ public List<String> getScope() {
public void setScope(List<String> scope) {
this.scope = scope;
}

/**
* @return the organization use
*/
public String getOrganizationUsage() {
return organizationUsage;
}

/**
* @param organizationUsage the value of {@code organization_usage} to set.
*/
public void setOrganizationUsage(String organizationUsage) {
this.organizationUsage = organizationUsage;
}

/**
* @return the value of {@code allow_any_organization}
*/
public Boolean getAllowAnyOrganization() {
return allowAnyOrganization;
}

/**
* @param allowAnyOrganization the value of {@code allow_any_organization} to set.
*/
public void setAllowAnyOrganization(Boolean allowAnyOrganization) {
this.allowAnyOrganization = allowAnyOrganization;
}
}
Loading

0 comments on commit c117f3c

Please sign in to comment.