|
| 1 | +package io.micronaut.security.authorization |
| 2 | + |
| 3 | +import io.micronaut.context.annotation.Requires |
| 4 | +import io.micronaut.http.HttpRequest |
| 5 | +import io.micronaut.http.MediaType |
| 6 | +import io.micronaut.http.annotation.Controller |
| 7 | +import io.micronaut.http.annotation.Get |
| 8 | +import io.micronaut.http.annotation.Produces |
| 9 | +import io.micronaut.security.MockAuthenticationProvider |
| 10 | +import io.micronaut.security.SuccessAuthenticationScenario |
| 11 | +import io.micronaut.security.annotation.Secured |
| 12 | +import io.micronaut.security.authentication.Authentication |
| 13 | +import io.micronaut.security.testutils.EmbeddedServerSpecification |
| 14 | +import io.micronaut.security.token.RolesFinder |
| 15 | +import io.micronaut.security.utils.DefaultSecurityService |
| 16 | +import io.micronaut.security.utils.SecurityService |
| 17 | +import jakarta.inject.Singleton |
| 18 | + |
| 19 | +import java.security.Principal |
| 20 | + |
| 21 | +class SecuredRolesCaseInsensitiveConfigurationSpec extends EmbeddedServerSpecification { |
| 22 | + |
| 23 | + @Override |
| 24 | + String getSpecName() { |
| 25 | + 'SecuredRolesCaseInsensitiveConfigurationSpec' |
| 26 | + } |
| 27 | + |
| 28 | + @Override |
| 29 | + Map<String, Object> getConfiguration() { |
| 30 | + super.configuration + ['micronaut.security.roles-case-sensitive': false] |
| 31 | + } |
| 32 | + |
| 33 | + void "@Secured annotation value can be case insensitive"() { |
| 34 | + when: |
| 35 | + client.exchange(HttpRequest.GET("/uppercase").basicAuth('user', 'password'), String) |
| 36 | + |
| 37 | + then: |
| 38 | + noExceptionThrown() |
| 39 | + |
| 40 | + when: |
| 41 | + client.exchange(HttpRequest.GET("/lowercase").basicAuth('user', 'password'), String) |
| 42 | + |
| 43 | + then: |
| 44 | + noExceptionThrown() |
| 45 | + } |
| 46 | + |
| 47 | + void "SecurityService::hasRole can be case insensitive"() { |
| 48 | + when: |
| 49 | + Authentication authentication = Authentication.build("sherlock", ["ROLE_DETECTIVE"]) |
| 50 | + SecurityService securityService = new CustomSecurityService(applicationContext.getBean(RolesFinder), authentication) |
| 51 | + |
| 52 | + then: |
| 53 | + securityService.hasRole('ROLE_DETECTIVE') |
| 54 | + |
| 55 | + and: |
| 56 | + securityService.hasRole('role_detective') |
| 57 | + } |
| 58 | + |
| 59 | + @Requires(property = 'spec.name', value = 'SecuredRolesCaseInsensitiveConfigurationSpec') |
| 60 | + @Controller |
| 61 | + static class RolesCaseInsensitiveController { |
| 62 | + |
| 63 | + @Produces(MediaType.TEXT_PLAIN) |
| 64 | + @Secured(["role_user"]) |
| 65 | + @Get("/lowercase") |
| 66 | + String lowercase(Principal principal) { |
| 67 | + principal.name |
| 68 | + } |
| 69 | + |
| 70 | + @Produces(MediaType.TEXT_PLAIN) |
| 71 | + @Secured(["ROLE_USER"]) |
| 72 | + @Get("/uppercase") |
| 73 | + String uppercase(Principal principal) { |
| 74 | + principal.name |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + @Singleton |
| 79 | + @Requires(property = 'spec.name', value = 'SecuredRolesCaseInsensitiveConfigurationSpec') |
| 80 | + static class AuthenticationProviderUserPassword extends MockAuthenticationProvider { |
| 81 | + AuthenticationProviderUserPassword() { |
| 82 | + super([new SuccessAuthenticationScenario('user', ['ROLE_USER'])]) |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + @Requires(property = 'spec.name', value = 'SecuredRolesCaseInsensitiveConfigurationSpec') |
| 87 | + static class CustomSecurityService extends DefaultSecurityService { |
| 88 | + |
| 89 | + Authentication authentication |
| 90 | + |
| 91 | + CustomSecurityService(RolesFinder rolesFinder, Authentication authentication) { |
| 92 | + super(rolesFinder) |
| 93 | + this.authentication = authentication |
| 94 | + } |
| 95 | + |
| 96 | + @Override |
| 97 | + Optional<Authentication> getAuthentication() { |
| 98 | + Optional.of(authentication) |
| 99 | + } |
| 100 | + } |
| 101 | +} |
0 commit comments