diff --git a/src/main/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResource.java b/src/main/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResource.java index a1aba70..8335a8d 100644 --- a/src/main/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResource.java +++ b/src/main/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResource.java @@ -15,7 +15,16 @@ */ package org.commonjava.indy.service.ui.jaxrs.auth; +import io.quarkus.security.identity.SecurityIdentity; +import org.apache.commons.lang3.StringUtils; +import org.commonjava.indy.service.ui.models.auth.UserInfo; import org.eclipse.microprofile.jwt.JsonWebToken; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.ws.rs.GET; @@ -26,13 +35,21 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; +import java.security.Principal; +import java.util.Collections; +import java.util.Set; @Path( "/api/admin/auth" ) public class AuthResource { + private final Logger logger = LoggerFactory.getLogger( this.getClass() ); + @Inject JsonWebToken accessToken; + @Inject + SecurityIdentity identity; + @Path( "accesstoken" ) @GET @Produces( MediaType.TEXT_HTML ) @@ -57,4 +74,28 @@ public Response getAccessToken( @Context UriInfo uriInfo ) .append( "" ); return Response.ok( contentBuilder.toString() ).build(); } + + @APIResponses( { @APIResponse( responseCode = "200", + content = @Content( schema = @Schema( implementation = UserInfo.class ) ), + description = "Return the current user information" ), + @APIResponse( responseCode = "401", description = "User not authenticated" ) } ) + @Path( "userinfo" ) + @GET + @Produces( MediaType.APPLICATION_JSON ) + public Response getUserInfo( @Context UriInfo uriInfo ) + { + Set roles = identity.getRoles() == null ? Collections.emptySet() : identity.getRoles(); + Principal user = identity.getPrincipal(); + if ( user != null && StringUtils.isNotBlank( user.getName() ) ) + { + logger.debug( "User: {}", user.getName() ); + final UserInfo userInfo = new UserInfo( user.getName(), roles ); + return Response.ok( userInfo ).build(); + } + else + { + logger.warn( "User name is not got correctly, please check the security configuration." ); + return Response.status( Response.Status.UNAUTHORIZED ).build(); + } + } } diff --git a/src/main/java/org/commonjava/indy/service/ui/models/auth/UserInfo.java b/src/main/java/org/commonjava/indy/service/ui/models/auth/UserInfo.java new file mode 100644 index 0000000..93f8436 --- /dev/null +++ b/src/main/java/org/commonjava/indy/service/ui/models/auth/UserInfo.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed 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 + * + * http://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 org.commonjava.indy.service.ui.models.auth; + +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +import java.util.Set; + +@Schema( description = "The user information. Contains the user name and user roles" ) +public class UserInfo +{ + @Schema( description = "User name for current user" ) + private final String userName; + + @Schema( description = "User roles for current user" ) + private final Set roles; + + public UserInfo( String userName, Set roles ) + { + this.userName = userName; + this.roles = roles; + } + + public String getUserName() + { + return userName; + } + + public Set getRoles() + { + return roles; + } +} diff --git a/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResourceTest.java b/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResourceTest.java new file mode 100644 index 0000000..194961f --- /dev/null +++ b/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthResourceTest.java @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed 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 + * + * http://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 org.commonjava.indy.service.ui.jaxrs.auth; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.quarkus.test.security.TestSecurity; +import io.restassured.path.json.JsonPath; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.core.Response; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@QuarkusTest +@TestProfile( AuthTestProfile.class ) +public class AuthResourceTest +{ + @TestSecurity( roles = { "power", "admin" }, user = "user" ) + @Test + public void testGetUserInfo() + { + given().when().get( "/api/admin/auth/userinfo" ).then().statusCode( Response.Status.OK.getStatusCode() ); + final JsonPath resultPath = given().get( "/api/admin/auth/userinfo" ).thenReturn().jsonPath(); + assertThat( resultPath.getString( "userName" ), is( "user" ) ); + assertThat( resultPath.getInt( "roles.size" ), is( 2 ) ); + assertThat( resultPath.getList( "roles" ), hasItems( "power", "admin" ) ); + } +} diff --git a/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthTestProfile.java b/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthTestProfile.java new file mode 100644 index 0000000..d830b00 --- /dev/null +++ b/src/test/java/org/commonjava/indy/service/ui/jaxrs/auth/AuthTestProfile.java @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed 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 + * + * http://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 org.commonjava.indy.service.ui.jaxrs.auth; + +import io.quarkus.test.junit.QuarkusTestProfile; + +import java.util.HashMap; +import java.util.Map; + +public class AuthTestProfile + implements QuarkusTestProfile +{ + @Override + public Map getConfigOverrides() + { + Map configs = new HashMap<>(); + configs.put( "quarkus.oidc.enabled", "true" ); + configs.put( "quarkus.oidc.auth-server-url", "http://localhost:8180/realms/test" ); + return configs; + } +}