Skip to content

Commit d7b7e85

Browse files
authored
fix: support new create access token API
2 parents 55675c4 + 446f111 commit d7b7e85

3 files changed

Lines changed: 23 additions & 49 deletions

File tree

README.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,9 @@ art.security.create_api_key( art.security.get_encrypted_password( art.
205205
art.security.get_api_key( art.security.regenerate_api_key( art.security.revoke_user_api_key(
206206
```
207207

208-
Create an access token (for a transient user):
208+
Create an access token:
209209
```python
210-
token = art.security.create_access_token(user_name='transient_artifactory_user',
211-
groups=['g1', 'g2'],
212-
refreshable=True)
213-
```
214-
215-
Create an access token for an existing user (groups are implied from the existing user):
216-
```python
217-
token = art.security.create_access_token(user_name='existing_artifactory_user',
218-
refreshable=True)
210+
token = art.security.create_access_token(user_name='artifactory_user', refreshable=True, scope="applied-permissions/user")
219211
```
220212

221213
Revoke an existing revocable token:

pyartifactory/objects/security.py

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import logging
4-
from typing import Dict, Optional
54

65
from pyartifactory.exception import InvalidTokenDataError
76
from pyartifactory.models.auth import AccessTokenModel, ApiKeyModel, PasswordModel
@@ -14,6 +13,7 @@ class ArtifactorySecurity(ArtifactoryObject):
1413
"""Models artifactory security."""
1514

1615
_uri = "security"
16+
_tokens_uri = "tokens"
1717

1818
def get_encrypted_password(self) -> PasswordModel:
1919
"""
@@ -29,7 +29,7 @@ def create_access_token(
2929
user_name: str,
3030
expires_in: int = 3600,
3131
refreshable: bool = False,
32-
groups: Optional[str] = None,
32+
scope: str = "applied-permissions/user",
3333
) -> AccessTokenModel:
3434
"""
3535
Creates an access token.
@@ -38,39 +38,28 @@ def create_access_token(
3838
is created if user doesn't exist in artifactory.
3939
:param expires_in: Expiry time for the token in seconds. For eternal tokens specify 0.
4040
:param refreshable: If set to true token can be refreshed using the refresh token returned.
41-
:param groups: A list of groups the token has membership of.
42-
If an existing user in artifactory is used with existing memberships
43-
groups are automatically implied without specification.
41+
:param scope: The scope of access that the token provides.
4442
:return: AccessToken
4543
"""
46-
payload = {
47-
"username": user_name,
48-
"expires_in": expires_in,
49-
"refreshable": refreshable,
50-
}
51-
if groups:
52-
if not isinstance(groups, list):
53-
raise ValueError(groups)
54-
scope = f'member-of-groups:"{",".join(groups)}"'
55-
payload.update({"scope": scope})
56-
response = self._post(f"api/{self._uri}/token", data=payload, raise_for_status=False)
44+
payload = {"username": user_name, "expires_in": expires_in, "refreshable": refreshable, "scope": scope}
45+
response = self._post(f"access/api/v1/{self._tokens_uri}", data=payload, raise_for_status=False)
5746
if response.ok:
5847
return AccessTokenModel(**response.json())
5948
raise InvalidTokenDataError(response.json().get("error_description", "Unknown error"))
6049

61-
def revoke_access_token(self, token: Optional[str] = None, token_id: Optional[str] = None) -> bool:
50+
def revoke_access_token(self, token: str) -> bool:
6251
"""
6352
Revokes an access token.
6453
6554
:param token: The token to revoke
66-
:param token_id: The id of a token to revoke
6755
:return: bool True or False indicating success or failure of token revocation attempt.
6856
"""
69-
if not any([token, token_id]):
70-
logger.error("Neither a token or a token id was specified")
71-
raise InvalidTokenDataError
72-
payload: Dict[str, Optional[str]] = {"token": token} if token else {"token_id": token_id}
73-
response = self._post(f"api/{self._uri}/token/revoke", data=payload, raise_for_status=False)
57+
58+
response = self._delete(
59+
f"access/api/v1/{self._tokens_uri}/revoke",
60+
data={"token": token},
61+
raise_for_status=False,
62+
)
7463
if response.ok:
7564
logger.debug("Token revoked successfully, or token did not exist")
7665
return True

tests/test_security.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from __future__ import annotations
22

3-
import pytest
43
import responses
54

65
from pyartifactory import ArtifactorySecurity
7-
from pyartifactory.exception import InvalidTokenDataError
86
from pyartifactory.models import ApiKeyModel, AuthModel, PasswordModel
97

108
URL = "http://localhost:8080/artifactory"
@@ -77,29 +75,24 @@ def test_revoke_user_api_key():
7775
def test_create_access_token():
7876
responses.add(
7977
responses.POST,
80-
f"{URL}/api/security/token",
78+
f"{URL}/access/api/v1/tokens",
8179
status=200,
8280
json={
8381
"access_token": "<the access token>",
8482
"expires_in": 3600,
85-
"scope": "api:* member-of-groups:g1, g2",
86-
"token_type": "Bearer",
83+
"scope": "applied-permissions/user",
84+
"token_type": "access_token",
8785
},
8886
)
8987

9088
artifactory_security = ArtifactorySecurity(AuthModel(url=URL, auth=AUTH))
91-
access_token = artifactory_security.create_access_token(
92-
user_name="my-username",
93-
expires_in=3600,
94-
refreshable=False,
95-
groups=["g1", "g2"],
96-
)
97-
assert access_token.scope == "api:* member-of-groups:g1, g2"
89+
access_token = artifactory_security.create_access_token(user_name="my-username", expires_in=3600, refreshable=False)
90+
assert access_token.scope == "applied-permissions/user"
9891

9992

10093
@responses.activate
10194
def test_revoke_access_token_success():
102-
responses.add(responses.POST, f"{URL}/api/security/token/revoke", status=200)
95+
responses.add(responses.DELETE, f"{URL}/access/api/v1/tokens/revoke", status=200)
10396

10497
artifactory_security = ArtifactorySecurity(AuthModel(url=URL, auth=AUTH))
10598
result = artifactory_security.revoke_access_token(token="my-token") # noqa: S106
@@ -108,8 +101,8 @@ def test_revoke_access_token_success():
108101

109102
@responses.activate
110103
def test_revoke_access_token_fail_no_token_provided():
111-
responses.add(responses.POST, f"{URL}/api/security/token/revoke", status=400)
104+
responses.add(responses.DELETE, f"{URL}/access/api/v1/tokens/revoke", status=400)
112105

113106
artifactory_security = ArtifactorySecurity(AuthModel(url=URL, auth=AUTH))
114-
with pytest.raises(InvalidTokenDataError):
115-
artifactory_security.revoke_access_token()
107+
result = artifactory_security.revoke_access_token(token="my-token") # noqa: S106
108+
assert result is False

0 commit comments

Comments
 (0)