Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement createPersonalAccessToken #686

Open
wants to merge 1 commit into
base: 6.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 48 additions & 25 deletions src/main/java/org/gitlab4j/api/UserApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import org.gitlab4j.api.GitLabApi.ApiVersion;
import org.gitlab4j.api.models.CustomAttribute;
import org.gitlab4j.api.models.Email;
import org.gitlab4j.api.models.ImpersonationToken;
import org.gitlab4j.api.models.ImpersonationToken.Scope;
import org.gitlab4j.api.models.PersonalAccessToken;
import org.gitlab4j.api.models.PersonalAccessToken.Scope;
import org.gitlab4j.api.models.SshKey;
import org.gitlab4j.api.models.User;
import org.gitlab4j.api.utils.EmailChecker;
Expand Down Expand Up @@ -829,7 +829,7 @@ public void deleteSshKey(Object userIdOrUsername, Integer keyId) throws GitLabAp
* @return a list of a specified user's impersonation tokens
* @throws GitLabApiException if any exception occurs
*/
public List<ImpersonationToken> getImpersonationTokens(Object userIdOrUsername) throws GitLabApiException {
public List<PersonalAccessToken> getImpersonationTokens(Object userIdOrUsername) throws GitLabApiException {
return (getImpersonationTokens(userIdOrUsername, null));
}

Expand All @@ -843,12 +843,12 @@ public List<ImpersonationToken> getImpersonationTokens(Object userIdOrUsername)
* @return a list of a specified user's impersonation tokens
* @throws GitLabApiException if any exception occurs
*/
public List<ImpersonationToken> getImpersonationTokens(Object userIdOrUsername, ImpersonationState state) throws GitLabApiException {
public List<PersonalAccessToken> getImpersonationTokens(Object userIdOrUsername, ImpersonationState state) throws GitLabApiException {
GitLabApiForm formData = new GitLabApiForm()
.withParam("state", state)
.withParam(PER_PAGE_PARAM, getDefaultPerPage());
Response response = get(Response.Status.OK, formData.asMap(), "users", getUserIdOrUsername(userIdOrUsername), "impersonation_tokens");
return (response.readEntity(new GenericType<List<ImpersonationToken>>() {}));
return (response.readEntity(new GenericType<List<PersonalAccessToken>>() {}));
}

/**
Expand All @@ -861,14 +861,14 @@ public List<ImpersonationToken> getImpersonationTokens(Object userIdOrUsername,
* @return the specified impersonation token
* @throws GitLabApiException if any exception occurs
*/
public ImpersonationToken getImpersonationToken(Object userIdOrUsername, Integer tokenId) throws GitLabApiException {
public PersonalAccessToken getImpersonationToken(Object userIdOrUsername, Integer tokenId) throws GitLabApiException {

if (tokenId == null) {
throw new RuntimeException("tokenId cannot be null");
}

Response response = get(Response.Status.OK, null, "users", getUserIdOrUsername(userIdOrUsername), "impersonation_tokens", tokenId);
return (response.readEntity(ImpersonationToken.class));
return (response.readEntity(PersonalAccessToken.class));
}

/**
Expand All @@ -880,7 +880,7 @@ public ImpersonationToken getImpersonationToken(Object userIdOrUsername, Integer
* @param tokenId the impersonation token ID to get
* @return the specified impersonation token as an Optional instance
*/
public Optional<ImpersonationToken> getOptionalImpersonationToken(Object userIdOrUsername, Integer tokenId) {
public Optional<PersonalAccessToken> getOptionalImpersonationToken(Object userIdOrUsername, Integer tokenId) {
try {
return (Optional.ofNullable(getImpersonationToken(userIdOrUsername, tokenId)));
} catch (GitLabApiException glae) {
Expand All @@ -897,25 +897,11 @@ public Optional<ImpersonationToken> getOptionalImpersonationToken(Object userIdO
* @param name the name of the impersonation token, required
* @param expiresAt the expiration date of the impersonation token, optional
* @param scopes an array of scopes of the impersonation token
* @return the created ImpersonationToken instance
* @return the created PersonalAccessToken instance
* @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));
public PersonalAccessToken createImpersonationToken(Object userIdOrUsername, String name, Date expiresAt, Scope[] scopes) throws GitLabApiException {
return createPersonalAccessTokenOrImpersonationToken(userIdOrUsername, name, expiresAt, scopes, true);
}

/**
Expand All @@ -937,6 +923,43 @@ public void revokeImpersonationToken(Object userIdOrUsername, Integer tokenId) t
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 PersonalAccessToken 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 PersonalAccessToken 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(PersonalAccessToken.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 @@ -9,12 +9,12 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

public class ImpersonationToken {
public class PersonalAccessToken {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming the class like this is a breaking change for the API consumer.


/** Enum to specify the scope of an ImpersonationToken. */
/** Enum to specify the scope of a PersonalAccessToken. */
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
4 changes: 2 additions & 2 deletions src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
import org.gitlab4j.api.models.GpgSignature;
import org.gitlab4j.api.models.Group;
import org.gitlab4j.api.models.HealthCheckInfo;
import org.gitlab4j.api.models.ImpersonationToken;
import org.gitlab4j.api.models.PersonalAccessToken;
import org.gitlab4j.api.models.ImportStatus;
import org.gitlab4j.api.models.Issue;
import org.gitlab4j.api.models.IssueLink;
Expand Down Expand Up @@ -671,7 +671,7 @@ public void testUser() throws Exception {

@Test
public void testImpersonationToken() throws Exception {
ImpersonationToken token = unmarshalResource(ImpersonationToken.class, "impersonation-token.json");
PersonalAccessToken token = unmarshalResource(PersonalAccessToken.class, "impersonation-token.json");
assertTrue(compareJson(token, "impersonation-token.json"));
}

Expand Down
62 changes: 47 additions & 15 deletions src/test/java/org/gitlab4j/api/TestUserApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import javax.ws.rs.core.Response;

import org.gitlab4j.api.models.Email;
import org.gitlab4j.api.models.ImpersonationToken;
import org.gitlab4j.api.models.ImpersonationToken.Scope;
import org.gitlab4j.api.models.PersonalAccessToken;
import org.gitlab4j.api.models.PersonalAccessToken.Scope;
import org.gitlab4j.api.models.SshKey;
import org.gitlab4j.api.models.User;
import org.gitlab4j.api.models.Version;
Expand Down Expand Up @@ -56,7 +56,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 @@ -268,12 +269,12 @@ 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.
Scope[] scopes = {Scope.API, Scope.READ_USER, Scope.READ_REPOSITORY, Scope.WRITE_REPOSITORY, Scope.SUDO};
// 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");

ImpersonationToken token = null;
PersonalAccessToken token = null;
try {

token = gitLabApi.getUserApi().createImpersonationToken(user, TEST_IMPERSONATION_TOKEN_NAME, expiresAt, scopes);
Expand All @@ -299,13 +300,13 @@ public void testGetOptionalImpersonationToken() throws GitLabApiException, Parse
Scope[] scopes = {Scope.API, Scope.READ_USER};
Date expiresAt = ISO8601.toDate("2018-01-01T00:00:00Z");

ImpersonationToken token = null;
PersonalAccessToken token = null;
try {

token = gitLabApi.getUserApi().createImpersonationToken(user.getId(), TEST_IMPERSONATION_TOKEN_NAME, expiresAt, scopes);
assertNotNull(token);

Optional<ImpersonationToken> optional = gitLabApi.getUserApi().getOptionalImpersonationToken(user.getId(), token.getId());
Optional<PersonalAccessToken> optional = gitLabApi.getUserApi().getOptionalImpersonationToken(user.getId(), token.getId());
assertTrue(optional.isPresent());
assertEquals(token.getId(), optional.get().getId());
gitLabApi.getUserApi().revokeImpersonationToken(user.getId(), token.getId());
Expand All @@ -327,32 +328,32 @@ public void testGetImpersonationTokens() throws GitLabApiException, ParseExcepti
User user = gitLabApi.getUserApi().getCurrentUser();
Scope[] scopes = {Scope.API, Scope.READ_USER};
Date expiresAt = ISO8601.toDate("2018-01-01T00:00:00Z");
ImpersonationToken createdToken = gitLabApi.getUserApi().createImpersonationToken(user.getId(), TEST_IMPERSONATION_TOKEN_NAME, expiresAt, scopes);
PersonalAccessToken createdToken = gitLabApi.getUserApi().createImpersonationToken(user.getId(), TEST_IMPERSONATION_TOKEN_NAME, expiresAt, scopes);
assertNotNull(createdToken);

ImpersonationToken token = gitLabApi.getUserApi().getImpersonationToken(user.getId(), createdToken.getId());
PersonalAccessToken token = gitLabApi.getUserApi().getImpersonationToken(user.getId(), createdToken.getId());
assertNotNull(token);
assertEquals(createdToken.getId(), token.getId());
assertEquals(TEST_IMPERSONATION_TOKEN_NAME, token.getName());
assertEquals(createdToken.getExpiresAt(), token.getExpiresAt());

List<ImpersonationToken> tokens = gitLabApi.getUserApi().getImpersonationTokens(user.getId());
List<PersonalAccessToken> tokens = gitLabApi.getUserApi().getImpersonationTokens(user.getId());
assertNotNull(tokens);
assertTrue(tokens.size() > 0);

gitLabApi.getUserApi().revokeImpersonationToken(user.getId(), createdToken.getId());
}

@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};
Date expiresAt = ISO8601.toDate("2018-01-01T00:00:00Z");
ImpersonationToken createdToken = gitLabApi.getUserApi().createImpersonationToken(user.getId(), TEST_IMPERSONATION_TOKEN_NAME + "a", expiresAt, scopes);
PersonalAccessToken createdToken = gitLabApi.getUserApi().createImpersonationToken(user.getId(), TEST_IMPERSONATION_TOKEN_NAME + "a", expiresAt, scopes);
assertNotNull(createdToken);

ImpersonationToken token = gitLabApi.getUserApi().getImpersonationToken(user.getId(), createdToken.getId());
PersonalAccessToken token = gitLabApi.getUserApi().getImpersonationToken(user.getId(), createdToken.getId());
assertNotNull(token);
assertEquals(createdToken.getId(), token.getId());

Expand All @@ -361,6 +362,37 @@ 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");

PersonalAccessToken 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