Skip to content

Commit

Permalink
Merge branch 'main' into update-armeria-version
Browse files Browse the repository at this point in the history
  • Loading branch information
minwoox authored Dec 8, 2023
2 parents ddd1c0e + 2b07420 commit 1b530e8
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.MediaType;
import com.linecorp.armeria.common.auth.OAuth2Token;
import com.linecorp.armeria.common.auth.AuthToken;
import com.linecorp.centraldogma.internal.Jackson;
import com.linecorp.centraldogma.internal.api.v1.AccessToken;
import com.linecorp.centraldogma.server.CentralDogmaBuilder;
Expand Down Expand Up @@ -57,7 +57,7 @@ void createNonRandomToken() throws Exception {
final String sessionId = Jackson.readValue(response.content().array(), AccessToken.class)
.accessToken();
final WebClient adminClient = WebClient.builder(client.uri())
.auth(OAuth2Token.of(sessionId)).build();
.auth(AuthToken.ofOAuth2(sessionId)).build();

final HttpRequest request = HttpRequest.builder()
.post("/api/v1/tokens")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import com.linecorp.armeria.common.AggregatedHttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.SessionProtocol;
import com.linecorp.armeria.common.auth.OAuth2Token;
import com.linecorp.armeria.common.auth.AuthToken;
import com.linecorp.centraldogma.client.CentralDogma;
import com.linecorp.centraldogma.client.armeria.ArmeriaCentralDogmaBuilder;
import com.linecorp.centraldogma.internal.Jackson;
Expand Down Expand Up @@ -92,7 +92,7 @@ void setUp() throws IOException {
getSessionId(port1, TestAuthMessageUtil.USERNAME, TestAuthMessageUtil.PASSWORD);

webClient = WebClient.builder("http://127.0.0.1:" + port1)
.auth(OAuth2Token.of(adminSessionId))
.auth(AuthToken.ofOAuth2(adminSessionId))
.build();
dogmaClient = new ArmeriaCentralDogmaBuilder()
.accessToken(adminSessionId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.common.AggregatedHttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.auth.OAuth2Token;
import com.linecorp.armeria.common.auth.AuthToken;
import com.linecorp.centraldogma.client.CentralDogma;
import com.linecorp.centraldogma.client.armeria.ArmeriaCentralDogmaBuilder;
import com.linecorp.centraldogma.internal.Jackson;
Expand Down Expand Up @@ -61,7 +61,7 @@ void setUp() throws JsonProcessingException, UnknownHostException {
final URI uri = dogma.httpClient().uri();

webClient = WebClient.builder(uri)
.auth(OAuth2Token.of(adminSessionId))
.auth(AuthToken.ofOAuth2(adminSessionId))
.build();
dogmaClient = new ArmeriaCentralDogmaBuilder()
.accessToken(adminSessionId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import com.linecorp.centraldogma.server.metadata.MetadataService;
import com.linecorp.centraldogma.server.metadata.MetadataServiceInjector;
import com.linecorp.centraldogma.server.metadata.Permission;
import com.linecorp.centraldogma.server.metadata.ProjectRole;
import com.linecorp.centraldogma.server.metadata.User;
import com.linecorp.centraldogma.server.storage.project.Project;

Expand All @@ -65,37 +64,13 @@ public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exc
final String repoName = ctx.pathParam("repoName");
checkArgument(!isNullOrEmpty(repoName), "no repository name is specified");

if (Project.isReservedRepoName(repoName)) {
return serveInternalRepo(ctx, req, mds, user, projectName, repoName);
} else {
return serveUserRepo(ctx, req, mds, user, projectName, repoName);
}
}

private HttpResponse serveInternalRepo(ServiceRequestContext ctx, HttpRequest req,
MetadataService mds, User user,
String projectName, String repoName) throws Exception {
if (user.isAdmin()) {
return unwrap().serve(ctx, req);
}
if (Project.REPO_DOGMA.equals(repoName)) {
return throwForbiddenResponse(ctx, projectName, repoName, "administrator");
}
assert Project.REPO_META.equals(repoName);

return HttpResponse.from(mds.findRole(projectName, user).handle((role, cause) -> {
if (cause != null) {
return handleException(ctx, cause);
if (!user.isAdmin()) {
return throwForbiddenResponse(ctx, projectName, repoName, "administrator");
}
if (role != ProjectRole.OWNER) {
return throwForbiddenResponse(ctx, projectName, repoName, "owner");
}
try {
return unwrap().serve(ctx, req);
} catch (Exception e) {
return Exceptions.throwUnsafely(e);
}
}));
return unwrap().serve(ctx, req);
}
return serveUserRepo(ctx, req, mds, user, projectName, repoName);
}

private static HttpResponse throwForbiddenResponse(ServiceRequestContext ctx, String projectName,
Expand All @@ -115,7 +90,7 @@ private HttpResponse serveUserRepo(ServiceRequestContext ctx, HttpRequest req,
return handleException(ctx, cause);
}

return HttpResponse.from(f.handle((permission, cause) -> {
return HttpResponse.of(f.handle((permission, cause) -> {
if (cause != null) {
return handleException(ctx, cause);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.linecorp.centraldogma.server.metadata;

import static com.linecorp.centraldogma.internal.api.v1.HttpApiV1Constants.PROJECTS_PREFIX;
import static com.linecorp.centraldogma.testing.internal.auth.TestAuthMessageUtil.login;
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.common.AggregatedHttpResponse;
import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpMethod;
import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.MediaType;
import com.linecorp.armeria.common.RequestHeaders;
import com.linecorp.armeria.common.auth.AuthToken;
import com.linecorp.centraldogma.internal.Jackson;
import com.linecorp.centraldogma.internal.api.v1.AccessToken;
import com.linecorp.centraldogma.server.CentralDogmaBuilder;
import com.linecorp.centraldogma.testing.internal.auth.TestAuthMessageUtil;
import com.linecorp.centraldogma.testing.internal.auth.TestAuthProviderFactory;
import com.linecorp.centraldogma.testing.junit.CentralDogmaExtension;

class MetadataApiServiceTest {

@RegisterExtension
static CentralDogmaExtension dogma = new CentralDogmaExtension() {

@Override
protected void configure(CentralDogmaBuilder builder) {
builder.administrators(TestAuthMessageUtil.USERNAME);
builder.authProviderFactory(new TestAuthProviderFactory());
}
};

@Test
void grantPermissionToMemberForMetaRepository() throws Exception {
final String projectName = "foo_proj";
final WebClient client = dogma.httpClient();
final AggregatedHttpResponse response = login(client,
TestAuthMessageUtil.USERNAME,
TestAuthMessageUtil.PASSWORD);

assertThat(response.status()).isEqualTo(HttpStatus.OK);
final String sessionId = Jackson.readValue(response.content().array(), AccessToken.class)
.accessToken();
final WebClient adminClient = WebClient.builder(client.uri())
.auth(AuthToken.ofOAuth2(sessionId)).build();
final RequestHeaders headers = RequestHeaders.of(HttpMethod.POST, PROJECTS_PREFIX,
HttpHeaderNames.CONTENT_TYPE, MediaType.JSON);
final String body = "{\"name\": \"" + projectName + "\"}";
// Create a project.
assertThat(adminClient.execute(headers, body).aggregate().join().status()).isSameAs(HttpStatus.CREATED);

final String memberToken = "appToken-secret-member";
// Create a token with a non-random secret.
HttpRequest request = HttpRequest.builder()
.post("/api/v1/tokens")
.content(MediaType.FORM_DATA,
"secret=" + memberToken + "&isAdmin=false&appId=foo")
.build();
AggregatedHttpResponse res = adminClient.execute(request).aggregate().join();
assertThat(res.status()).isEqualTo(HttpStatus.CREATED);
res = adminClient.get("/api/v1/tokens").aggregate().join();
assertThat(res.contentUtf8()).contains("\"secret\":\"" + memberToken + '"');

// Add as a member to the project
request = HttpRequest.builder()
.post("/api/v1/metadata/" + projectName + "/tokens")
.content(MediaType.JSON,
'{' +
"\"id\":\"foo\"," +
"\"role\":\"MEMBER\"" +
'}')
.build();
res = adminClient.execute(request).aggregate().join();
assertThat(res.status()).isSameAs(HttpStatus.OK);

final WebClient memberClient = WebClient.builder(client.uri())
.auth(AuthToken.ofOAuth2(memberToken)).build();
res = memberClient.get("/api/v1/projects/" + projectName + "/repos/meta/list").aggregate().join();
// A member isn't allowed to access the meta repository yet.
assertThat(res.status()).isSameAs(HttpStatus.FORBIDDEN);
assertThat(res.contentUtf8()).contains("You must have READ permission for repository");

// Grant a READ permission to the member.
request = HttpRequest.builder()
.post("/api/v1/metadata/" + projectName + "/repos/meta/perm/role")
.content(MediaType.JSON,
"{\n" +
" \"owner\": [ \"READ\", \"WRITE\" ],\n" +
" \"member\": [ \"READ\" ],\n" +
" \"guest\": [ ]\n" +
'}')
.build();
adminClient.execute(request).aggregate().join();

// Now the member can access the meta repository.
res = memberClient.get("/api/v1/projects/" + projectName + "/repos/meta/list").aggregate().join();
assertThat(res.status()).isSameAs(HttpStatus.NO_CONTENT);
}
}

0 comments on commit 1b530e8

Please sign in to comment.