Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1404403

Browse files
committed
Add orgs in client credentials support
1 parent c00b4ea commit 1404403

File tree

6 files changed

+219
-0
lines changed

6 files changed

+219
-0
lines changed

auth0/authentication/get_token.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def client_credentials(
9191
self,
9292
audience: str,
9393
grant_type: str = "client_credentials",
94+
organization: str | None = None,
9495
) -> Any:
9596
"""Client credentials grant
9697
@@ -104,6 +105,9 @@ def client_credentials(
104105
105106
grant_type (str, optional): Denotes the flow you're using. For client credentials use "client_credentials"
106107
108+
organization (str, optional): Optional Organization name or ID. When included, the access token returned
109+
will include the org_id and org_name claims
110+
107111
Returns:
108112
access_token
109113
"""
@@ -114,6 +118,7 @@ def client_credentials(
114118
"client_id": self.client_id,
115119
"audience": audience,
116120
"grant_type": grant_type,
121+
"organization": organization,
117122
},
118123
)
119124

auth0/management/client_grants.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def all(
5959
per_page: int | None = None,
6060
include_totals: bool = False,
6161
client_id: str | None = None,
62+
allow_any_organization: bool | None = None,
6263
):
6364
"""Retrieves all client grants.
6465
@@ -77,6 +78,8 @@ def all(
7778
7879
client_id (string, optional): The id of a client to filter.
7980
81+
allow_any_organization (bool, optional): Optional filter on allow_any_organization.
82+
8083
See: https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants
8184
"""
8285

@@ -86,6 +89,7 @@ def all(
8689
"per_page": per_page,
8790
"include_totals": str(include_totals).lower(),
8891
"client_id": client_id,
92+
"allow_any_organization": allow_any_organization,
8993
}
9094

9195
return self.client.get(self._url(), params=params)
@@ -124,3 +128,43 @@ def update(self, id: str, body: dict[str, Any]) -> dict[str, Any]:
124128
"""
125129

126130
return self.client.patch(self._url(id), data=body)
131+
132+
def get_organizations(
133+
self,
134+
id: str,
135+
page: int | None = None,
136+
per_page: int | None = None,
137+
include_totals: bool = False,
138+
from_param: str | None = None,
139+
take: int | None = None,
140+
):
141+
"""Get the organizations associated to a client grant.
142+
143+
Args:
144+
id (str): Id of client grant.
145+
146+
page (int, optional): The result's page number (zero based). When not set,
147+
the default value is up to the server.
148+
149+
per_page (int, optional): The amount of entries per page. When not set,
150+
the default value is up to the server.
151+
152+
include_totals (bool, optional): True if the query summary is
153+
to be included in the result, False otherwise. Defaults to False.
154+
155+
from_param (str, optional): Id to start retrieving entries. You can
156+
limit the amount of entries using the take parameter.
157+
158+
take (int, optional): The total amount of entries to retrieve when
159+
using the from parameter. When not set, the default value is up to the server.
160+
"""
161+
162+
params = {
163+
"per_page": per_page,
164+
"page": page,
165+
"include_totals": str(include_totals).lower(),
166+
"from": from_param,
167+
"take": take,
168+
}
169+
170+
return self.client.get(self._url(f"{id}/organizations"), params=params)

auth0/management/organizations.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,65 @@ def delete_organization_invitation(self, id: str, invitation_id: str) -> Any:
460460
"""
461461

462462
return self.client.delete(self._url(id, "invitations", invitation_id))
463+
464+
def get_client_grants(
465+
self,
466+
id: str,
467+
audience: str | None = None,
468+
client_id: str | None = None,
469+
page: int | None = None,
470+
per_page: int | None = None,
471+
include_totals: bool = False,
472+
):
473+
"""Get client grants associated to an organization.
474+
475+
Args:
476+
id (str): Id of organization.
477+
478+
audience (str, optional): URL encoded audience of a Resource Server
479+
to filter.
480+
481+
client_id (string, optional): The id of a client to filter.
482+
483+
page (int, optional): The result's page number (zero based). When not set,
484+
the default value is up to the server.
485+
486+
per_page (int, optional): The amount of entries per page. When not set,
487+
the default value is up to the server.
488+
489+
include_totals (bool, optional): True if the query summary is
490+
to be included in the result, False otherwise. Defaults to False.
491+
"""
492+
params = {
493+
"audience": audience,
494+
"client_id": client_id,
495+
"page": page,
496+
"per_page": per_page,
497+
"include_totals": str(include_totals).lower(),
498+
}
499+
500+
return self.client.get(self._url(id, "client-grants"), params=params)
501+
502+
def add_client_grant(self, id: str, grant_id: str) -> dict[str, Any]:
503+
"""Associate a client grant with an organization.
504+
505+
Args:
506+
id (str): the ID of the organization.
507+
508+
grant_id (string) A Client Grant ID to add to the organization.
509+
"""
510+
511+
return self.client.post(
512+
self._url(id, "client-grants"), data={"grant_id": grant_id}
513+
)
514+
515+
def delete_client_grant(self, id: str, grant_id: str) -> dict[str, Any]:
516+
"""Remove a client grant from an organization.
517+
518+
Args:
519+
id (str): the ID of the organization.
520+
521+
grant_id (string) A Client Grant ID to remove from the organization.
522+
"""
523+
524+
return self.client.delete(self._url(id, "client-grants", grant_id))

auth0/test/authentication/test_get_token.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def test_client_credentials(self, mock_post):
111111
"client_secret": "clsec",
112112
"audience": "aud",
113113
"grant_type": "gt",
114+
"organization": None,
114115
},
115116
)
116117

