Coder Social home page Coder Social logo

ambassador-auth-oidc's People

Contributors

ajmyyra avatar atolia avatar yanniszark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ambassador-auth-oidc's Issues

Possibility to return JWT token via the headers

Currently only tokens in a cookie are supported.

Will it be possible to:

  • Return the JWT token via the x-auth-token header (or better named header) after login.
  • Check JWT token if the x-auth-token is present.

Storing cookies to the users browsers seems unneeded in some use-cases.

Better logging

Logging is currently all over the place and repeats itself on many lines. Create a separate logger to handle the cases.

Ambassador-->oidc-->Keycloak: Failed to exchange token: oauth2

Hello,
First a little description of my setup :)
In a kubernetes cluster i'm running the following:
Ambassador v: 0.72.0
Keycloak v: 5.0.0
and a echo-http-test service serving a "hello world page"

I'm trying to get ambassador-auth-oidc to work as middle-ware between ambassador and keycloak.
All services are up and running. Keycloak is configured with realm, client and user.
I can navigate to my echo-http-test uri, and it will redirect to keycloaks login page as expected.
I login, and i get redirected to ambassador-auth-oidc service "/login/oidc"
Here I keep on getting error-code response from ambassador-auth-oidc:

Failed to exchange token.

The full logs of the ambassador service contains:

2019/06/27 15:16:06 Failed to exchange token: oauth2: cannot fetch token: 500 Internal Server Error
Response: 

And the logs of from Keycloak say:

ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-160) Uncaught server error: java.lang.NullPointerException                                                                     
        at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.codeToToken(TokenEndpoint.java:300)                                                                                                                  
        at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:183)                                                                                                          
        at sun.reflect.GeneratedMethodAccessor751.invoke(Unknown Source)                                                                                                                                           
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)                                                                                                                   
        at java.lang.reflect.Method.invoke(Method.java:498)                                                                                                                                                        
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)                                                                                                                          
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:509)                                                                                                    
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:399)                                                                                                 
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:363)                                                                                                   
        at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:355)                                                                                   
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:365)                                                                                                            
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)                                                                                                                    
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:137)                                                                                                    
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:106)                                                                                                                  
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:132)                                                                                                    
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:100)                                                                                                                  
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:439)                                                                                                                    
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)                                                                                                           
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)                                                                                                       
        at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:355)                                                                                   
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)                                                                                                                
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)                                                                                                                    
        at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)   
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)                                                                                                  
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)                                                                                                  
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)                                                                                                                                            
        at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:90)
        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
        at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
        at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
        at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
        at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
        at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
        at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
        at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
        at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
        at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
        at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)

Now initially i thought this would be a error on keycloaks side, however i did a bit of a search around stack-overflow and found that the error is caused by a missing redirect_uri parameter in the request between oidc and keycloak.

use UTC time

I think it would be best-practice to use UTC time explicitly as the dex codebase does:

https://github.com/dexidp/dex/search?q=UTC&unscoped_q=UTC

Otherwise the code will just use whatever timezone the server is using.

I hit this when using a dex setup with a local client and this auth service running in the server. The server was on UTC and my local wasn't. So tokens generated on my local were rejected by the server, which was doing a check on when it was issued and thinking it was being used before it was even issued. It is a fringe use-case and we were able to address it by changing the local to use UTC. But it highlights why making UTC explicit might be a better practice.

Allow limiting users based on userinfo

Currently every user able to login at OIDC endpoint will be let in. Make it possible to limit users, for example with email domain or if their email_verified is set to true.

Make the userinfo endpoint optional

I have discovered that there is some confusion around the userinfo_endpoint and whether it's mandatory or not.
Dex, a big project around OIDC, doesn't seem to implement it yet and I have found references to the spec that characterize it as RECOMMENDED.

Because of the Dex use-case and also the fact that the userinfo endpoint doesn't seem to be mandatory, it makes sense to provide a flag to allow getting the claims from the id_token instead of the userinfo endpoint.

cc @ajmyyra

Version without Redis?

Have you considered an option to have this available without Redis and have the JWT token only be stored in the cookie? You will not be able to token blacklisting on logout, but this could be ok with short lived tokens and would simplify deployment?

Redirect fails after successful login

Hi
I'm trying to connect Ambassador GW to Keycloak using this auth-oidc middleware.
The only change I made in the auth-deployment.yaml and auth-service.yaml was to change from port 8080 to 9090.

I'm using MacOS
Here is the K8S deployments:

NAME                                  READY   STATUS    RESTARTS   AGE
pod/ambassador-558b7b6cb7-8gzq9       1/1     Running   8          28h
pod/ambassador-558b7b6cb7-c8vd8       1/1     Running   9          28h
pod/ambassador-558b7b6cb7-m9jdp       1/1     Running   8          28h
pod/flinckr-events-7b97db9d64-pc2tz   1/1     Running   2          20h
pod/keycloak-0                        1/1     Running   2          17d
pod/oidc-auth-6cb698d467-ljncs        2/2     Running   5          20h
pod/postgres-kc-postgresql-0          1/1     Running   2          18d


