ch4mpy / spring-addons

Ease spring OAuth2 resource-servers configuration and testing
Apache License 2.0
521 stars 84 forks source link

`@WithOidcLogin` using json file similarly as `@WithJwt` #211

Closed ffroliva closed 3 months ago

ffroliva commented 3 months ago

I would like to use @WithOidcLogin in the same manner as @WithJwt as I feel it is more intuitive in certain usecases.

As this approach currently doesn't exist, is there an example of how to customize @WithOidcLogin? Maybe a Javadoc with an example of usage could be added to the interface following the approach taken in WithJwt. I feel it would facilitate for newcomers.

Thank you for such a great library!

ch4mpy commented 3 months ago

What is your use case for needing to configure more than authorities on an OAuth2 client?

Configuring an OAuth2AuthenticationToken from claims would require the test Authentication factory to scan the application context for potentially customized OAuth2UserService and GrantedAuthoritiesMapper. For that, some test configuration has to be imported, which complicates usage in parameterized test or when spring-addons is not involved. So, if something like that would be done, it should probably be with another annotation.

ffroliva commented 3 months ago

How about adding an example of usage of the annotation as javadocs, for example:

@WithOidcLogin(
        authorities = {"ROLE_ADMINISTRATOR"},
        claims = @OpenIdClaims(
                otherClaims = @Claims(
                        stringClaims = @StringClaim(name = "preferred_username", value = "admin"),
                        stringArrayClaims = @StringArrayClaim(name = "group", value = {"Administrator"}))))
@Test
void testAdminUserAuthenticated() {
...
}
ch4mpy commented 3 months ago

Sure, adding Javadoc is possible, but this does not answer my question...

ffroliva commented 3 months ago

Sorry for not answering before.

The authorities are initially mapped from groups that the user belongs to. The user can be in multiple groups at the same time but only one group can be active at a time. If the user has multiple groups assigned I need to redirect him to a group section page where a given group will be activated and a new token will be generated with a special activeGroup claim provided. Any suggestion on how to handle such a use case?

ch4mpy commented 3 months ago

Here is the draft for the Javadoc:

Populates the test security context with an OAuth2AuthenticationToken instance with a DefaultOidcUser as principal.

Only the annotation properties are used to build the authentication Instance. Neither OAuth2UserService nor GrantedAuthoritiesMapper are called.

Usage to define just authorities:

@WithOidcLogin({"BIDULE", "CHOSE"})

Advanced usage to set any claims, including private ones:

@WithOidcLogin(
   authorities = {"NICE"},
   nameAttributeKey = StandardClaimNames.PREFERRED_USERNAME,
   claims = @OpenIdClaims(
     preferredUsername = "tonton-pirate",
     email = "tonton@c4-soft.com",
     otherClaims =  @Claims(
       stringClaims = { @StringClaim(name = "machin", value = "truc") })))
ch4mpy commented 3 months ago

only one group can be active at a time

Why that? If a user is member of several groups, requesting him to manually switch between profiles to be able to do something he is allowed to seems a pretty bad user experience...

a new token will be generated with a special activeGroup claim provided

This means logout and then login (again, pretty bad UX)

Also, issuing tokens is the job of the authorization server, when keeping the information about this activeGroup is probably the job of a resource server and redirections the job of the client. This makes the solution pretty complicated (you'll have to expose an endpoint on the resource server for the authorization server to query for the user's active group during login).

ffroliva commented 3 months ago

Here is the draft for the Javadoc:

Populates the test security context with an OAuth2AuthenticationToken instance with a DefaultOidcUser as principal.

Only the annotation properties are used to build the authentication Instance. Neither OAuth2UserService nor GrantedAuthoritiesMapper are called.

Usage to define just authorities:

@WithOidcLogin({"BIDULE", "CHOSE"})

Advanced usage to set any claims, including private ones:

@WithOidcLogin(
   authorities = {"NICE"},
   nameAttributeKey = StandardClaimNames.PREFERRED_USERNAME,
   claims = @OpenIdClaims(
     preferredUsername = "tonton-pirate",
     email = "tonton@c4-soft.com",
     otherClaims =  @Claims(
       stringClaims = { @StringClaim(name = "machin", value = "truc") })))

Looks good to me. I would probably add a few other @Claims like stringArrayClaims = @StringArrayClaim(name = "group", value = {"Administrator"})) just for the sake of showing people that there are multiple options of claim types.

Perhaps add the test method after the annotation to show where it should be used.

@WithOidcLogin(
   authorities = {"NICE"},
   nameAttributeKey = StandardClaimNames.PREFERRED_USERNAME,
   claims = @OpenIdClaims(
     preferredUsername = "tonton-pirate",
     email = "tonton@c4-soft.com",
     otherClaims =  @Claims(
       stringClaims = { @StringClaim(name = "machin", value = "truc") }),
       stringArrayClaims = @StringArrayClaim(name = "myCustomStringArrayClaim", value = {"Administrator"})))
@Test
void test() {
...
}
ch4mpy commented 3 months ago

There are way too many properties to demo it all. Also, the IDE auto completion is there too...

Released what was drafted with 7.7.0