@@ -133,11 +134,32 @@ def test_client_credentials_with_client_assertion(self, mock_post):
133134
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
134135
"audience": "aud",
135136
"grant_type": "gt",
137+
"organization": None,
136138
},
137139
)
138140

139141
self.assertTrue(fnmatch(kwargs["data"]["client_assertion"], "*.*.*"))
140142

143+
@mock.patch("auth0.rest.RestClient.post")
144+
def test_client_credentials_with_organization(self, mock_post):
145+
g = GetToken("my.domain.com", "cid", client_secret="clsec")
146+
147+
g.client_credentials("aud", organization="my-org")
148+
149+
args, kwargs = mock_post.call_args
150+
151+
self.assertEqual(args[0], "https://my.domain.com/oauth/token")
152+
self.assertEqual(
153+
kwargs["data"],
154+
{
155+
"client_id": "cid",
156+
"grant_type": "client_credentials",
157+
"client_secret": "clsec",
158+
"audience": "aud",
159+
"organization": "my-org",
160+
},
161+
)
162+
141163
@mock.patch("auth0.rest.RestClient.post")
142164
def test_login(self, mock_post):
143165
g = GetToken("my.domain.com", "cid", client_secret="clsec")

auth0/test/management/test_client_grants.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def test_all(self, mock_rc):
3333
"per_page": None,
3434
"include_totals": "false",
3535
"client_id": None,
36+
"allow_any_organization": None,
3637
},
3738
)
3839

@@ -50,6 +51,7 @@ def test_all(self, mock_rc):
5051
"per_page": None,
5152
"include_totals": "false",
5253
"client_id": None,
54+
"allow_any_organization": None,
5355
},
5456
)
5557

@@ -67,6 +69,7 @@ def test_all(self, mock_rc):
6769
"per_page": 23,
6870
"include_totals": "true",
6971
"client_id": None,
72+
"allow_any_organization": None,
7073
},
7174
)
7275

@@ -84,6 +87,25 @@ def test_all(self, mock_rc):
8487
"per_page": None,
8588
"include_totals": "false",
8689
"client_id": "exampleid",
90+
"allow_any_organization": None,
91+
},
92+
)
93+
94+
# With allow any organization
95+
c.all(allow_any_organization=True)
96+
97+
args, kwargs = mock_instance.get.call_args
98+
99+
self.assertEqual("https://domain/api/v2/client-grants", args[0])
100+
self.assertEqual(
101+
kwargs["params"],
102+
{
103+
"audience": None,
104+
"page": None,
105+
"per_page": None,
106+
"include_totals": "false",
107+
"client_id": None,
108+
"allow_any_organization": True,
87109
},
88110
)
89111

@@ -120,3 +142,26 @@ def test_update(self, mock_rc):
120142

121143
self.assertEqual("https://domain/api/v2/client-grants/this-id", args[0])
122144
self.assertEqual(kwargs["data"], {"a": "b", "c": "d"})
145+
146+
@mock.patch("auth0.management.client_grants.RestClient")
147+
def test_get_organizations(self, mock_rc):
148+
mock_instance = mock_rc.return_value
149+
150+
c = ClientGrants(domain="domain", token="jwttoken")
151+
c.get_organizations("cgid")
152+
153+
args, kwargs = mock_instance.get.call_args
154+
155+
self.assertEqual(
156+
"https://domain/api/v2/client-grants/cgid/organizations", args[0]
157+
)
158+
self.assertEqual(
159+
kwargs["params"],
160+
{
161+
"page": None,
162+
"per_page": None,
163+
"include_totals": "false",
164+
"from": None,
165+
"take": None,
166+
},
167+
)

auth0/test/management/test_organizations.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,44 @@ def test_delete_organization_invitation(self, mock_rc):
479479
mock_instance.delete.assert_called_with(
480480
"https://domain/api/v2/organizations/test-org/invitations/test-inv"
481481
)
482+
483+
@mock.patch("auth0.management.organizations.RestClient")
484+
def test_get_client_grants(self, mock_rc):
485+
mock_instance = mock_rc.return_value
486+
487+
c = Organizations(domain="domain", token="jwttoken")
488+
c.get_client_grants("test-org")
489+
490+
mock_instance.get.assert_called_with(
491+
"https://domain/api/v2/organizations/test-org/client-grants",
492+
params={
493+
"audience": None,
494+
"client_id": None,
495+
"page": None,
496+
"per_page": None,
497+
"include_totals": "false",
498+
},
499+
)
500+
501+
@mock.patch("auth0.management.organizations.RestClient")
502+
def test_add_client_grant(self, mock_rc):
503+
mock_instance = mock_rc.return_value
504+
505+
c = Organizations(domain="domain", token="jwttoken")
506+
c.add_client_grant("test-org", "test-cg")
507+
508+
mock_instance.post.assert_called_with(
509+
"https://domain/api/v2/organizations/test-org/client-grants",
510+
data={"grant_id": "test-cg"},
511+
)
512+
513+
@mock.patch("auth0.management.organizations.RestClient")
514+
def test_delete_client_grant(self, mock_rc):
515+
mock_instance = mock_rc.return_value
516+
517+
c = Organizations(domain="domain", token="jwttoken")
518+
c.delete_client_grant("test-org", "test-cg")
519+
520+
mock_instance.delete.assert_called_with(
521+
"https://domain/api/v2/organizations/test-org/client-grants/test-cg",
522+
)

0 commit comments

Comments
 (0)