NAME                                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/ambassador                        LoadBalancer   10.99.201.29     localhost     80:32393/TCP,443:30066/TCP      4d3h
service/ambassador-admin                  ClusterIP      10.99.238.140    <none>        8877/TCP                        4d3h
service/ambassador-oidc-auth              ClusterIP      10.105.50.239    <none>        9090/TCP                        20h
service/flinckr-events                    ClusterIP      10.101.31.137    <none>        9000/TCP                        20h
service/keycloak-headless                 ClusterIP      None             <none>        8080/TCP,8443/TCP               17d
service/keycloak-http                     LoadBalancer   10.107.104.233   localhost     8080:32156/TCP,8443:32712/TCP   5d15h
service/kubernetes                        ClusterIP      10.96.0.1        <none>        443/TCP                         18d
service/oidc-auth                         ClusterIP      10.102.175.104   <none>        9090/TCP                        20h
service/postgres-kc-postgresql            ClusterIP      10.103.204.109   <none>        5432/TCP                        18d
service/postgres-kc-postgresql-headless   ClusterIP      None             <none>        5432/TCP                        18d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ambassador       3/3     3            3           4d3h
deployment.apps/flinckr-events   1/1     1            1           20h
deployment.apps/oidc-auth        1/1     1            1           20h

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/ambassador-558b7b6cb7       3         3         3       4d3h
replicaset.apps/flinckr-events-7b97db9d64   1         1         1       20h
replicaset.apps/oidc-auth-6cb698d467        1         1         1       20h

NAME                                      READY   AGE
statefulset.apps/keycloak                 1/1     17d
statefulset.apps/postgres-kc-postgresql   1/1     18d

The task is to make Ambassador to redirect to Keycloak in case the user is not authenticated, or in case the session is expired.

Here are the secrets I configured:

kubectl create secret generic ambassador-auth-jwt-key --from-literal=jwt-key=$(openssl rand -base64 64|tr -d '\n ')

kubectl create secret generic ambassador-auth-redis-password --from-literal=redis-password=$(openssl rand -base64 20)

kubectl create secret generic ambassador-auth-oidc-provider --from-literal=oidc-provider="http://keycloak-http:8080/auth/realms/flinckr_realm"

kubectl create secret generic ambassador-auth-self-url --from-literal=self-url="http://localhost"

kubectl create secret generic ambassador-auth-client-id --from-literal=client-id="flinckr_backend"

kubectl create secret generic ambassador-auth-client-secret --from-literal=client-secret= <MY_SECRET>


I'm able to successfully go thru the OIDC process, as was nicely explained in the OIDC-flow.png

The problem I'm facing is that the last redirect is wrong.
I'll explain....
Here what I see in the browser:
1- going to http://localhost/events
oidc-phase-1

Call is being directed to keycloak as was expected

2- Keycloak shows login screen
oidc-phase-2

3- Code is being sent to the browser and from there back to oidc-auth service for generating JWT (if I get it correctly)

oidc-phase-3

oidc-phase-5

4- And now that user is authenticated, I expect the browser to be redirected back to my original request which was http://localhost/events.
But here is the problem, the browser is being redirected to http://localhost (which of course returns 404 Error), instead of going to http://localhost/events.
oidc-phase-6

You could see from the attached images, that the authentication process is correct. The only thing is missing how to make sure the last redirect URL is set correctly

This is the Ambassador image:

image:
  repository: quay.io/datawire/ambassador
  tag: 0.86.0
  pullPolicy: IfNotPresent

This is the Keycloak image:

image:
    repository: jboss/keycloak
    tag: 7.0.0
    pullPolicy: IfNotPresent

Appreciate your help

SELF_URL adds additional path

Hi there!
This is likely an extremely stupid question. But I wanted to ask why you add the following extra paths to the SELF_URL variable? I assumed that this variable was the URL we would want to end up redirecting to, and wanted to understand why this was needed?

redirURL = redirURL + "/login/oidc"

Thanks for your help!
Jay

support access control using additional claims in id_token

in some OIDC provider such as Azure Active Directory it's possible to configure the client application to emit groups claim (or roles claim). For instance, this and that.
With these claims, we can implement access control so that only ones in the selected group can access the sensitive resources protected by Ambassador API gateway.

Since I have already implemented this feature in my fork, I'm happy to send a PR if you think it's useful.

Redirect in JWT validation error

Currently, when the JWT validation fails, an HTTP error code is sent along with a small message.
Clearing the cookie and redirecting to login would make for a better UX.
@ajmyyra what do you think? I will open a PR for this if you agree.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.