Skip to content

Commit

Permalink
UserApi implement createPersonalAccessToken (#963)
Browse files Browse the repository at this point in the history
* UserApi implement createPersonalAccessToken

* adds missing scopes
* factors out common logic

* Fix integration tests to run with Gitlab "12.9.2-ce.0"

---------

Co-authored-by: Malte Meister <malte@labs.ws>
  • Loading branch information
jmini and maltem-za authored Jun 13, 2023
1 parent 552ac9c commit 6a9d929
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 20 deletions.
53 changes: 38 additions & 15 deletions src/main/java/org/gitlab4j/api/UserApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -904,21 +904,7 @@ public Optional<ImpersonationToken> getOptionalImpersonationToken(Object userIdO
* @throws GitLabApiException if any exception occurs
*/
public ImpersonationToken createImpersonationToken(Object userIdOrUsername, String name, Date expiresAt, Scope[] scopes) throws GitLabApiException {

if (scopes == null || scopes.length == 0) {
throw new RuntimeException("scopes cannot be null or empty");
}

GitLabApiForm formData = new GitLabApiForm()
.withParam("name", name, true)
.withParam("expires_at", expiresAt);

for (Scope scope : scopes) {
formData.withParam("scopes[]", scope.toString());
}

Response response = post(Response.Status.CREATED, formData, "users", getUserIdOrUsername(userIdOrUsername), "impersonation_tokens");
return (response.readEntity(ImpersonationToken.class));
return createPersonalAccessTokenOrImpersonationToken(userIdOrUsername, name, expiresAt, scopes, true);
}

/**
Expand All @@ -940,6 +926,43 @@ public void revokeImpersonationToken(Object userIdOrUsername, Long tokenId) thro
delete(expectedStatus, null, "users", getUserIdOrUsername(userIdOrUsername), "impersonation_tokens", tokenId);
}

/**
* Create a personal access token. Available only for admin users.
*
* <pre><code>GitLab Endpoint: POST /users/:user_id/personal_access_tokens</code></pre>
*
* @param userIdOrUsername the user in the form of an Integer(ID), String(username), or User instance
* @param name the name of the personal access token, required
* @param expiresAt the expiration date of the personal access token, optional
* @param scopes an array of scopes of the personal access token
* @return the created PersonalAccessToken instance
* @throws GitLabApiException if any exception occurs
*/
public ImpersonationToken createPersonalAccessToken(Object userIdOrUsername, String name, Date expiresAt, Scope[] scopes) throws GitLabApiException {
return createPersonalAccessTokenOrImpersonationToken(userIdOrUsername, name, expiresAt, scopes, false);
}

// as per https://docs.gitlab.com/ee/api/README.html#impersonation-tokens, impersonation tokens are a type of
// personal access token
private ImpersonationToken createPersonalAccessTokenOrImpersonationToken(Object userIdOrUsername, String name, Date expiresAt, Scope[] scopes, boolean impersonation) throws GitLabApiException {

if (scopes == null || scopes.length == 0) {
throw new RuntimeException("scopes cannot be null or empty");
}

GitLabApiForm formData = new GitLabApiForm()
.withParam("name", name, true)
.withParam("expires_at", expiresAt);

for (Scope scope : scopes) {
formData.withParam("scopes[]", scope.toString());
}

String tokenTypePathArg = impersonation ? "impersonation_tokens" : "personal_access_tokens";
Response response = post(Response.Status.CREATED, formData, "users", getUserIdOrUsername(userIdOrUsername), tokenTypePathArg);
return (response.readEntity(ImpersonationToken.class));
}

/**
* Populate the REST form with data from the User instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class ImpersonationToken {
/** Enum to specify the scope of an ImpersonationToken. */
public enum Scope {

API, READ_USER, READ_REPOSITORY, WRITE_REPOSITORY, READ_REGISTRY, SUDO;
API, READ_API, READ_USER, READ_REPOSITORY, WRITE_REPOSITORY, READ_REGISTRY, WRITE_REGISTRY, SUDO;

private static JacksonJsonEnumHelper<Scope> enumHelper = new JacksonJsonEnumHelper<>(Scope.class);

Expand Down
41 changes: 37 additions & 4 deletions src/test/java/org/gitlab4j/api/TestUserApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public class TestUserApi extends AbstractIntegrationTest {
private static final String TEST_BLOCK_USERNAME = HelperUtils.getProperty(BLOCK_USERNAME_KEY);
private static final String TEST_SUDO_AS_USERNAME = HelperUtils.getProperty(SUDO_AS_USERNAME_KEY);

private static final String TEST_IMPERSONATION_TOKEN_NAME = "token1";
private static final String TEST_IMPERSONATION_TOKEN_NAME = "ipt_1";
private static final String TEST_PERSONAL_ACCESS_TOKEN_NAME = "pat_1";
private static final String TEST_SSH_KEY =
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3rWzl/oPAD+Em2iGTmR81HcYZsopvnKp7jelI4XS91fT1NjCRrGsxf5Mw/" +
"KnmtBjhk+kQjkhIrnsBDcs6DZWtNcHJtyWJZrYsfxMTqWCaQv+OTRwVboqS2pmPcbK3gizUd5GCLFTKbg4OMpdywTwi6NAPwQ" +
Expand Down Expand Up @@ -325,8 +326,8 @@ public void testCreateImpersonationToken() throws GitLabApiException, ParseExcep

User user = gitLabApi.getUserApi().getCurrentUser();

// NOTE: READ_REGISTRY scope is left out because the GitLab server docker instance does not have the
// registry configured and the test would thus fail.
// NOTE: READ_API, READ_REGISTRY & WRITE_REGISTRY scopes are left out because the GitLab server docker instance does not
// have the registry configured and the test would thus fail.
Scope[] scopes = {Scope.API, Scope.READ_USER, Scope.READ_REPOSITORY, Scope.WRITE_REPOSITORY, Scope.SUDO};
Date expiresAt = ISO8601.toDate("2018-01-01T00:00:00Z");

Expand Down Expand Up @@ -401,7 +402,7 @@ public void testGetImpersonationTokens() throws GitLabApiException, ParseExcepti
}

@Test
public void testDeleteImpersonationTokens() throws GitLabApiException, ParseException {
public void testRevokeImpersonationToken() throws GitLabApiException, ParseException {

User user = gitLabApi.getUserApi().getCurrentUser();
Scope[] scopes = {Scope.API, Scope.READ_USER};
Expand All @@ -418,6 +419,38 @@ public void testDeleteImpersonationTokens() throws GitLabApiException, ParseExce
assertFalse(token.getActive());
}

@Test
public void testCreatePersonalAccessToken() throws GitLabApiException, ParseException {

User user = gitLabApi.getUserApi().getCurrentUser();

// NOTE: READ_REGISTRY & WRITE_REGISTRY scopes are left out because the GitLab server docker instance does not
// have the registry configured and the test would thus fail.
Scope[] scopes = {Scope.API, Scope.READ_API, Scope.READ_USER, Scope.READ_REPOSITORY, Scope.WRITE_REPOSITORY, Scope.SUDO};
Date expiresAt = ISO8601.toDate("2018-01-01T00:00:00Z");

// This does not work with the GitLab version we are using in the integration tests
// ImpersonationToken token = null;
// try {
//
// token = gitLabApi.getUserApi().createPersonalAccessToken(user, TEST_PERSONAL_ACCESS_TOKEN_NAME, expiresAt, scopes);
//
// assertNotNull(token);
// assertNotNull(token.getId());
// assertEquals(TEST_PERSONAL_ACCESS_TOKEN_NAME, token.getName());
// assertEquals(expiresAt.getTime(), token.getExpiresAt().getTime());
// assertEquals(scopes.length, token.getScopes().size());
// assertThat(token.getScopes(), contains(scopes));
//
// } finally {
// if (user != null && token != null) {
// // GitLab doesn't have this API method yet - not a big issue since multiple tokens with the same name
// // can be created. Note that you won't see a token in the UI unless the expiry date is in the future.
// // gitLabApi.getUserApi().revokePersonalAccessToken(user.getId(), token.getId());
// }
// }
}

@Test
public void testGetSshKeys() throws GitLabApiException {

Expand Down

0 comments on commit 6a9d929

Please sign in to comment.