The official Micronaut security solution.
See the Documentation for more information.
./gradlew -Dgeb.env=firefox build
The official Micronaut security solution
License: Apache License 2.0
The official Micronaut security solution.
See the Documentation for more information.
./gradlew -Dgeb.env=firefox build
Spelling mistake. See https://www.keycloak.org/
Feature Request
When I use an access token directly in the Authorization Header with Scheme Bearer
, I get a 401 response.
Is there a mechanism I can configure for Resource Server?
Micronaut Security: 1.2.0
OS: Windows: 10
JDK: 11
While securing some endpoints I noticed that due to the implementation of the SecuredAnnotationRule within the following code snippet, the @permitAll annotation will yield a 403 Forbidden response:
@Override public SecurityRuleResult check(HttpRequest request, @Nullable RouteMatch routeMatch, @Nullable Map<String, Object> claims) {
if (routeMatch instanceof MethodBasedRouteMatch) {
MethodBasedRouteMatch methodRoute = ((MethodBasedRouteMatch) routeMatch);
if (methodRoute.hasAnnotation(Secured.class)) {
Optional<String[]> optionalValue = methodRoute.getValue(Secured.class, String[].class);
if (optionalValue.isPresent()) {
List<String> values = Arrays.asList(optionalValue.get());
if (values.contains(SecurityRule.DENY_ALL)) {
return SecurityRuleResult.REJECTED;
}
return compareRoles(values, getRoles(claims));
}
}
}
return SecurityRuleResult.UNKNOWN;
}
The guide available at https://micronaut-projects.github.io/micronaut-security/latest/guide/ denotes that use of these JSR-250 (https://jcp.org/en/jsr/detail?id=250) annotations should be working, so either this functionality should be updated, or the documentation should be removed.
use multitenancy and configuration:micronaut-multitenancy-gorm
compile 'io.micronaut:micronaut-multitenancy'
compile "io.micronaut.configuration:micronaut-multitenancy-gorm"
i my custom
class ZysoftSecuredAnnotationRule implements SecurityRule {
@Inject
TenantResolver tenantResolver
}
then
tenantResolver.resolveTenantIdentifier() throw exception
Tenant could not be resolved outside a web request
i just create a demo project
When access token is opaque (which is assumed by OpenID Connect spec) it can be validated by resource server using token introspection endpoint.
https://tools.ietf.org/html/rfc7662
Related to #650
@Error(status = HttpStatus.NOT_FOUND, global = true)
micronaut.security.enabled: true
@Secured(Role.ROLE_CONNECT_READ)
@Controller("/{cluster}/connect")
public class ConnectController {
/test/connect/bla
micronaut.security.enabled: false
/test/connect/bla
Security should not change the behavior off 404 page and must be check before security for some use case.
The best will be to let user have an option to allow choose if you you want to have a 404 or a unauthorized response.
I think the better option is to allow 404 before unauthorized if the ErrorController is annotated with : @Secured(SecurityRule.IS_ANONYMOUS)
Full source code is here on branch dev
Is it possible to setup access to service based on IP only (using ip-patterns), without setting up any security providers?
Given the tests below, if it passes the ip-patterns, it is still failing with No rule provider authorized or rejected the request.
If it fails the ip-patterns, you get The rule provider io.micronaut.security.rules.IpPatternsRule rejected the request.
So based on the tests below, i know the ip-pattern rule is working. Are there any other configurations needed to just protect the endpoint based the the client IP?
Looking at the IpPattern code, when it passes the ip-pattern rule, it seem to always to return SecurityRuleResult.UNKNOWN
public SecurityRuleResult check(HttpRequest request, @Nullable RouteMatch routeMatch, @Nullable Map<String, Object> claims) {
if (patternList.isEmpty()) {
return SecurityRuleResult.UNKNOWN;
} else {
if (patternList.stream().anyMatch(pattern ->
pattern.pattern().equals(SecurityConfigurationProperties.ANYWHERE) ||
pattern.matcher(request.getRemoteAddress().getAddress().getHostAddress()).matches())) {
return SecurityRuleResult.UNKNOWN;
} else {
return SecurityRuleResult.REJECTED;
}
}
}
Secenario: Testing from 127.0.0.1, results in log entries below.
micronaut:
application:
name: test-app
security:
enabled: true
ip-patterns:
- '127.0.0.1'
15:41:37.320 [pool-1-thread-7] DEBUG i.m.security.filters.SecurityFilter - Failure to authenticate request. GET /test.
15:41:37.324 [pool-1-thread-7] DEBUG i.m.security.filters.SecurityFilter - Authorized request GET /test. No rule provider authorized or rejected the request.
Secenario: Testing from 127.0.0.1, results in log entries below.
micronaut:
application:
name: test-app
security:
enabled: true
ip-patterns:
- '198.1.1.1'
15:46:58.376 [pool-1-thread-4] DEBUG i.m.security.filters.SecurityFilter - Failure to authenticate request. GET /test.
15:46:58.381 [pool-1-thread-4] DEBUG i.m.security.filters.SecurityFilter - Unauthorized request GET /test. The rule provider io.micronaut.security.rules.IpPatternsRule rejected the request.
I have a custom annotation "Managed" that wants to check for the SecurityService to perform some extra logic.
Here is the source of the annotation:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Around
@Type(ManagedAdvice.class)
public @interface Managed {
}
The advice that is executed looks like this:
@Singleton
@Requires(classes = SecurityService.class)
public class ManagedAdvice implements MethodInterceptor<Object, Object> {
@Inject
SecurityService securityService;
@Inject
Connection natsConnection;
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
// ...
and example usage of this annotation is as follows:
@Managed
@View("callboard/home")
@Get("/")
public HttpResponse home() {
// ...
Anyone has a clue as to why this bean would not be found during runtime?
Here is the stack-trace for the error-message:
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [securityService] of class: customProject.advice.ManagedAdvice
Path Taken: new $CallboardControllerDefinition$Intercepted(BeanContext beanContext,[Interceptor[] interceptors]) --> ManagedAdvice.securityService
at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1354)
at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1148)
at customProject.advice.$ManagedAdviceDefinition.injectBean(Unknown Source)
at customProject.advice.$ManagedAdviceDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1494)
at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2495)
at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2395)
at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:854)
at io.micronaut.context.AbstractBeanDefinition.lambda$getBeansOfTypeForConstructorArgument$10(AbstractBeanDefinition.java:1088)
at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1697)
at io.micronaut.context.AbstractBeanDefinition.getBeansOfTypeForConstructorArgument(AbstractBeanDefinition.java:1083)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:959)
at customProject.controllers.callboard.$$CallboardControllerDefinition$InterceptedDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1494)
at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2163)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1849)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1829)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:577)
at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.getTarget(DefaultBeanContext.java:2681)
at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:2702)
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:236)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:122)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$17(RoutingInBoundHandler.java:1360)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:71)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14755)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap.subscribeActual(FlowableSwitchMap.java:49)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.micronaut.security.utils.SecurityService] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1835)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:997)
at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1346)
... 58 common frames omitted
may I ask if the lap server read timeout can be configured in the application.yml? I found a workaround way is to create my own DefaultContextBuilder as follow and add the explicit timeout value
@Singleton
@Replaces(DefaultContextBuilder.class)
public class MyDefaultContextBuilder implements ContextBuilder {
private static final Logger LOG = LoggerFactory.getLogger(RglDefaultContextBuilder.class);
@Override
public DirContext build(ContextSettings contextSettings) throws NamingException {
return build(
contextSettings.getFactory(),
contextSettings.getUrl(),
contextSettings.getDn(),
contextSettings.getPassword(),
contextSettings.getPooled());
}
@Override
public DirContext build(String factory, String server, String user, String password, boolean pooled) throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, factory);
props.put(Context.PROVIDER_URL, server);
props.put(Context.SECURITY_AUTHENTICATION, "simple");
props.put(Context.SECURITY_PRINCIPAL, user);
props.put(Context.SECURITY_CREDENTIALS, password);
// Override the lap timeout value explicitly for 5 seconds
props.put("com.sun.jndi.ldap.read.timeout", "5");
if (pooled) {
props.put("com.sun.jndi.ldap.connect.pool", "true");
}
return new InitialDirContext(props);
}
}
I'd like to authenticate on multiple realms based on the path or param.
Something like this example: https://github.com/keycloak/keycloak/tree/master/examples/multi-tenant/src/main/java/org/keycloak/example/multitenant
Discovered this during @sdelamo deep dive presentation. If you add @Secured
and @RolesAllowed
, the method will use the first annotation found. Instead, it should throw an error to let the developer know that only one annotation is supported.
Example:
@Secured(SecurityRule.IS_AUTHENTICATED)
@View("books")
@Get
@RolesAllowed("ROLE_USER")
public Map<String, Object> index() {
Map<String, Object> model = new HashMap<>();
model.put("books", Arrays.asList(new Book("1491950358", "Building Microservices"),
new Book("1680502395", "Release It!"),
new Book("0321601912", "Continuous Delivery")));
return model;
}
I want to integrate my Micronaut app with Kerberos Server (using Kerberos authentication protocol). Users should be authenticated against app by opening the URL.
User should not enter a username/password and install additional software.
Are there any activities planned in this topic?
Enabling Redis as a session cache in Micronaut does not work.
Using the code from the session guide as a starting point:
https://guides.micronaut.io/micronaut-security-session/guide/index.html
Add the following to the appplication.yml
:
session:
http:
redis:
enabled: true
write-mode: BACKGROUND
value-serializer: io.micronaut.core.serialize.JdkSerializer
redis:
uri: redis://localhost
ssl: false
Using the io.micronaut.core.serialize.JdkSerializer
you will the following exception when trying to login:
Caused by: io.micronaut.core.serialize.exceptions.SerializationException: I/O error occurred during serialization: io.micronaut.security.authentication.AuthenticationUserDetailsAdapter
at io.micronaut.core.serialize.JdkSerializer.serialize(JdkSerializer.java:62)
at io.micronaut.core.serialize.ObjectSerializer.serialize(ObjectSerializer.java:74)
at io.micronaut.configuration.lettuce.session.RedisSessionStore$RedisSession.convertAttribute(RedisSessionStore.java:726)
at io.micronaut.configuration.lettuce.session.RedisSessionStore$RedisSession.delta(RedisSessionStore.java:683)
at io.micronaut.configuration.lettuce.session.RedisSessionStore.save(RedisSessionStore.java:279)
at io.micronaut.configuration.lettuce.session.RedisSessionStore.save(RedisSessionStore.java:84)
at io.micronaut.session.http.HttpSessionFilter.lambda$null$4(HttpSessionFilter.java:134)
at io.micronaut.core.async.publisher.CompletableFuturePublisher$CompletableFutureSubscription.request(CompletableFuturePublisher.java:75)
at io.reactivex.internal.subscribers.BasicFuseableSubscriber.request(BasicFuseableSubscriber.java:153)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapInnerSubscriber.onSubscribe(FlowableSwitchMap.java:379)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onSubscribe(InstrumentedSubscriber.java:75)
at io.reactivex.internal.subscribers.BasicFuseableSubscriber.onSubscribe(BasicFuseableSubscriber.java:67)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onSubscribe(InstrumentedSubscriber.java:75)
at io.micronaut.core.async.publisher.CompletableFuturePublisher.subscribe(CompletableFuturePublisher.java:48)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
... 250 common frames omitted
Caused by: java.io.NotSerializableException: io.micronaut.security.authentication.AuthenticationUserDetailsAdapter
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at io.micronaut.core.serialize.JdkSerializer.serialize(JdkSerializer.java:58)
... 265 common frames omitted
Switching the serializer to: io.micronaut.jackson.serialize.JacksonObjectSerializer
causes a different issue. When logging in you will be redirected to the login success page but it will state you aren't logged in despite the session cookie being set.
The issue here seems to be that RedisSession
uses strings for the keys in it's atributeMap
during construction but methods such as SessionAuthenticationFetcher.fetchAuthentication
are using an object as the key when they try to look up the authentication object.
In this case: SecurityFilter.AUTHENTICATION
is being converted to "micronaut.AUTHENTICATION" and so the authentication object is not found.
Should this really just return bad request without an error message?
Whenever we refer to OAuth, we try to spell it with two capital letters and add the version – “OAuth 2.0”. This helps eliminate confusion for end users.
Feature request
It would be great if Micronaut had this out of the box with clear instructions on setting up the necessary certificate stores server-side. Especially the procedure for creating the certificate stores and configuration for complicated PKI like the US DoD's CAC cards, which have 5 root CA's and dozens of intermediate ones.
I see a lot of documentation, but none detailing how to authenticate via OAuth2 in HTTP client.
Is this planned in this library?
Or is it already implement and I just didn't find it?
Or is it already supported by existing micronaut library?
Currently the login controller makes assumptions that a successful authentication response is a UserDetails and a failed response is an AuthenticationFailed. We should remove that assumption and change the response interface to allow for handling of both types of responses. UserDetails should be an implementation detail instead of a requirement
Should be OIDC_ISSUER_*
Section https://guides.micronaut.io/micronaut-oauth2-okta/guide/index.html#oauth2
I try to test oauth2 micronaut :
But I can not include security-oauth2 by including in gradle dependencies :
compile "io.micronaut.configuration:security-oauth2:1.2.0.BUILD-SNAPSHOT"
or
compile "io.micronaut:security-oauth2:1.2.0.BUILD-SNAPSHOT"
with repository :
repositories {
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://jcenter.bintray.com" }
jcenter()
}
it's working with
annotationProcessor "io.micronaut:micronaut-security:1.2.0.BUILD-SNAPSHOT"
compile "io.micronaut:micronaut-security:1.2.0.BUILD-SNAPSHOT"
but not for oauth2... how can I do that ?
Hello, I'm trying to get a micronaut microservice working with OpenID Connect.
I managed to get the basic setup working eventually (with help of micronaut-oauth2).
But when trying to set up role-based authentication via @Secured
, I noticed that the default SecuredAnnotationRule
cannot parse roles from the JWT generated by Keycloak. It is able to get list of roles from an Iterable, but the format is:
{
"realm_access": {
"roles": [
"global_role_1"
]
},
"resource_access": {
"resource_1": {
"roles": [
"resource_specific_role_1"
]
}
}
}
Unfortunately, I cannot (simply) extend the SecuredAnnotationRule
nor the the AbstractSecurityRule
as their constructors are package-private.
Do you plan to support resource-based authorization?
Should I create an issue for this in micronaut-core?
It seems strange that the end user has to add the classes and templates in the “Denied” section (https://guides.micronaut.io/micronaut-oauth2-okta/guide/index.html#denied).
Please add Java example how to add OpenID config. I saw there is a Groovy one, but unfortunately I'm not that familiar with it. I think the same for many others.
I created an example project:
https://github.com/andcuevas/micronaut-authentication-provider-rejection
There are two authentication providers:
As the names indicate, one authenticates the user and the other doesn't.
If you run the test class micronaut.custom.authentication.FailedAuthProviderTest, the user is authenticated.
The result is the same if FailedAuthenticationProvider.authenticate() returns:
I would like to have the possibility to reject the user if one authenticator says that the authentication is invalid.
http.server
metrics with status=401
should be reported
No metrics reported for the request.
I suspect the auth handling is done before server-filters are invoked.
I have two apps running locally, an auth server;
micronaut:
application:
name: auth
security:
enabled: true
endpoints:
login:
enabled: true
path: auth/login
oauth:
enabled: true
path: auth/oauth
keys:
enabled: true
path: auth/keys
token:
jwt:
enabled: true
Which implements a custom JwkProvider
and RSASignatureGeneratorConfiguration
;
@Singleton
public class RotatingJwksProvider implements JwkProvider {
@Inject
KeyPairRepository keyPairRepository;
@Override
public List<JWK> retrieveJsonWebKeys() {
List<JWK> retval = new ArrayList<>();
List<KeyPair> keyPairs = keyPairRepository.getAll();
for (KeyPair keyPair : keyPairs) {
RSAPublicKey rsaPublicKey = keyPair.getRSAPublicKey();
RSAKey jwk = new RSAKey.Builder(rsaPublicKey)
.keyID(keyPair.getId())
.keyUse(KeyUse.SIGNATURE)
.algorithm(JWSAlgorithm.RS256)
.build();
retval.add(jwk.toPublicJWK());
}
return retval;
}
}
@Singleton
@Named("generator")
public class RotatingRSASignatureConfiguration implements RSASignatureGeneratorConfiguration {
private final KeyPairRepository keyPairRepository;
private static KeyPair keyPair = null;
@Inject
public RotatingRSASignatureConfiguration(KeyPairRepository keyPairRepository) {
this.keyPairRepository = keyPairRepository;
}
private synchronized void ensureKeyPair() {
if (keyPair == null) {
keyPair = keyPairRepository.getLatest();
}
if (keyPair == null) {
keyPair = keyPairRepository.save(KeyPair.factory());
}
}
@Override
public RSAPublicKey getPublicKey() {
ensureKeyPair();
return keyPair.getRSAPublicKey();
}
@Override
public RSAPrivateKey getPrivateKey() {
ensureKeyPair();
return keyPair.getRSAPrivateKey();
}
@Override
public JWSAlgorithm getJwsAlgorithm() {
return JWSAlgorithm.RS256;
}
}
And a client server;
micronaut:
server:
port: 8081
security:
enabled: true
endpoints:
login:
enabled: false
oauth:
enabled: false
token:
jwt:
enabled: true
signatures:
jwks:
auth:
url: "http://localhost:8080/auth/keys"
I can login to the auth server and receive a JWT token;
curl -X POST \
http://localhost:8080/auth/login \
-H 'Content-Type: application/json' \
-d '{
"username": "jamie",
"password": "xxx"
}'
{"username":"jamie","roles":["admintestrole"],"access_token":"xxx","refresh_token":"xxx","token_type":"Bearer","expires_in":3600}
And I have successfully verified the generated JWT (and public key) using jwt.io;
Header:
{
"alg": "RS256"
}
Payload:
{
"sub": "jamie",
"nbf": 1559404743,
"roles": [
"admintestrole"
],
"iss": "auth",
"exp": 1559408343,
"iat": 1559404743
}
However when I attempt to use that access token against the client service, it fails;
curl -v http://localhost:8081/jctest -H 'Authorization: Bearer xxx' -H 'Content-Type: application/json'
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8081 (#0)
> GET /jctest HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.54.0
> Accept: */*
> Authorization: Bearer xxx
> Content-Type: application/json
>
< HTTP/1.1 401 Unauthorized
< Date: Sat, 1 Jun 2019 17:02:25 GMT
< transfer-encoding: chunked
< connection: close
<
* Closing connection 0
And the following is displayed in the logs;
2019-06-01 17:52:05 DEBUG JwtTokenValidator:130 - JWT is signed
2019-06-01 17:52:05 DEBUG JwtTokenValidator:154 - No algorithms are supported
2019-06-01 17:52:05 DEBUG JwtTokenValidator:159 - No signature algorithm found for JWT: xxx
I have also confirmed the client service is accessing the keys endpoint of the auth service;
2019-06-01 17:14:48 DEBUG SecurityFilter:157 - Authorized request GET /auth/keys. The rule provider io.micronaut.security.rules.SecuredAnnotationRule authorized the request.
2019-06-01 17:14:48 DEBUG RoutingInBoundHandler:1307 - Encoding emitted response object [{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"b4224a75-a902-46ea-a4fc-23d5b14153e2","alg":"RS256","n":"1uZ7e3YPcbHFDwMSlm8CN6WH4hpA6VxIoNdfiyPL49Vww8DrInzpBDFnGlQ9kwg-5Dzif_fGXF3BI4Uxzs-lyB3GLNmNPx-MDfZL63d7PE-Ydcj4Y6xEy6siH2IyXK3WFY-s_fX8ewT1Gam0rvvcFkvuOA0voCOrnX92-LvcdGDtJbsdFskI60JLfRNiVab21T8BsrY4xw8qZeZwDgUBQyVEz38wLOi2aXy9wTI7jIDhBweEOcl6Jz2nFymEModRbdLc5gBrQ6E6KPLfiR0KaXjWuAUjhh06iN9_ureKloFQiYp3CKUcDnEhnuIr53cz42SId06cPTEvZPcplo7BIQ"}]}] using codec: io.micronaut.runtime.http.codec.TextPlainCodec@1e30a519
Is there something I have missed?
Thanks!
The scope
field of PasswordGrant
is @Nullable
but getScope()
is @Nonnull
so which is it?
Currently does this:
ctx.createBean(RxHttpClient.class, url)
should be used otherwise distributed tracing, metrics etc. is bypassed. Ideally however a shared client could be used for this case.close()
to cleanup the client in this code.When using JWT along with basic authentication method and the latter is used, the error following error message is reported in the log file:
Cannot decrypt / verify JWT: Invalid JWT serialization: Missing dot delimiter
My understanding is that MN tries to decode the Basic auth token as it were a JWT token, tehn fails and fallback on the basic auth provider.
It seems strange that a developer has to create a StateProvider, StateFilter, and StateValidator. I’d recommend these are auto-enabled somehow.
Section https://guides.micronaut.io/micronaut-oauth2-okta/guide/index.html#state
I’d recommend getting rid of the “authorization” key and just using “scopes”.
Section https://guides.micronaut.io/micronaut-oauth2-okta/guide/index.html#oauth2
The token validator should probably be a prototype bean, or perhaps not a bean at all and instead use a builder style syntax to allow for multiple types of validation in a single app. Current use case is JWT validation of OpenID tokens as well as validation of normal authorization tokens
Micronaut: 1.2.0
The bellow settings throws an Exception.
micronaut.session.http.cookie-max-age: 60
micronaut.session.http.cookie.cookie-max-age: 60s
20:33:27.966 [nioEventLoopGroup-1-18] ERROR i.m.h.s.netty.RoutingInBoundHandler - Exception occurred executing error handler. Falling back to default error handling: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.session.http.HttpSessionConfiguration
Message: Error resolving property value [micronaut.session.http.cookie-max-age]. Property doesn't exist
Path Taken: new HttpSessionFilter(SessionStore sessionStore,[HttpSessionIdResolver[] resolvers],HttpSessionIdEncoder[] encoders) --> new CookieHttpSessionStrategy([HttpSessionConfiguration configuration]) --> HttpSessionConfiguration.setCookieMaxAge([TemporalAmount cookieMaxAge])
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.session.http.HttpSessionConfiguration
Message: Error resolving property value [micronaut.session.http.cookie-max-age]. Property doesn't exist
Path Taken: new HttpSessionFilter(SessionStore sessionStore,[HttpSessionIdResolver[] resolvers],HttpSessionIdEncoder[] encoders) --> new CookieHttpSessionStrategy([HttpSessionConfiguration configuration]) --> HttpSessionConfiguration.setCookieMaxAge([TemporalAmount cookieMaxAge])
at io.micronaut.context.AbstractBeanDefinition.getValueForMethodArgument(AbstractBeanDefinition.java:773)
at io.micronaut.session.http.$HttpSessionConfigurationDefinition.injectBean(Unknown Source)
at io.micronaut.session.http.$HttpSessionConfigurationDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2248)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1917)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1892)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1021)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:985)
at io.micronaut.session.http.$CookieHttpSessionStrategyDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2581)
at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2503)
at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:870)
at io.micronaut.context.AbstractBeanDefinition.lambda$getBeansOfTypeForConstructorArgument$10(AbstractBeanDefinition.java:1092)
at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1730)
at io.micronaut.context.AbstractBeanDefinition.getBeansOfTypeForConstructorArgument(AbstractBeanDefinition.java:1087)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:959)
at io.micronaut.session.http.$HttpSessionFilterDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2248)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1917)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1892)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:582)
at io.micronaut.web.router.AnnotatedFilterRouteBuilder.lambda$process$0(AnnotatedFilterRouteBuilder.java:76)
at io.micronaut.web.router.DefaultFilterRoute.getFilter(DefaultFilterRoute.java:66)
at io.micronaut.web.router.DefaultFilterRoute.match(DefaultFilterRoute.java:82)
at io.micronaut.web.router.DefaultRouter.findFilters(DefaultRouter.java:236)
at io.micronaut.http.server.netty.RoutingInBoundHandler.filterPublisher(RoutingInBoundHandler.java:1476)
at io.micronaut.http.server.netty.RoutingInBoundHandler.exceptionCaughtInternal(RoutingInBoundHandler.java:331)
at io.micronaut.http.server.netty.RoutingInBoundHandler.exceptionCaught(RoutingInBoundHandler.java:247)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:297)
at io.netty.channel.AbstractChannelHandlerContext.notifyHandlerException(AbstractChannelHandlerContext.java:831)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:376)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:108)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:191)
at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:186)
at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:152)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:835)
20:33:27.966 [nioEventLoopGroup-1-18] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.session.http.HttpSessionConfiguration
Message: Error resolving property value [micronaut.session.http.cookie-max-age]. Property doesn't exist
Path Taken: new HttpSessionFilter(SessionStore sessionStore,[HttpSessionIdResolver[] resolvers],HttpSessionIdEncoder[] encoders) --> new CookieHttpSessionStrategy([HttpSessionConfiguration configuration]) --> HttpSessionConfiguration.setCookieMaxAge([TemporalAmount cookieMaxAge])
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.session.http.HttpSessionConfiguration
Message: Error resolving property value [micronaut.session.http.cookie-max-age]. Property doesn't exist
Path Taken: new HttpSessionFilter(SessionStore sessionStore,[HttpSessionIdResolver[] resolvers],HttpSessionIdEncoder[] encoders) --> new CookieHttpSessionStrategy([HttpSessionConfiguration configuration]) --> HttpSessionConfiguration.setCookieMaxAge([TemporalAmount cookieMaxAge])
at io.micronaut.context.AbstractBeanDefinition.getValueForMethodArgument(AbstractBeanDefinition.java:773)
at io.micronaut.session.http.$HttpSessionConfigurationDefinition.injectBean(Unknown Source)
at io.micronaut.session.http.$HttpSessionConfigurationDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2248)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1917)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1892)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1021)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:985)
at io.micronaut.session.http.$CookieHttpSessionStrategyDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2581)
at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2503)
at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:870)
at io.micronaut.context.AbstractBeanDefinition.lambda$getBeansOfTypeForConstructorArgument$10(AbstractBeanDefinition.java:1092)
at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1730)
at io.micronaut.context.AbstractBeanDefinition.getBeansOfTypeForConstructorArgument(AbstractBeanDefinition.java:1087)
at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:959)
at io.micronaut.session.http.$HttpSessionFilterDefinition.build(Unknown Source)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1535)
at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2248)
at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1917)
at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1892)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:582)
at io.micronaut.web.router.AnnotatedFilterRouteBuilder.lambda$process$0(AnnotatedFilterRouteBuilder.java:76)
at io.micronaut.web.router.DefaultFilterRoute.getFilter(DefaultFilterRoute.java:66)
at io.micronaut.web.router.DefaultFilterRoute.match(DefaultFilterRoute.java:82)
at io.micronaut.web.router.DefaultRouter.findFilters(DefaultRouter.java:236)
at io.micronaut.http.server.netty.RoutingInBoundHandler.filterPublisher(RoutingInBoundHandler.java:1476)
at io.micronaut.http.server.netty.RoutingInBoundHandler.exceptionCaughtInternal(RoutingInBoundHandler.java:331)
at io.micronaut.http.server.netty.RoutingInBoundHandler.exceptionCaught(RoutingInBoundHandler.java:247)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:297)
at io.netty.channel.AbstractChannelHandlerContext.notifyHandlerException(AbstractChannelHandlerContext.java:831)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:376)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:108)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:191)
at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:186)
at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:152)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:835)
Environment:
OS: MacOS 10.14.6
JDK: jdk12
Micronaut: 1.2.0
Remove the RejectionHandler interface entirely and throw an exception instead. This can then be handled with an ExceptionHandler or a global/local error handler.
Micronaut: 1.1.0
The bellow settings throws an Exception.
micronaut.security.token.jwt.cookie.cookie-max-age: 86400
micronaut.security.token.jwt.cookie.cookie-max-age: 86400s
Debugging, DefaultConversionService didn't find a TypeConverter that for String -> TemporalAmount.
09:01:35.756 [nioEventLoopGroup-1-2] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.security.token.jwt.cookie.JwtCookieConfigurationProperties
Message: Error resolving property value [micronaut.security.token.jwt.cookie.cookie-max-age]. Property doesn't exist
Path Taken: new SecurityFilter(Collection securityRules,[Collection authenticationFetchers],RejectionHandler rejectionHandler,SecurityFilterOrderProvider securityFilterOrderProvider) --> new TokenAuthenticationFetcher(Collection tokenValidators,[TokenResolver tokenResolver],ApplicationEventPublisher eventPublisher) --> new DefaultTokenResolver([Collection tokenReaders]) --> new JwtCookieTokenReader([JwtCookieConfiguration jwtCookieConfiguration]) --> JwtCookieConfigurationProperties.setCookieMaxAge([TemporalAmount cookieMaxAge])
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [cookieMaxAge] of method [setCookieMaxAge] of class: io.micronaut.security.token.jwt.cookie.JwtCookieConfigurationProperties
Also the `/.well-known/openid-configuration” suffix is standard, so can be hard coded.
Section https://guides.micronaut.io/micronaut-oauth2-okta/guide/index.html#oauth2
I think some documentation is required for users who want to integrate with micronaut security but using custom authentication strategies.
I pass an Authorization header up to my service and then use it to produce some roles through my own methodology (not important here). My main goal is to use the @secured annotation to secure my endpoints and handle setting up the security context myself.
After reading through the source code, I discovered a pretty simple method to do this but it took quite a bit of digging.
I basically do the following.
@Singleton
public class CustomAuthenticationFetcher implements AuthenticationFetcher {
private final CustomAuthenticationProvider customAuthenticationProvider;
@Inject
public CustomAuthenticationFetcher (final CustomAuthenticationProvider customAuthenticationProvider) {
this.customAuthenticationProvider = customAuthenticationProvider;
}
@Override
public Publisher<Authentication> fetchAuthentication(final HttpRequest<?> request) {
return request.getHeaders().getAuthorization()
.map(customAuthenticationProvider::getAuthentication)
.orElseGet(Flowable::empty);
}
}
Then I simply implement Authentication in CustomAuthentication.
I essentially have 2 questions.
It would be nice if Micronaut supported OIDC compliant flows out of the box. That would make it easy to use external identity providers like Auth0 and Okta for authentication in Micronaut services.
OIDC Client support is priority 1, but it's also important to be able to create compliant authorization servers with Micronaut that expose public RSA keys (JWKS) for resource servers to use for signature checks.
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
References:
https://auth0.com/blog/navigating-rs256-and-jwks/
https://connect2id.com/products/nimbus-jose-jwt/examples/validating-jwt-access-tokens
https://connect2id.com/products/nimbus-jose-jwt/examples/jwk-selectors
It's hard to say whether or not this is a valid issue, so I'll describe what I did and saw, and let you make the call. :)
In a nutshell, I took the Okta OAuth2 example and tried to configure it to use Keycloak. On the demo side, I made this change to application.yml:
enabled: true # <1>
oauth2:
client-secret: '${OAUTH_CLIENT_SECRET:""}' # <2>
client-id: 'examples' # <3>
#issuer: '${OIDC_ISSUER_DOMAIN}/oauth2/${OIDC_ISSUER_AUTHSERVERID}' # <4>
issuer: "http://localhost:8080/auth/realms/micronaut-demo"
I set the following environment variables:
export KEYCLOACK_DOMAIN=http://localhost:8080
export KEYCLOAK_REALM=micronaut-demo
On the Keycloak side, I created a realm, micronaut-demo
, leaving everything as the default, iirc (I was following their getting started guide).
I started the micronaut application (in debug mode) and would get NPEs after authentication, which seemed really odd (especially since the debug session didn't seem to show any nulls) on this line of code (DefaultIdTokenAccessTokenResponseHandler line 62):
throw new InvalidIdTokenAccessTokenResponseException(idTokenAccessTokenResponse);
After stepping in to the call to idTokenAccessTokenResponseValidator.validate
, I found that Micronaut was claiming that HS256 was not a supported algorithm (JwtTokenValidator.validateSignedJWTSignature
). Putting a breakpoint at JwksSignatureFactory.jwsk
, it looks like HS256 was in the list of supported algorithms, but by the time SignatureConfiguration
was injected into JwtTokenValidator
, the only thing that seemed to be listed was RS256.
To make authentication work correctly, I had to modify realm in Keycloak to use RS256 by default (http://localhost:8080/auth/admin/master/console/#/realms/micronaut-demo/token-settings for reference). Once I made that change, I was able to authenticate against Keycloak and successfully redirect back to the app, but something seems strange about that.
If there are any more details you need (modified local sources, keycloak realm export, etc.), don't be shy. :)
While configuring the validation of OAuth 2 tokens for a REST API developed with micronaut, we were wondering, if it should be possible just with properties configured in the application.yaml
We were only able to provide a custom RSASignaturConfiguration class to get the key configured. The class looks likes this
class CustomRSASignatureConfiguration : RSASignatureConfiguration {
val key = """-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----""".trimIndent()
override fun getPublicKey(): RSAPublicKey {
return RSAPublicKeyImpl(Base64.decode(key.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replace("\n", "")))
}
}
Next, we were assuming, that the RSASignatureFactory would now automatically provide the right bean based on this configuration but we also had to create a custom factory class to instantiate the SignatureConfiguration:
@Factory
public class RSASignatureFactory {
@EachBean(RSASignatureConfiguration.class)
public SignatureConfiguration signatureConfiguration(RSASignatureConfiguration configuration) {
return new RSASignature(configuration);
}
}
What is the supposed way to do this? Shall it also be possible just using application properties?
When users enter a OAuth2-secured application through a link to a particular page or resource, they expect to continue using the application from that page, after having gone through authentication, rather than to be redirected to the application root URL.
This is how Spring OAuth2 behaves, as well as most authentication schemes I'm aware of.
Please implement this in micronaut-oauth2, and tell us roughly how we should devise a future-proof workaround, while waiting for the feature.
Hi guys,
Trying to inject into my app oauth2 authentication based on your guide for OKTA, but ran into an issue trying to start the app
19:58:26.765 [main] ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: io.micronaut.inject.annotation.DefaultAnnotationMetadata.registerAnnotationType(Lio/micronaut/core/annotation/AnnotationClassValue;)V
java.lang.NoSuchMethodError: io.micronaut.inject.annotation.DefaultAnnotationMetadata.registerAnnotationType(Lio/micronaut/core/annotation/AnnotationClassValue;)V
at io.micronaut.security.oauth2.openid.configuration.$OpenIdConfigurationClient$InterceptedDefinitionClass$$AnnotationMetadata.<clinit>(Unknown Source)
at io.micronaut.security.oauth2.openid.configuration.$OpenIdConfigurationClient$InterceptedDefinitionClass.<clinit>(Unknown Source)
at java.base/java.lang.Class.forName0(Native Method)
Can you give an advice what I can check to fix the issue?
Here is my build.gradle
plugins {
id "io.spring.dependency-management" version "1.0.6.RELEASE"
id "com.github.johnrengelman.shadow" version "4.0.2"
id "net.ltgt.apt-eclipse" version "0.18"
id "net.ltgt.apt-idea" version "0.18"
}
ext {
micronautVersion = '1.0.0.BUILD-SNAPSHOT'
}
apply plugin:"application"
apply plugin:"java"
version "0.1"
group "cloud.cert"
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
dependencyManagement {
imports {
mavenBom "io.micronaut:micronaut-bom:${micronautVersion}"
}
}
dependencies {
annotationProcessor "io.micronaut:micronaut-inject-java"
annotationProcessor "io.micronaut:micronaut-validation"
annotationProcessor "io.micronaut:micronaut-security"
compile "io.micronaut:micronaut-security-jwt"
compile "io.micronaut:micronaut-inject"
compile "io.micronaut:micronaut-validation"
compile "io.micronaut:micronaut-runtime"
compile "io.micronaut:micronaut-http-client"
compile "io.micronaut.configuration:micronaut-hibernate-jpa"
compile "io.micronaut.configuration:micronaut-hibernate-validator"
compile "io.micronaut.configuration:micronaut-jdbc-hikari"
compile "io.micronaut.configuration:micronaut-oauth2:$micronautVersion"
compile "javax.annotation:javax.annotation-api"
compile "io.micronaut:micronaut-http-server-netty"
compile "io.micronaut:micronaut-views"
compileOnly "io.micronaut:micronaut-inject-java"
runtime "ch.qos.logback:logback-classic:1.2.3"
runtime "com.h2database:h2"
runtime "org.thymeleaf:thymeleaf:3.0.11.RELEASE"
testCompile "junit:junit:4.12"
testCompile "io.micronaut:micronaut-inject-java"
testCompile "org.hamcrest:hamcrest-all:1.3"
}
shadowJar {
mergeServiceFiles()
}
run.jvmArgs('-noverify', '-XX:TieredStopAtLevel=1')
mainClassName = "com.xxx.xxxx.Application"
tasks.withType(JavaCompile){
options.encoding = "UTF-8"
options.compilerArgs.add('-parameters')
}
Invoking the 'logout' endpoint when using the session based authentication results in the same set-cookie session response returned as for a 'login' request.
Steps to reproduce:
Example:
$ curl -v -X POST "http://localhost:8080/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"username\":\"sherlock\",\"password\":\"password\"}"
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /login HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 45
>
* upload completely sent off: 45 out of 45 bytes
< HTTP/1.1 303 See Other
< Location: /
< Authorization-Info: a8733442-3124-4b47-8b3a-17986d779365
< set-cookie: SESSION=YTg3MzM0NDItMzEyNC00YjQ3LThiM2EtMTc5ODZkNzc5MzY1; Path=/; HTTPOnly
< Date: Thu, 9 May 2019 14:10:38 GMT
< transfer-encoding: chunked
< connection: close
<
* Closing connection 0
Example:
$ curl -v -X POST "http://localhost:8080/logout" -H "accept: application/json" -H "Content-Type: application/json" --cookie "SESSION=YTg3MzM0NDItMzEyNC00YjQ3LThiM2EtMTc5ODZkNzc5MzY1"
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /logout HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Cookie: SESSION=YTg3MzM0NDItMzEyNC00YjQ3LThiM2EtMTc5ODZkNzc5MzY1
> accept: application/json
> Content-Type: application/json
>
< HTTP/1.1 303 See Other
< Location: /
< Authorization-Info: a8733442-3124-4b47-8b3a-17986d779365
< set-cookie: SESSION=YTg3MzM0NDItMzEyNC00YjQ3LThiM2EtMTc5ODZkNzc5MzY1; Path=/; HTTPOnly
< Date: Thu, 9 May 2019 14:11:51 GMT
< transfer-encoding: chunked
< connection: close
<
* Closing connection 0
Expected: Response to logout request should set the session value to something other than the original session id (maybe blank).
Actual: The same session id is returned for the logout request as is for the login request
Environment:
OS: MacOS 10.14.3
JDK: jdk1.8.0_162
Micronaut: 1.1.0 (also updated the guided solution to 1.1.1 and the behaviour was the same)
I am currently using io.micronaut.configuration:micronaut-security-oauth2:1.2.0
behind a proxy.
Application is running on localhost:8082
and proxy is on localhost:5000
. When making a GET
request to http://localhost:8082/oauth/login{/provider}
, I get status 302
and Location containing redirect_uri=http://localhost:8082/oauth/callback{/provider}
Now when I make a GET
request to http://localhost:5000/oauth/login{/provider}
(note the port as 5000) - This is the proxy
I expect to get a status 302
and Location containing redirect_uri=http://localhost:5000/oauth/callback{/provider}
(Note the port 5000)
I get status 302
and Location containing redirect_uri=http://localhost:8082/oauth/callback{/provider}
SessionSecurityFilterOrderProvider
should be in security
annotated with @Requires(beans = {HttpSessionFilter.class})
with a compileOnly dependency to session
instead of inside the security-session
module.
it will achieve correct filter order even if the user is not including the security-session
module.
OpenIdClientCondition
evaluates to false for such configuration:
micronaut:
security:
oauth2:
enabled: true
clients:
apple:
client-secret: 'XXXX'
client-id: '${APPLE_SERVICE_ID}'
scopes:
- 'name'
- 'email'
openid:
authorization:
url: 'https://appleid.apple.com/auth/authorize'
token:
url: 'https://appleid.apple.com/auth/token'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.