GithubHelp home page GithubHelp logo

vouch / vouch-proxy Goto Github PK

View Code? Open in Web Editor NEW
2.8K 35.0 322.0 5.83 MB

an SSO and OAuth / OIDC login solution for Nginx using the auth_request module

License: MIT License

Shell 5.60% Go 93.68% CSS 0.32% Dockerfile 0.41%
nginx nginx-proxy sso oauth2 jwt lasso sso-login sso-solution authentication golang

vouch-proxy's Introduction

Vouch Proxy

GitHub stars Build Status Go Report Card MIT license GitHub version

An SSO solution for Nginx using the auth_request module. Vouch Proxy can protect all of your websites at once.

Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to...

Please do let us know when you have deployed Vouch Proxy with your preffered IdP or library so we can update the list.

If Vouch is running on the same host as the Nginx reverse proxy the response time from the /validate endpoint to Nginx should be less than 1ms.


Table of Contents

What Vouch Proxy Does

Vouch Proxy (VP) forces visitors to login and authenticate with an IdP (such as one of the services listed above) before allowing them access to a website.

Vouch Proxy protects websites

VP can also be used as a Single Sign On (SSO) solution to protect all web applications in the same domain.

Vouch Proxy is a Single Sign On solution

After a visitor logs in Vouch Proxy allows access to the protected websites for several hours. Every request is checked by VP to ensure that it is valid.

VP can send the visitor's email, name and other information which the IdP provides (including access tokens) to the web application as HTTP headers. VP can be used to replace application user management entirely.

Installation and Configuration

Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as vouch.yourdomain.com with apps running at app1.yourdomain.com and app2.yourdomain.com. The protected domain is .yourdomain.com and the Vouch Proxy cookie must be set in this domain by setting vouch.domains to include yourdomain.com or sometimes by setting vouch.cookie.domain to yourdomain.com.

  • cp ./config/config.yml_example_$OAUTH_PROVIDER ./config/config.yml
  • create OAuth credentials for Vouch Proxy at google or github, etc
    • be sure to direct the callback URL to the Vouch Proxy /auth endpoint
  • configure Nginx...

The following Nginx config assumes..

  • Nginx, vouch.yourdomain.com and protectedapp.yourdomain.com are running on the same server
  • both domains are served as https and have valid certs (if not, change to listen 80 and set vouch.cookie.secure to false)
server {
    listen 443 ssl http2;
    server_name protectedapp.yourdomain.com;
    root /var/www/html/;

    ssl_certificate /etc/letsencrypt/live/protectedapp.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/protectedapp.yourdomain.com/privkey.pem;

    # send all requests to the `/validate` endpoint for authorization
    auth_request /validate;

    location = /validate {
      # forward the /validate request to Vouch Proxy
      proxy_pass http://127.0.0.1:9090/validate;
      # be sure to pass the original host header
      proxy_set_header Host $http_host;

      # Vouch Proxy only acts on the request headers
      proxy_pass_request_body off;
      proxy_set_header Content-Length "";

      # optionally add X-Vouch-User as returned by Vouch Proxy along with the request
      auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;

      # optionally add X-Vouch-IdP-Claims-* custom claims you are tracking
      #    auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
      #    auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name;
      # optinally add X-Vouch-IdP-AccessToken or X-Vouch-IdP-IdToken
      #    auth_request_set $auth_resp_x_vouch_idp_accesstoken $upstream_http_x_vouch_idp_accesstoken;
      #    auth_request_set $auth_resp_x_vouch_idp_idtoken $upstream_http_x_vouch_idp_idtoken;

      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;

      # Vouch Proxy can run behind the same Nginx reverse proxy
      # may need to comply to "upstream" server naming
      # proxy_pass http://vouch.yourdomain.com/validate;
      # proxy_set_header Host $http_host;
    }

    # if validate returns `401 not authorized` then forward the request to the error401block
    error_page 401 = @error401;

    location @error401 {
        # redirect to Vouch Proxy for login
        return 302 https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
        # you usually *want* to redirect to Vouch running behind the same Nginx config proteced by https
        # but to get started you can just forward the end user to the port that vouch is running on
        # return 302 http://vouch.yourdomain.com:9090/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    location / {
      # forward authorized requests to your service protectedapp.yourdomain.com
      proxy_pass http://127.0.0.1:8080;
      # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810
      #    auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user
      #    auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
      #    auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name;

      # set user header (usually an email)
      proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
      # optionally pass any custom claims you are tracking
      #     proxy_set_header X-Vouch-IdP-Claims-Groups $auth_resp_x_vouch_idp_claims_groups;
      #     proxy_set_header X-Vouch-IdP-Claims-Given_Name $auth_resp_x_vouch_idp_claims_given_name;
      # optionally pass the accesstoken or idtoken
      #     proxy_set_header X-Vouch-IdP-AccessToken $auth_resp_x_vouch_idp_accesstoken;
      #     proxy_set_header X-Vouch-IdP-IdToken $auth_resp_x_vouch_idp_idtoken;
    }
}

If Vouch is configured behind the same nginx reverseproxy (perhaps so you can configure ssl) be sure to pass the Host header properly, otherwise the JWT cookie cannot be set into the domain

server {
    listen 443 ssl http2;
    server_name vouch.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/vouch.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vouch.yourdomain.com/privkey.pem;

    location / {
      proxy_pass http://127.0.0.1:9090;
      # be sure to pass the original host header
      proxy_set_header Host $http_host;
    }
}

Vouch Proxy "in a path"

As of v0.33.0 Vouch Proxy can be served within an Nginx location (path) by configuring vouch.document_root: /vp_in_a_path

This avoids the need to setup a separate domain for Vouch Proxy such as vouch.yourdomain.com. For example VP login will be served from https://protectedapp.yourdomain.com/vp_in_a_path/login

server {
    listen 443 ssl http2;
    server_name protectedapp.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/protectedapp.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/protectedapp.yourdomain.com/privkey.pem;

    # This location serves all Vouch Proxy endpoints as /vp_in_a_path/$uri
    #   including /vp_in_a_path/validate, /vp_in_a_path/login, /vp_in_a_path/logout, /vp_in_a_path/auth, /vp_in_a_path/auth/$STATE, etc
    location /vp_in_a_path {
      proxy_pass http://127.0.0.1:9090; # must not! have a slash at the end
      proxy_set_header Host $http_host;
      proxy_pass_request_body off;
      proxy_set_header Content-Length "";

      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
    }

    # if /vp_in_a_path/validate returns `401 not authorized` then forward the request to the error401block
    error_page 401 = @error401;

    location @error401 {
        # redirect to Vouch Proxy for login
        return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    location / {
      auth_request /vp_in_a_path/validate;
      proxy_pass http://127.0.0.1:8080;
      # see the Nginx config above for additional headers which can be set from Vouch Proxy
    }
}

Additional Nginx Configurations

Additional Nginx configurations can be found in the examples directory.

Configuring via Environmental Variables

Here's a minimal setup using Google's OAuth...

VOUCH_DOMAINS=yourdomain.com \
  OAUTH_PROVIDER=google \
  OAUTH_CLIENT_ID=1234 \
  OAUTH_CLIENT_SECRET=secretsecret \
  OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \
  ./vouch-proxy

Environmental variable names are documented in config/config.yml_example

All lists with multiple values must be comma separated: VOUCH_DOMAINS="yourdomain.com,yourotherdomain.com"

The variable VOUCH_CONFIG can be used to set an alternate location for the configuration file. VOUCH_ROOT can be used to set an alternate root directory for Vouch Proxy to look for support files.

Tips, Tricks and Advanced Configurations

All Vouch Proxy configuration items are documented in config/config.yml_example

Please do help us to expand this list.

Scopes and Claims

With Vouch Proxy you can request various scopes (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to user_info_url after successful authentication. The required claims are extracted from the provider's response and stored in the VP cookie.

⚠️ Additional claims and tokens will be added to the VP cookie and can make it large

The VP cookie may be split into several cookies to accomdate browser cookie size limits. But if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See large_client_header_buffers and proxy_buffer_size for more information.

Setup scopes and claims in Vouch Proxy with Nginx

  1. Configure Vouch Proxy for Nginx and your IdP as normal (See: Installation and Configuration)

  2. Set the necessary scopes in the oauth section of the vouch-proxy config.yml (example config)

    1. set idtoken: X-Vouch-IdP-IdToken in the headers section of vouch-proxy's config.yml
    2. log in and call the /validate endpoint in a modern browser
    3. check the response header for a X-Vouch-IdP-IdToken header
    4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt
    5. if they are not, you need to adjust the scopes in the oauth section of your config.yml or reconfigure your oauth provider
  3. Set the necessary claims in the header section of the vouch-proxy config.yml

    1. log in and call the /validate endpoint in a modern browser
    2. check the response headers for headers of the form X-Vouch-IdP-Claims-<ClaimName>
    3. If they are not there clear your cookies and cached browser data
    4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug
    5. remove the idtoken: X-Vouch-IdP-IdToken from the headers section of vouch-proxy's config.yml if you don't need it
  4. Use auth_request_set after auth_request inside the protected location in the nginx server.conf

  5. Consume the claim (example nginx config)

Running from Docker

docker run -d \
    -p 9090:9090 \
    --name vouch-proxy \
    -v ${PWD}/config:/config \
    quay.io/vouch/vouch-proxy

or

docker run -d \
    -p 9090:9090 \
    --name vouch-proxy \
    -e VOUCH_DOMAINS=yourdomain.com \
    -e OAUTH_PROVIDER=google \
    -e OAUTH_CLIENT_ID=1234 \
    -e OAUTH_CLIENT_SECRET=secretsecret \
    -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \
    quay.io/vouch/vouch-proxy

As of v0.36.0 the docker process in the container runs as user vouch with UID 999 and GID 999. You may need to set the permissions of /config/config.yml and /config/secret to correspond to be readable by this user, or otherwise use docker run --user $UID:$GID ... or perhaps build the docker container from source and use the available ARGs for UID and GID.

Automated container builds for each Vouch Proxy release are available from quay.io. Each release produces..

a minimal go binary container built from Dockerfile

  • quay.io/vouch/vouch-proxy:latest
  • quay.io/vouch/vouch-proxy:x.y.z such as quay.io/vouch/vouch-proxy:0.28.0

an alpine based container built from Dockerfile.alpine

  • quay.io/vouch/vouch-proxy:alpine-latest
  • quay.io/vouch/vouch-proxy:alpine-x.y.z

Vouch Proxy arm images are available on Docker Hub

  • voucher/vouch-proxy:latest-arm

Kubernetes Nginx Ingress

If you are using kubernetes with nginx-ingress, you can configure your ingress with the following annotations (note quoting the auth-signin annotation):

    nginx.ingress.kubernetes.io/auth-signin: "https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err"
    nginx.ingress.kubernetes.io/auth-url: https://vouch.yourdomain.com/validate
    nginx.ingress.kubernetes.io/auth-response-headers: X-Vouch-User
    nginx.ingress.kubernetes.io/auth-snippet: |
      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
      # when VP is hosted externally to k8s ensure the SSL cert is valid to avoid MITM risk
      # proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
      # proxy_ssl_session_reuse on;
      # proxy_ssl_verify_depth 2;
      # proxy_ssl_verify on;

Helm Charts are maintained by punkle, martina-if and halkeye and are available at https://github.com/vouch/helm-charts

Compiling from source and running the binary

  ./do.sh goget
  ./do.sh build
  ./vouch-proxy

As of v0.29.0 all templates, static assets and configuration defaults in .defaults.yml are built into the static binary using go:embed directives.

/login and /logout endpoint redirection

As of v0.11.0 additional checks are in place to reduce the attack surface of url redirection.

/login?url=POST_LOGIN_URL

The passed URL...

  • must start with either http or https
  • must have a domain overlap with either a domain in the vouch.domains list or the vouch.cookie.domain (if either of those are configured)
  • cannot have a parameter which includes a URL to prevent URL chaining attacks

/logout?url=NEXT_URL

The Vouch Proxy /logout endpoint accepts a url parameter in the query string which can be used to 302 redirect a user to your orignal OAuth provider/IDP/OIDC provider's revocation_endpoint

    https://vouch.oursites.com/logout?url=https://oauth2.googleapis.com/revoke

this url must be present in the configuration file on the list vouch.post_logout_redirect_uris

# in order to prevent redirection attacks all redirected URLs to /logout must be specified
# the URL must still be passed to Vouch Proxy as https://vouch.yourdomain.com/logout?url=${ONE OF THE URLS BELOW}
post_logout_redirect_uris:
  # your apps login page
  - https://yourdomain.com/login
  # your IdPs logout enpoint
  # from https://accounts.google.com/.well-known/openid-configuration
  - https://oauth2.googleapis.com/revoke
  # you may be daisy chaining to your IdP
  - https://myorg.okta.com/oauth2/123serverid/v1/logout?post_logout_redirect_uri=http://myapp.yourdomain.com/login

Note that your IdP will likely carry their own, separate post_logout_redirect_uri list.

logout resources..

Troubleshooting, Support and Feature Requests (Read this before submitting an issue at GitHub)

Getting the stars to align between Nginx, Vouch Proxy and your IdP can be tricky. We want to help you get up and running as quickly as possible. The most common problem is..

I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)

Double check that you are running Vouch Proxy and your apps on a common domain that can share cookies. For example, vouch.yourdomain.com and app.yourdomain.com can share cookies on the .yourdomain.com domain. (It will not work if you are trying to use vouch.yourdomain.org and app.yourdomain.net.)

You may need to explicitly define the domain that the cookie should be set on. You can do this in the config file by setting the option:

vouch:
  cookie:
    # force the domain of the cookie to set
    domain: yourdomain.com

If you continue to have trouble, try the following:

  • turn on vouch.testing: true. This will slow down the loop.

  • set vouch.logLevel: debug.

  • the Host: header in the http request, the oauth.callback_url and the configured vouch.domains must all align so that the cookie that carries the JWT can be placed properly into the browser and then returned on each request

  • it helps to think like a cookie.

    • a cookie is set into a domain. If you have siteA.yourdomain.com and siteB.yourdomain.com protected by Vouch Proxy, you want the Vouch Proxy cookie to be set into .yourdomain.com
    • if you authenticate to vouch.yourdomain.com the cookie will not be able to be seen by dev.anythingelse.com
    • unless you are using https, you should set vouch.cookie.secure: false
    • cookies are available to all ports of a domain
  • please see the issues which have been closed that mention redirect

Okay, I looked at the issues and have tried some things with my configs but it's still not working

Please submit a new issue in the following fashion..

TLDR:

  • set vouch.testing: true
  • set vouch.logLevel: debug
  • conduct two full round trips of ./vouch-proxy capturing the output..
    • VP startup
    • /validate
    • /login - even if the error is here
    • /auth
    • /validate - capture everything
  • put all your logs and config in a gist.
  • ./do.sh bug_report is your friend

But read this anyways because we'll ask you to read it if you don't follow these instruction. :)

  • turn on vouch.testing: true and set vouch.logLevel: debug.
  • use a gist or another paste service such as hasteb.in. DO NOT PUT YOUR LOGS AND CONFIG INTO THE GITHUB ISSUE. Using a paste service is important as it will maintain spacing and will provide line numbers and formatting. We are hunting for needles in haystacks with setups with several moving parts, these features help considerably. Paste services save your time and our time and help us to help you quickly. You're more likely to get good support from us in a timely manner by following this advice.
  • run ./do.sh bug_report secretdomain.com secretpass [anothersecret..] which will create a redacted version of your config and logs removing each of those strings
    • and follow the instructions at the end to redact your Nginx config
  • all of those go into a gist
  • then open a new issue in this repository

A bug report can be generated from a docker environment using the quay.io/vouch/vouch-proxy:alpine image...

docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh quay.io/vouch/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret

Contributing

We'd love to have you contribute! Please refer to our contribution guidelines for details.

Advanced Authorization Using OpenResty

OpenResty® is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies.

You can replace nginx with OpenResty fairly easily.

With OpenResty and Lua it is possible to provide customized and advanced authorization on any header or claims vouch passes down.

OpenResty and configs for a variety of scenarios are available in the examples directory.

The flow of login and authentication using Google Oauth

  • Bob visits https://private.oursites.com

  • the Nginx reverse proxy...

    • recieves the request for private.oursites.com from Bob
    • uses the auth_request module configured for the /validate path
    • /validate is configured to proxy_pass requests to the authentication service at https://vouch.oursites.com/validate
      • if /validate returns...
        • 200 OK then SUCCESS allow Bob through
        • 401 NotAuthorized then
          • respond to Bob with a 302 redirect to https://vouch.oursites.com/login?url=https://private.oursites.com
  • Vouch Proxy https://vouch.oursites.com/validate

    • recieves the request for private.oursites.com from Bob via Nginx proxy_pass
    • looks for a cookie named "oursitesSSO" that contains a JWT
    • if the cookie is found, and the JWT is valid
      • returns 200 OK to Nginx, which will allow access (bob notices nothing)
    • if the cookie is NOT found, or the JWT is NOT valid
      • return 401 NotAuthorized to Nginx (which forwards the request on to login)
  • Bob is first forwarded briefly to https://vouch.oursites.com/login?url=https://private.oursites.com

    • clears out the cookie named "oursitesSSO" if it exists
    • generates a nonce and stores it in session variable $STATE
    • stores the url https://private.oursites.com from the query string in session variable $requestedURL
    • respond to Bob with a 302 redirect to Google's OAuth Login form, including the $STATE nonce
  • Bob logs into his Google account using Oauth

    • after successful login
    • Google responds to Bob with a 302 redirect to https://vouch.oursites.com/auth?state=$STATE
  • Bob is forwarded to https://vouch.oursites.com/auth?state=$STATE

    • if the $STATE nonce from the url matches the session variable "state"
    • make a "third leg" request of Google (server to server) to exchange the OAuth code for Bob's user info including email address [email protected]
    • if the email address matches the domain oursites.com (it does)
      • issue bob a JWT in the form of a cookie named "oursitesSSO"
      • retrieve the session variable $requestedURL and 302 redirect bob back to https://private.oursites.com

Note that outside of some innocuos redirection, Bob only ever sees https://private.oursites.com and the Google Login screen in his browser. While Vouch does interact with Bob's browser several times, it is just to set cookies, and if the 302 redirects work properly Bob will log in quickly.

Once the JWT is set, Bob will be authorized for all other sites which are configured to use https://vouch.oursites.com/validate from the auth_request Nginx module.

The next time Bob is forwarded to google for login, since he has already authorized the Vouch Proxy OAuth app, Google immediately forwards him back and sets the cookie and sends him on his merry way. In some browsers such as Chrome, Bob may not even notice that he logged in using Vouch Proxy.

vouch-proxy's People

Contributors

aaronpk avatar artagel avatar bgehman avatar bnfinet avatar cpatel-secureauth avatar danfaizer avatar davidgibbons avatar dobli avatar eikehartmann avatar firefoxmetzger avatar flexponsive avatar gdamjan avatar halkeye avatar herbrant avatar innermatrix avatar jbwtan avatar jchapman77 avatar jrib avatar lispyclouds avatar madworx avatar mig5 avatar mzjp2 avatar punkle avatar qingsong-yao avatar rayward avatar reedstrm avatar rmak-cpi avatar simongottschlag avatar vallahaye avatar yannh 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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

vouch-proxy's Issues

Not able set additional claims to Ngnix proxy header

Hello,

I have a OIDC authorization server OKTA, where I have created a claim called "sub" and it's been included to fetched along ID_Token as well as Access_Token. I am trying to set both user and sub as header attributes using following settings in ngnix server.

auth_request_set $auth_user $upstream_http_x_vouch_user;
auth_request_set $sub $upstream_http_x_vouch_sub;

proxy_set_header username $auth_user;
proxy_set_header sub $sub;

At the endpoint, I am only receiving username in the header, not the sub.

Please let me know the exact settings I should follow in order to get the included claim "sub" in the endpoint header

error: named cookie not present

I'm seeing a lot of this in my logs:

time="2017-12-04T15:10:47Z" level=error msg="http: named cookie not present"

I think it's coming from this line where it's logging the error and the return statement is commented out. That would suggest to me that it's not actually an error.

Validate tokens using JWKS

Hi,

We should add functionality to validate the tokens received from the OpenID Providers. Either add jwks_uri or using the discovery document. I'm not sure they are validated as of now.

Raspberry Pi 2/3 version

Is there a docker container for armhf processor? If not, would you be able to generate it?
Thanks.

The name "Lasso" is already taken by our own library

Hi,

I work for a french company, Entr'ouvert, and we developped, since 2003, a SAML library called Lasso : http://lasso.entrouvert.org/

It has been SAML 2 certified by the liberty Alliance consortium in 2006, it is packaged in Debian, Red Hat, etc. and used by third party projects such as mod_mellon, developed by Uninett in Norway.

It is also used by customers like Cisco, Bloomberg, Miracl and most french universities.

You can easily understand we fear confusion as your project has taken the same name, also in the SSO domain.

For a clear identification of both projects, we'd like to ask you if you could switch your project to something different?

Thank you,

get oauth2 401 Unauthorized in Github Enterprse 2.13

In https://developer.github.com/enterprise/2.13/v3/oauth_authorizations/#more-info, I saw the token field is deprecated, not sure whether it has impact on this.

Logs

time="2018-09-20T08:06:19Z" level=debug msg=/validate
time="2018-09-20T08:06:19Z" level=error msg="no jwt found"
time="2018-09-20T08:06:19Z" level=debug msg="Request handled successfully"
time="2018-09-20T08:06:19Z" level=debug msg="statuscode: <nil>"
time="2018-09-20T08:06:19Z" level=info msg="|\x1b[97;42m 200 \x1b[0m|      29.309µs | 172.19.0.7:48630 | GET lasso:9091 /validate | "
time="2018-09-20T08:06:19Z" level=debug msg="Request received : &{GET /login?url=http://xi-sat.eng.a.com/prometheus/&lasso-failcount=&X-Lasso-Token=&error= HTTP/1.1 1 1 map[User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8] Accept-Language:[en-US,en;q=0.5] Accept-Encoding:[gzip, deflate] Upgrade-Insecure-Requests:[1] Dnt:[1] Connection:[keep-alive]] {} <nil> 0 [] false xi-sat.eng.a.com:9091 map[] map[] <nil> map[] 10.3.254.101:54809 /login?url=http://xi-sat.eng.a.com/prometheus/&lasso-failcount=&X-Lasso-Token=&error= <nil> <nil> <nil> 0xc420330880}\n"
time="2018-09-20T08:06:19Z" level=debug msg=/login
time="2018-09-20T08:06:19Z" level=debug msg="session state set to v/n9PnQSQq6LmX486Nz2cTazM3rDImuDl4VuhepdBdI="
time="2018-09-20T08:06:19Z" level=debug msg="session requestedURL set to http://xi-sat.eng.a.com/prometheus/"
time="2018-09-20T08:06:19Z" level=debug msg="saving session"
time="2018-09-20T08:06:19Z" level=debug msg="redirecting to oauthURL https://drt-it-github-prod-1.eng.a.com/login/oauth/authorize?client_id=not_displayed&response_type=code&scope=user&state=v%2Fn9PnQSQq6LmX486Nz2cTazM3rDImuDl4VuhepdBdI%3D"
time="2018-09-20T08:06:19Z" level=debug msg="Request handled successfully"
time="2018-09-20T08:06:19Z" level=debug msg="statuscode: <nil>"
time="2018-09-20T08:06:19Z" level=info msg="|\x1b[97;42m 200 \x1b[0m|     238.022µs | 10.3.254.101:54809 | GET xi-sat.eng.a.com:9091 /login | "
time="2018-09-20T08:06:25Z" level=debug msg="Request received : &{GET /auth?code=e921fc2b5ea3c0a5007a&state=v%2Fn9PnQSQq6LmX486Nz2cTazM3rDImuDl4VuhepdBdI%3D HTTP/1.1 1 1 map[Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8] Accept-Language:[en-US,en;q=0.5] Accept-Encoding:[gzip, deflate] Referer:[https://drt-it-github-prod-1.eng.a.com/] Connection:[keep-alive] Cookie:[lasso-session=MTUzNzQzMDc3OXxEdi1CQkFFQ180SUFBUkFCRUFBQV85TF9nZ0FEQm5OMGNtbHVad3dIQUFWemRHRjBaUVp6ZEhKcGJtY01MZ0FzZGk5dU9WQnVVVk5SY1RaTWJWZzBPRFpPZWpKalZHRjZUVE55UkVsdGRVUnNORloxYUdWd1pFSmtTVDBHYzNSeWFXNW5EQTRBREhKbGNYVmxjM1JsWkZWU1RBWnpkSEpwYm1jTUt3QXBhSFIwY0RvdkwzaHBMWE5oZEM1bGJtY3ViblYwWVc1cGVDNWpiMjB2Y0hKdmJXVjBhR1YxY3k4R2MzUnlhVzVuRENzQUtXaDBkSEE2THk5NGFTMXpZWFF1Wlc1bkxtNTFkR0Z1YVhndVkyOXRMM0J5YjIxbGRHaGxkWE12QTJsdWRBUUNBQUk9fEigLUf7d7pTeMNzHFPq3VzUWAsRyrHe9MCM3Dd89Zij] Dnt:[1]] {} <nil> 0 [] false xi-sat.eng.a.com:9091 map[] map[] <nil> map[] 10.3.254.101:54809 /auth?code=e921fc2b5ea3c0a5007a&state=v%2Fn9PnQSQq6LmX486Nz2cTazM3rDImuDl4VuhepdBdI%3D <nil> <nil> <nil> 0xc42018f680}\n"
time="2018-09-20T08:06:25Z" level=debug msg=/auth
time="2018-09-20T08:06:25Z" level=error msg="oauth2: cannot fetch token: 401 Unauthorized\nResponse: {\"message\":\"Bad credentials\",\"documentation_url\":\"https://developer.github.com/enterprise/2.13/v3\"}"
time="2018-09-20T08:06:25Z" level=debug msg="Request handled successfully"
time="2018-09-20T08:06:25Z" level=debug msg="statuscode: <nil>"
time="2018-09-20T08:06:25Z" level=info msg="|\x1b[97;42m 200 \x1b[0m|   92.752547ms | 10.3.254.101:54809 | GET xi-sat.eng.a.com:9091 /auth | https://drt-it-github-prod-1.eng.a.com/"```

/auth User is not authorized. %!s(<nil>) Please try again.

The string literal '%!s()' is output where a reason is supposed to go.

It's also logged: time="2019-03-14T21:07:06Z" level=error msg="<nil>"

It appears to be happening here:

renderIndex(w, fmt.Sprintf("/auth User is not authorized. %s Please try again.", err))

VerifyUser(user) is returning !ok but err = nil. I believe err is set to nil here: https://github.com/vouch/vouch-proxy/blame/a83233064598b1a62ed8aff1ae07caa771f1f10c/handlers/handlers.go#L341

My config has a whiteList of email addresses and is set up for Google oauth.

Alternate domain not respected

In my Lasso config file I have:

allowAllUsers: true

and I've commented out the 'domains' part. I hope this would allow users whose usernames are their emails and their emails are from different domains to login. however it seems that lasso forbids this. I can login fine if my email domain matches the domain of the server that lasso is protecting, but not if it's a alternate email domain (eg. gmail.com).

Have I configured something wrongly ? Or is this expected behaviour ?

Thanks,
Phil

Token secrets are generated insecurely

If a token isn't explicitly provided, vouch generates one using a non-cryptographic random number generator seeded with the current time in nanoseconds:

vouch-proxy/pkg/cfg/cfg.go

Lines 384 to 390 in 233ffee

log.Warn("generating random jwt.secret and storing it in " + secretFile)
rand.Seed(time.Now().UnixNano())
b := make([]byte, secretLen)
for i := range b {
b[i] = charRunes[rand.Intn(len(charRunes))]
}

Vouch has only existed for 2 years, or about 2^56 nanoseconds, so this code could only ever have generated one of 2^56 secrets. That's plausibly in the realm of brute force, especially since vouch uses HS256 which is just non-iterated SHA256.

This code should be using crypto/rand.

Even if the RNG problem is fixed, a secret with 18 characters chosen from "a-z A-Z 0-9 except no l, o, O" (why exclude those characters??) could only ever have log2(54^18) or about 104 bits of entropy. The definition of HS256 says:

A key of the same size as the hash output (for instance, 256 bits for "HS256") or larger MUST be used with this algorithm.

Please consider using something like this library to generate a string with at least 32 bytes of randomness.

Passing original JWT through as a header

Would it be possible to pass the original JWT (from the openid provider) back as a header from the validate request?

I'm trying to use nginx/lasso in front of the istio gateway, and if I could use lasso to do the openid redirection and pass on the jwt to istio, I could then use istio authorization.

Other data from IdP call to be made available in headers

Feature request:

In the same vein as X-Lasso-user holds the email/user info and this can be passed back to nginx and upstream, it would be nice if any other information made available via the identity provider such as first name etc could also be made available to nginx.

[FEATURE REQ] google authenticator?

is there a way to use lasso to authenticate with the offline google authenticator tokens (like from the android app) ?

i see it has the ability to use google's OAUTH but it would be great if it could allow users to login by using the password generated from the app.

thanks!

Allow multiple callback_urls for all backends

In principle one vouch proxy instance can be used to authenticate users on different vhosts. Putting the nginx config for vouch in a separate file and including it for different vhosts adds a lot of convenience. Such setup currently almost works and only fails at the callback since only a single callback url can be specified in the vouch config. Only the google backend already allows for multiple callback_urls. As can be seen below, it chooses the callback url that matches the identified domain.

if cfg.GenOAuth.Provider == cfg.Providers.Google {
// If the provider is Google, find a matching redirect URL to use for the client
domain := domains.Matches(r.Host)
log.Debugf("looking for redirect URL matching %v", domain)
for i, v := range cfg.GenOAuth.RedirectURLs {
if strings.Contains(v, domain) {
log.Debugf("redirect value matched at [%d]=%v", i, v)
cfg.OAuthClient.RedirectURL = v
break
}
}

To enable using one vouch proxy on different vhosts, it would be great to move the code out of the if-statement and apply this logic to all backends.

Error - no bucket for users

When I try to authenticate a user I have this error:

ERRO[0014] no bucket for users
ERRO[0014] key required
2018/09/05 23:20:59 http: panic serving 127.0.0.1:57072: interface conversion: interface is nil, not string
goroutine 11 [running]:
net/http.(*conn).serve.func1(0xc420055600)
/usr/lib/go/src/net/http/server.go:1491 +0x12a
panic(0x8a1c00, 0xc420012e40)
/usr/lib/go/src/runtime/panic.go:458 +0x243
github.com/LassoProject/lasso/handlers.CallbackHandler(0xb3af00, 0xc42010fad0, 0xc4200b2b40)
/root/go/src/github.com/LassoProject/lasso/handlers/handlers.go:414 +0x894
net/http.HandlerFunc.ServeHTTP(0x960320, 0xb3af00, 0xc42010fad0, 0xc4200b2b40)
/usr/lib/go/src/net/http/server.go:1726 +0x44
github.com/LassoProject/lasso/pkg/timelog.TimeLog.func1(0xb3af00, 0xc42010fad0, 0xc4200b2a50)
/root/go/src/github.com/LassoProject/lasso/pkg/timelog/timelog.go:33 +0x14b
net/http.HandlerFunc.ServeHTTP(0xc42012b660, 0xb3af00, 0xc42010fad0, 0xc4200b2a50)
/usr/lib/go/src/net/http/server.go:1726 +0x44
net/http.(*ServeMux).ServeHTTP(0xc420136780, 0xb3af00, 0xc42010fad0, 0xc4200b2a50)
/usr/lib/go/src/net/http/server.go:2022 +0x7f
net/http.serverHandler.ServeHTTP(0xc420054b80, 0xb3af00, 0xc42010fad0, 0xc4200b2a50)
/usr/lib/go/src/net/http/server.go:2202 +0x7d
net/http.(*conn).serve(0xc420055600, 0xb3b780, 0xc420139400)
/usr/lib/go/src/net/http/server.go:1579 +0x4b7
created by net/http.(*Server).Serve
/usr/lib/go/src/net/http/server.go:2293 +0x44d

Can't logout

Hi,

I tried the following :

  • delete VouchCookie
  • go to vouch.mydomain.com/logout
  • go to google.com/accounts/logout

But I still can access my app. Is there any way to logout ?

User name not put into headers

When I use this with Okta , while it authenticates, I am unable to get the username in the x-lasso-user header passed to my proxied server. As far as I can see I'm following the instructions laid out in the wiki. I'd just like to verify whether this 'should' work and whether anyone has any ideas what may be wrong here.

Thanks,
Phil

offer an alpine Dockerfile (in addition to existing scratch)

Hi,

A suggestion would be to use alpine instead of scratch for the container, which means it will be a few MB larger but quay will support the security scan as well as make it possible (easier) to troubleshoot since cat / sh etc is there.

I've also noted that ENTRYPOINT doesn't support to change the initial command, so maybe change that to CMD instead.

I hit some issues when I had to troubleshoot the config generation from a consul template and the only solution to actually do "cat /config/config.yml" was to change both of those things.

OAuth Provider logout?

Can the OAuth provider logout be implemented? For Okta, this would require the passing an id_token.. which could be obtained using the access_token obtained obtained here:

providerToken, err := cfg.OAuthClient.Exchange(oauth2.NoContext, r.URL.Query().Get("code"))

How to make vouch to secure https?

Unless I didn't see it, the README doesn't talk about how to enable secure https. If I wanted to provide my own certs, where would I put them? Btw, the latest NGINX complains about non-secure connections - suspect those are from using the vouch server section (running with Chrome, F12 and monitoring Network traffic). Great app! This was the only complete openid client solution I found that actually works in a production environment.

Invalid session state

Hi. Trying to use this library and having some issues. Getting the following error message and not sure what it means.

> map[] 192.168.96.3:32998 /auth <nil> <nil> <nil> 0xc420155480}\n"
auth_1   | time="2018-09-10T02:28:33Z" level=debug msg=/auth
auth_1   | time="2018-09-10T02:28:33Z" level=error msg="Invalid session state: stored %!s(<nil>), returned "
auth_1   | time="2018-09-10T02:28:33Z" level=debug msg="Request handled successfully"
auth_1   | time="2018-09-10T02:28:33Z" level=debug msg="statuscode: <nil>"

Here is the repo I am working from: https://github.com/i8ramin/nginx-lasso

"401 Authorization Required" and "no jwt found in request"

Hi guys,
I would be very appreciated for any help.
I'm using Kibana both with searchguard and nginx for security, and it's configured and working.
Now I want to use lasso for aouth Google authentication for this Kibana.

I followed the steps described here, created a web application in Google, created lasso conf file with all the needed credentials, configured nginx, but when trying to run the URL, I'm getting
"401 Authorization Required" in the browser , and "no jwt found in request" when running lasso.

Here are the logs from lass (I ran it with debug level) -

DEBU[0009] Request received : &{GET /validate HTTP/1.0 1 0 map[Cookie:[csrftoken_sef_debug=7uZzJbZz7Jej1ZLxMHPU1Oiek7YkmUlX; sessionid_sef_debug=rd72gr9de0lo72immbyj7icjlfyfuqu4; _ga=GA1.2.1902745027.1517923862; visid_incap_391285=8oI8BuviRLWM+YSe7/B5IG+0p1oAAAAAQUIPAAAAAADRWNzfHXqvVnSA/H0xeNVt; sessionid_sef=b4t2h1utxzt53tnfx0oeh4mtcnjks7qr; csrftoken_sef=c9JVq8t5qI6RuCynMIE7RZTqDDU5tLCl; ajs_user_id=null; ajs_group_id=null; ajs_anonymous_id=%228b201204-09fd-487c-807d-579ee2f709f1%22; mp_6e3b5ef17b23d8a98ce9b62a8b6ff467_mixpanel=%7B%22distinct_id%22%3A%20%221668669b7ed619-067a5dcbbf9115-346c780e-1fa400-1668669b7ee57b%22%2C%22mp_lib%22%3A%20%22Segment%3A%20web%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C%22%24initial_referring_domain%22%3A%20%22%24direct%22%7D] Purpose:[prefetch] Upgrade-Insecure-Requests:[1] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8] Accept-Language:[en-US,en;q=0.9,he;q=0.8,ru;q=0.7,uk;q=0.6] Connection:[close] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36] Accept-Encoding:[gzip, deflate, br]] {} <nil> 0 [] true 127.0.0.1:9090 map[] map[] <nil> map[] 127.0.0.1:40952 /validate <nil> <nil> <nil> 0xc000061dc0}
DEBU[0009] /validate
ERRO[0009] no jwt found in request
DEBU[0009] domain matched array value at [0]=XXXX.com
DEBU[0009] CaptureWriter.WriteHeader set w.StatusCode 401
DEBU[0009] Request handled successfully: 401
INFO[0009] | 401 |   92.999µs /validate      avgLatency="  92.999µs" host="127.0.0.1:9090" ipPort="127.0.0.1:40952" latency="  92.999µs" method=GET path=/validate referer= request=1 statusCode=401
DEBU[0010] Request received : &{GET /validate HTTP/1.0 1 0 map[Cookie:[csrftoken_sef_debug=7uZzJbZz7Jej1ZLxMHPU1Oiek7YkmUlX; sessionid_sef_debug=rd72gr9de0lo72immbyj7icjlfyfuqu4; _ga=GA1.2.1902745027.1517923862; visid_incap_391285=8oI8BuviRLWM+YSe7/B5IG+0p1oAAAAAQUIPAAAAAADRWNzfHXqvVnSA/H0xeNVt; sessionid_sef=b4t2h1utxzt53tnfx0oeh4mtcnjks7qr; csrftoken_sef=c9JVq8t5qI6RuCynMIE7RZTqDDU5tLCl; ajs_user_id=null; ajs_group_id=null; ajs_anonymous_id=%228b201204-09fd-487c-807d-579ee2f709f1%22; mp_6e3b5ef17b23d8a98ce9b62a8b6ff467_mixpanel=%7B%22distinct_id%22%3A%20%221668669b7ed619-067a5dcbbf9115-346c780e-1fa400-1668669b7ee57b%22%2C%22mp_lib%22%3A%20%22Segment%3A%20web%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C%22%24initial_referring_domain%22%3A%20%22%24direct%22%7D] Connection:[close] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-US,en;q=0.9,he;q=0.8,ru;q=0.7,uk;q=0.6]] {} <nil> 0 [] true 127.0.0.1:9090 map[] map[] <nil> map[] 127.0.0.1:40954 /validate <nil> <nil> <nil> 0xc00014c040}
DEBU[0010] /validate
ERRO[0010] no jwt found in request
DEBU[0010] domain matched array value at [0]=XXXX.com
DEBU[0010] CaptureWriter.WriteHeader set w.StatusCode 401
DEBU[0010] Request handled successfully: 401
INFO[0010] | 401 |   85.874µs /validate      avgLatency="  89.437µs" host="127.0.0.1:9090" ipPort="127.0.0.1:40954" latency="  85.874µs" method=GET path=/validate referer= request=2 statusCode=401
DEBU[0010] Request received : &{GET /validate HTTP/1.0 1 0 map[Accept-Language:[en-US,en;q=0.9,he;q=0.8,ru;q=0.7,uk;q=0.6] Cookie:[csrftoken_sef_debug=7uZzJbZz7Jej1ZLxMHPU1Oiek7YkmUlX; sessionid_sef_debug=rd72gr9de0lo72immbyj7icjlfyfuqu4; _ga=GA1.2.1902745027.1517923862; visid_incap_391285=8oI8BuviRLWM+YSe7/B5IG+0p1oAAAAAQUIPAAAAAADRWNzfHXqvVnSA/H0xeNVt; sessionid_sef=b4t2h1utxzt53tnfx0oeh4mtcnjks7qr; csrftoken_sef=c9JVq8t5qI6RuCynMIE7RZTqDDU5tLCl; ajs_user_id=null; ajs_group_id=null; ajs_anonymous_id=%228b201204-09fd-487c-807d-579ee2f709f1%22; mp_6e3b5ef17b23d8a98ce9b62a8b6ff467_mixpanel=%7B%22distinct_id%22%3A%20%221668669b7ed619-067a5dcbbf9115-346c780e-1fa400-1668669b7ee57b%22%2C%22mp_lib%22%3A%20%22Segment%3A%20web%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C%22%24initial_referring_domain%22%3A%20%22%24direct%22%7D] Connection:[close] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36] Accept:[image/webp,image/apng,image/*,*/*;q=0.8] Referer:[https://jopa-test.XXXX.com/] Accept-Encoding:[gzip, deflate, br]] {} <nil> 0 [] true 127.0.0.1:9090 map[] map[] <nil> map[] 127.0.0.1:40956 /validate <nil> <nil> <nil> 0xc00014c280}

HERE IS MY LASSO CONF FILE

lasso:
  domains:
  - XXXX.com

  whiteList:
  - [email protected]

  jwt:
    secret: vaaicBMUfIhtk8caV1
    maxAge: 10080

oauth:
  provider: google
  # get credentials from...
  # https://console.developers.google.com/apis/credentials
  client_id: 689617171583-7c8bpguvib6arojo4eb6t7dbkstkqnqk.apps.googleusercontent.com
  client_secret: aFUzAkj26Rp6Dt8ZcfC-eP8e
  callback_urls:
  - http://127.0.0.1:9090/auth
  preferredDomain: XXXX.com

HERE IS MY NGINX FILE

server {
    listen       443;

     ssl on;
     ssl_certificate /etc/nginx/ssl_cert/wild_pipl_com.pem;  ## Replace with your own certificate
     ssl_certificate_key /etc/nginx/ssl_cert/wild_pipl_com.key;  ## Replace with your own key
     server_name  jopa-test.XXXX.com;
     auth_request /validate;



    location = /validate {
      # lasso can run behind the same nginx-revproxy
      # May need to add "internal", and comply to "upstream" server naming
      proxy_pass http://127.0.0.1:9090;

      # lasso only acts on the request headers
      proxy_pass_request_body off;
      proxy_set_header Content-Length "";

      # pass X-Lasso-User along with the request
      auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user;

      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_lasso_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount;
    }


     if validate returns `401 not authorized` then forward the request to the error401block
#    error_page 401 = @error401;

#    location @error401 {
         redirect to lasso for login
#        return 302 https://jopa-test.XXXX.com/login?url=$scheme://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err;
#    }


#    location / {
#      auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user;
#     proxy_set_header X-Lasso-User $auth_resp_x_lasso_user;
#    }

    location / {
      proxy_pass http://es-k8s-001.XXXX.pro:5601;
#      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#      proxy_set_header x-proxy-user admin;
#      proxy_set_header x-proxy-roles admin;
      proxy_set_header X-Lasso-User $auth_resp_x_lasso_user;
      proxy_set_header Host es-k8s-001.XXXX.pro;
    }
}

Could you assist please?

Thx!

Aleksei

redirect issue

Hi-

So we use Okta internally here and I think this would be a nice addition to the toolbox, however it's somewhat difficult to test. I tried to 'fake out' lasso a bit with nginx so I'm thinking that's my problem.

I think my lasso config is correct, because it seems to generate the proper redirect URL, but it doesn't actually redirect to Okta.

Here's my lasso config:

oauth:

Generic OpenID Connect

provider: oidc
client_id:
client_secret:
auth_url: https://dev-747150.oktapreview.com/oauth2/authorize
token_url: https://dev-747150.oktapreview.com/oauth2/token
user_info_url: https://dev-747150.oktapreview.com/oauth2/userinfo
scopes:
- openid
- email
callback_url: http://ec2-18-234-210-151.compute-1.amazonaws.com:81/auth

Here's my nginx config:

server {
listen 80;
server_name ec2-18-234-210-151.compute-1.amazonaws.com;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   html;
        index  index.html index.htm;
    }

    auth_request /lasso-validate;

    location = /lasso-validate {
    # This address is where Lasso will be listening on
            proxy_pass http://127.0.0.1:9090/validate;
            proxy_pass_request_body off; # no need to send the POST body

            proxy_set_header Content-Length "";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

    # these return values are passed to the @error401 call
            auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt;
            auth_request_set $auth_resp_err $upstream_http_x_lasso_err;
            auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount;

#error_page 404 /404.html;
error_page 401 = @error401;

    # If the user is not logged in, redirect them to Lasso's login URL

location @error401 {
return 302 http://ec2-18-234-210-151.compute-1.amazonaws.com:81/login?url=http://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err;
}
server {
listen 81 ;
server_name ec2-18-234-210-151.compute-1.amazonaws.com;

#location / {

root html;

#        index  index.html index.htm;
 #   }

#ssl_certificate /etc/letsencrypt/live/login.avocado.lol/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/login.avocado.lol/privkey.pem;

Proxy to your Lasso instance

location / {
proxy_set_header Host ec2-18-234-210-151.compute-1.amazonaws.com;
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://127.0.0.1:9090;
}
}

the 'fake out' is instead of any real domains, I'm just using a single one, with servers on different ports (one nginx). For the login (really a proxy for the lasso server), i'm just pointing to a different port (81), but the same domain (which I suspect is the real problem, because of the lassoCookie?).

So what happens is that I go to the root (port 80), it redirects to the lasso login (at port 81).. and then I see this in the page:

302 redirect to: https://dev-747150.oktapreview.com/oauth2/authorize?client_id=&redirect_uri=http%3A%2F%2Fec2-18-234-210-151.compute-1.amazonaws.com%3A81%2Fauth&response_type=code&scope=openid+email&state=e9ozknFuNrWWr76NFnUIn1JNQqOdBlEYV%2BmUOsPqy%2Bo%3D.
login
logout
validate
http://18.234.210.151

https://dev-747150.oktapreview.com/oauth2/authorize?client_id=&redirect_uri=http%3A%2F%2Fec2-18-234-210-151.compute-1.amazonaws.com%3A81%2Fauth&response_type=code&scope=openid+email&state=e9ozknFuNrWWr76NFnUIn1JNQqOdBlEYV%2BmUOsPqy%2Bo%3D
For support, please contact your network administrator or whomever setup nginx to use Lasso.
For help with Lasso or to file a bug report, please see the project page at https://github.com/LassoProject/lasso

the links actually work to Okta so I think that's all correct.. just doesn't finish the 302. I'm thinking that it's because I don't have a real server set up.

I was just trying to see if I could get the redirect to work and then I would try it with a real service, but maybe not possible.

Flexible structures?

Any idea how to approach this with configurable storage/model/structures?
I've configured this almost all the way but I have problem with user.Id being int...

Error when getting token

After receiving the id token Lasso is failing with the following error.

Logs:

time="2018-09-07T18:11:26Z" level=info msg="OpenID userinfo body: {\"sub\":\"*************************"}\r\n" time="2018-09-07T18:11:26Z" level=debug msg="{ 0 0 0}" time="2018-09-07T18:11:26Z" level=debug msg="no domains configured" time="2018-09-07T18:11:26Z" level=error msg="no bucket for users" time="2018-09-07T18:11:26Z" level=debug msg="new user.. setting created on to 1536343886" time="2018-09-07T18:11:26Z" level=error msg="key required" time="2018-09-07T18:11:26Z" level=debug msg="token: &{ 0xc4201381c0 map[typ:JWT alg:HS256] { [] { 1536373886 0 Lasso 0 }} false}" time="2018-09-07T18:11:26Z" level=debug msg="token expires: 1536373886" time="2018-09-07T18:11:26Z" level=debug msg="diff from now: 30000" time="2018-09-07T18:11:26Z" level=debug msg="compressed string: H4sIAAAAAAAA_xzMwY6CMBRA0S8aMsOIkaUC4nuhJQGF4o7WRgpUKy6g_XqD25ubIy12PBUqVwgXB39UwRseRSAi2MJgWBVh6EmLI6-Phq_xO1BzSysHveGsnNWVdTP0z4WeiU-ccHl897MIjfgnK0waRh23GHqnn7HIgsQesGPaDS1N6ric9X6SRDcSmqnavFq91Lvl9xMAAP__MX4AgpkAAAA=" 2018/09/07 18:11:26 http: panic serving 192.168.0.2:34052: interface conversion: interface {} is nil, not string goroutine 62 [running]: net/http.(*conn).serve.func1(0xc4200d3720) /usr/local/go/src/net/http/server.go:1721 +0xd0 panic(0x8da480, 0xc42004f000) /usr/local/go/src/runtime/panic.go:489 +0x2cf github.com/dmadams/lasso/handlers.CallbackHandler(0xb8b580, 0xc4201089a0, 0xc4201b4600) /go/src/github.com/dmadams/lasso/handlers/handlers.go:415 +0xa3b net/http.HandlerFunc.ServeHTTP(0x97a408, 0xb8b580, 0xc4201089a0, 0xc4201b4600) /usr/local/go/src/net/http/server.go:1942 +0x44 github.com/dmadams/lasso/pkg/timelog.TimeLog.func1(0xb8b580, 0xc4201089a0, 0xc4201b4400) /go/src/github.com/dmadams/lasso/pkg/timelog/timelog.go:33 +0x14b net/http.HandlerFunc.ServeHTTP(0xc42000c540, 0xb8b580, 0xc4201089a0, 0xc4201b4400) /usr/local/go/src/net/http/server.go:1942 +0x44 net/http.(*ServeMux).ServeHTTP(0xc4201463c0, 0xb8b580, 0xc4201089a0, 0xc4201b4400) /usr/local/go/src/net/http/server.go:2238 +0x130 net/http.serverHandler.ServeHTTP(0xc420162000, 0xb8b580, 0xc4201089a0, 0xc4201b4400) /usr/local/go/src/net/http/server.go:2568 +0x92 net/http.(*conn).serve(0xc4200d3720, 0xb8bd80, 0xc4201ca080) /usr/local/go/src/net/http/server.go:1825 +0x612 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2668 +0x2ce
/usr/local/go/src/net/http/server.go:1825 +0x612
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:2668 +0x2ce`

No whitelist or domains configured -> allow all

The above appears to allow all users when neither a whitelist or domains are configured. Given the purpose of Vouch, configurations like that are almost certainly unintentional. There is the allowAllUsers variable for that.

bnfinet if you agree this should change I'm happy to take a stab at it and send a pull request.

GitHub provider default scope is R/W

Hi,

why does vouch default to requesting R/W access to all user data?
Read-only access seems to work fine. As long as OAuth is only used for authentication, I think this should become the default.

oauth:
  scopes: read:user

GenOAuth.Scopes = []string{"user"}

Cheers!

Support custom OAuth servers in config

I'd love to be able to change the OAuth server that this uses to a custom server. Given that it's using the generic OAuth client, it looks like you'd just need to add a few settings to the config.yml file.

The OAuth client [1] seems to take the following config values: ClientID, ClientSecret, Scopes and Endpoint which contains both the authorization and token endpoints. [2] Moving these to the config file should make it super easy to use with any OAuth 2 server!

Infinite re-directs when I set `allowAllUsers: false`.

I have included a config below which works with github as my auth provider. I have tested this; once I authenticate with github, I am redirected back to my protected endpoint and everything is great.

The problem: I wish to define allowed users in the whitelist, so only a few friends can get access to my protected endpoint. For this reason I change allowAllUsers: false. The whitelist is already defined.

Immediately upon restarting the service (docker kill vouch-proxy ; docker rm vouch-proxy followed by the docker run command below) I hit the private endpoint in my browser, and enter an infinite loop betwen login.example.com and github.com, until github asks me to re-authorize the request due to too many attempts. At one point I got a short rate ban.

My issues seem similar to this thread logged by @brettp What I took from that thread was not to list all the subdomains (private.example.com, login.example.com) under vouch.domains which I have followed.

I'm not sure what's wrong with my config. I'm hoping it's something obvious. I'm not sure if I've used incorrect YML syntax/indentation anywhere. I can add further information if required.

I launch it with:

docker run -d \
    -p 9090:9090 \
    --name vouch-proxy \
    -v ${PWD}/config:/config \
    -v ${PWD}/data:/data \
    voucher/vouch-proxy

My config.yml:

vouch:
  # logLevel: debug
  logLevel: info
  listen: 0.0.0.0
  port: 9090

  # domains
  # each of these domains must serve the url https://vouch.$domains[0] https://vouch.$domains[1] ...
  # so that the cookie which stores the JWT can be set in the relevant domain
  # usually you'll just have one.
  # Comment this out if you set allowAllUser:true
  domains:
   - example.com
  # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider
  allowAllUsers: true

  # Setting publicAccess: true will accept all requests, even without a cookie. 
  # If the user is logged in, the cookie will be validated and the user header will be set.
  # You will need to direct people to the Vouch Proxy login page from your application.
  publicAccess: false

  # whiteList (optional) allows only the listed usernames
  # usernames are usually email addresses (google, most oidc providers) or login/username for github and github enterprise
  whiteList:
  - vulcan25
  - anotheruser
    
  jwt:
    # secret: a random string used to cryptographically sign the jwt
    # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes)
    # if the secret is not set here then..
    # look for the secret in `./config/secret`
    # if `./config/secret` doesn't exist then randomly generate a secret and store it there
    # in order to run multiple instances of vouch on multiple servers (perhaps purely for validating the jwt),
    # you'll want them all to have the same secret
    secret: TOTALLY_SECRET_STRING
    issuer: Vouch
    # number of minutes until jwt expires
    maxAge: 240
    # compress the jwt
    compress: true

  cookie: 
    # name of cookie to store the jwt
    name: VouchCookie
    # optionally force the domain of the cookie to set
    domain: example.com
    secure: true
    httpOnly: true

  session:
    # just the name of session variable stored locally
    name: vouchSession

  headers:
    jwt: X-Vouch-Token
    querystring: access_token
    redirect: X-Vouch-Requested-URI

  db: 
    file: data/vouch_bolt.db

  # testing: force all 302 redirects to be rendered as a webpage with a link
  #testing: true
  # test_url: add this URL to the page which vouch displays
  #test_url: http://yourdomain.com
  # webapp: WIP for web interface to vouch (mostly logs)
  webapp: true

#
# OAuth Provider
# configure ONLY ONE of the following oauth providers
#
oauth:

  # GitHub
  # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/
  provider: github
  client_id: myclientid
  client_secret: mysecretkey
  callback_urls:
   - https://login.example.com/auth
  scopes:
   - ''

Too many redirects issue

I looked through what appear to be related (closed) issues, but was not able to find a solution to my problem. I hope you can help.

I have Lasso (compiled binary, not docker container) running on one host, proxied behind NGINX with SSL, with its own hostname (lasso.[domain].com). I have a basic NGINX static site for testing with Lasso, running on a separate host, with its own hostname (foo.[domain].com), also with SSL. I've tried to follow several guides for configuring both NGINX and Lasso. Here's what I see:

When I hit the static site in Chrome, I'm redirected to the Google "Sign in" page. In my static site's NGINX access.log, I see the expected 302 redirect to Lasso; Lasso shows no jwt found in request, a 401 from /validate, then a 302 from /login. Back in the browser, I enter my email address and password (I've got allowAllUsers: true in my Lasso config.yml, along with a whitelist specifying my email address). My address bar shows https://accounts.youtube.com/accounts/SetSID for a bit, then I get a "too many redirects" error. In the logs, I see a long series of duplicate 302 redirects on the static-site side to that https://accounts.youtube.com/accounts/SetSID address, and on the Lasso side a google userinfo body JSON block that appears to be correct information about my account, but followed by a long series of /auth -> no jwt found in request -> /validate -> /login -> google userinfo body -> [loop]. I have some Lasso debug log output, too, and nothing looks like an error.

Here are what I hope are the relevant portions on my configs:

Static site nginx.conf:

http {

  server {

    listen 443 ssl http2;
    server_name foo.[domain].com;
    root /usr/share/nginx/html;

    ssl_certificate /etc/pki/nginx/server.crt;
    ssl_certificate_key /etc/pki/nginx/private/server.key;

    auth_request /validate;

    location /validate {
      proxy_pass https://lasso.[domain].com;
      proxy_pass_request_body off;
      proxy_set_header Content-Length "";
      auth_request_set $auth_resp_err $upstream_http_x_lasso_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount;
      auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt;
      auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user;
    }

    error_page 401 = @error401;

    location @error401 {
      return 302 https://lasso.[domain].com/login?url=$scheme://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    location / {
      auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user;
      proxy_set_header X-Lasso-User $auth_resp_x_lasso_user;
    }

  }

}

Lasso nginx.conf:

http {

  server {
    listen 443 ssl http2;
    server_name lasso.[domain].com;
    ssl_certificate /etc/pki/nginx/server.crt;
    ssl_certificate_key /etc/pki/nginx/private/server.key;
    location / {
      proxy_set_header Host lasso.[domain].com;
      proxy_pass http://127.0.0.1:9090;
    }
  }

}

Lasso config.yml:

lasso:
  logLevel: debug
  allowAllUsers: true
  whiteList:
  - [address]@[domain].com
  jwt:
    secret: ...
    issuer: Lasso
    maxAge: 1
    compress: true
oauth:
  provider: google
  client_id: ...
  client_secret: ...
  callback_urls:
    - https://lasso.[domain].com/auth

Any ideas where I might be going wrong here?

improved error handling for `/auth` endpoint

as a follow up to PR #46

  • might be time to have renderError routine similar to renderIndex in handlers.go
  • look for error_uri callback parameter in addition to error_description and report to the end user's browser
  • same for the value of error

OIDC Discovery support?

Instead of setting all the URLs individually, can we use OIDC discovery?

e.g. specify server url and then use /.well-known/openid-configuration

Catch error when redirect URL is not set

I managed to crash Lasso by attempting the login flow without setting a URL to redirect to, e.g. just hitting https://login.example.org/login without ?url=....

The error happens when it's trying to build the redirect URL here.

http: panic serving 127.0.0.1:63233: interface conversion: interface {} is nil, not string
goroutine 4 [running]:
net/http.(*conn).serve.func1(0xc42019e000)
	/usr/local/go/src/net/http/server.go:1697 +0xd0
panic(0x149fc20, 0xc420195400)
	/usr/local/go/src/runtime/panic.go:491 +0x283
github.com/bnfinet/lasso/handlers.CallbackHandler(0x177e580, 0xc4201b2000, 0xc4201a2200)
	/Users/aaronpk/go/src/github.com/bnfinet/lasso/handlers/handlers.go:389 +0xc06
net/http.HandlerFunc.ServeHTTP(0x1540648, 0x177e580, 0xc4201b2000, 0xc4201a2200)
	/usr/local/go/src/net/http/server.go:1918 +0x44
github.com/bnfinet/lasso/pkg/timelog.TimeLog.func1(0x177e580, 0xc4201b2000, 0xc4201a2000)
	/Users/aaronpk/go/src/github.com/bnfinet/lasso/pkg/timelog/timelog.go:33 +0x143
net/http.HandlerFunc.ServeHTTP(0xc4200f1a60, 0x177e580, 0xc4201b2000, 0xc4201a2000)
	/usr/local/go/src/net/http/server.go:1918 +0x44
net/http.(*ServeMux).ServeHTTP(0xc4201745d0, 0x177e580, 0xc4201b2000, 0xc4201a2000)
	/usr/local/go/src/net/http/server.go:2254 +0x130
net/http.serverHandler.ServeHTTP(0xc42016f040, 0x177e580, 0xc4201b2000, 0xc4201a2000)
	/usr/local/go/src/net/http/server.go:2619 +0xb4
net/http.(*conn).serve(0xc42019e000, 0x177ed00, 0xc42005a080)
	/usr/local/go/src/net/http/server.go:1801 +0x71d
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2720 +0x288

ADFS support / top level config elements are only `vouch` and `oauth`

Hi,

Sorry if this is me not understanding Go. I've been looking at an issue where my cookie.domain isn't being set for the cookies.

I've forked and built the project and added the following:
log.Debugf("temp debug - cookie: %v", cfg.Cfg.Cookie)

Which is returned like this:
time="2019-02-05T10:17:18Z" level=debug msg="temp debug - cookie: {VouchCookie false true}"

I can see, at startup, that it is configured. Seems like cookie.go isn't using the configuration set?

Am I just doing everything wrong here or is there a bug?

502 Bad Gateway

I have been trying to get this up and running for the last couple of days, but have been unsuccessful. Can someone point out what I am doing wrong?

I am running lasso in docker and encounter a 502 error when I am redirected to the lasso login. I am trying to authenticate using nginx. It looks like the none of the upstream variables are being set properly, but I am quite new to this area.

time="2018-12-29T11:36:44-05:00" level=debug msg=/validate
time="2018-12-29T11:36:44-05:00" level=error msg="no jwt found in request"
time="2018-12-29T11:36:44-05:00" level=debug msg="CaptureWriter.WriteHeader set w.StatusCode 401"
time="2018-12-29T11:36:44-05:00" level=debug msg="Request handled successfully: 401"
time="2018-12-29T11:36:44-05:00" level=info msg="|401|   86.556µs /validate" avgLatency=" 179.024µs" host="192.168.10.32:9090" ipPort="172.26.0.1:35670" latency="  86.556µs" method=GET path=/validate referer= request=4 statusCode=401 time="2018-12-29T11:36:44-05:00" level=debug msg="Request received : &{GET /login?url=https://REDACTED_URL/&lasso-failcount=&X-Lasso-Token=&error= HTTP/1.0 1 0 map[Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-CA,en;q=0.9,fr;q=0.8,en-GB;q=0.7,en-US;q=0.6] X-Forwarded-Proto:[https] Connection:[close]] {} <nil> 0 [] true login.REDACTED_URL map[] map[] <nil> map[] 172.26.0.1:35674 /login?url=https://REDACTED_URL/&lasso-failcount=&X-Lasso-Token=&error= <nil> <nil> <nil> 0xc42018cf40}"
time="2018-12-29T11:36:44-05:00" level=debug msg=/login
time="2018-12-29T11:36:44-05:00" level=debug msg="session state set to t2G6AkxdPzmt0gLkakXEzWfefpZvYrwoE/roTARSOdU=" time="2018-12-29T11:36:44-05:00" level=debug msg="session requestedURL set to https://REDACTED_URL/"
time="2018-12-29T11:36:44-05:00" level=debug msg="saving session"
2018/12/29 11:36:44 http: panic serving 172.26.0.1:35674: runtime error: invalid memory address or nil pointer dereference
goroutine 21 [running]:
net/http.(*conn).serve.func1(0xc420081b80)
        /usr/local/go/src/net/http/server.go:1726 +0xd0
panic(0x8be1c0, 0xbf58b0)
        /usr/local/go/src/runtime/panic.go:502 +0x229
github.com/LassoProject/lasso/handlers.loginURL(0xc4201ca000, 0xc420084cc0, 0x2c, 0xc420181120, 0x0)
        /go/src/github.com/LassoProject/lasso/handlers/handlers.go:62 +0x40
github.com/LassoProject/lasso/handlers.LoginHandler(0x9ae8a0, 0xc420181120, 0xc4201ca000)
        /go/src/github.com/LassoProject/lasso/handlers/handlers.go:296 +0x7ad
net/http.HandlerFunc.ServeHTTP(0x96bee0, 0x9ae8a0, 0xc420181120, 0xc4201ca000)
        /usr/local/go/src/net/http/server.go:1947 +0x44
github.com/LassoProject/lasso/pkg/timelog.TimeLog.func1(0x9af5e0, 0xc420130700, 0xc42012be00)
        /go/src/github.com/LassoProject/lasso/pkg/timelog/timelog.go:47 +0x17b
net/http.HandlerFunc.ServeHTTP(0xc4200f3fa0, 0x9af5e0, 0xc420130700, 0xc42012be00)
        /usr/local/go/src/net/http/server.go:1947 +0x44
net/http.(*ServeMux).ServeHTTP(0xc420171dd0, 0x9af5e0, 0xc420130700, 0xc42012be00)
        /usr/local/go/src/net/http/server.go:2340 +0x130
net/http.serverHandler.ServeHTTP(0xc42017b040, 0x9af5e0, 0xc420130700, 0xc42012be00)
        /usr/local/go/src/net/http/server.go:2697 +0xbc
net/http.(*conn).serve(0xc420081b80, 0x9afca0, 0xc42018cec0)
        /usr/local/go/src/net/http/server.go:1830 +0x651
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2798 +0x27b

Here is my relevant nginx config:

server {
    listen 443 ssl;
    server_name login.REDACTED_URL;

    ssl_certificate /etc/letsencrypt/live/login.REDACTED_URL/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/login.REDACTED_URL/privkey.pem;

    # Proxy to your Lasso instance
    location / {
      proxy_set_header  Host  login.REDACTED_URL;
      proxy_set_header  X-Forwarded-Proto https;
      proxy_pass        http://127.0.0.1:9090;
    }
  }

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name REDACTED_URL;

    ssl_certificate /etc/letsencrypt/live/REDACTED_URL/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/REDACTED_URL/privkey.pem;

    # Any request to this server will first be sent to this URL
    auth_request /validate;

    location = /validate {
      # lasso can run behind the same nginx-revproxy
      # May need to add "internal", and comply to "upstream" server naming
      proxy_pass http://127.0.0.1:9090/validate;

      # lasso only acts on the request headers
      proxy_pass_request_body off;

      proxy_set_header Content-Length "";
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      # pass X-Lasso-User along with the request
      #auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user;

      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_lasso_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount;
    }

    # if validate returns `401 not authorized` then forward the request to the error401block
    error_page 401 = @error401;

    location @error401 {
        # redirect to lasso for login
        return 302 https://login.REDACTED_URL/login?url=$scheme://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    location / {
      
    }

    root /usr/share/nginx/html;
    index index.html;
  }

Any help would be greatly appreciated :)

Report an error when config is missing

I managed to spend half an hour bashing my head against the wall trying to figure out what was failing. Turns out I had commented out the generic line in the config file, so none of my settings were being applied. Rather than erroring out, Lasso promptly redirected me to an OAuth URL with no host name, so was redirecting back to itself. It would have saved me a lot of time if it could have noticed that there were no OAuth settings defined in the config instead!

Can tagged builds be turned on?

In the automated build configuration, add a section to match all tags. This would allow us to have builds of releases, instead of having to follow a moving target.

multiple redirects.. I think I know why.. but confirming

so, over the weekend, i was able to get this (sorta) working with Okta.. I'm now getting the callback from okta..but it doesn't look like the JWT is set properly on the domain, so it goes into a redirect loop (with okta). I think it's because I don't have an actual live domain for the lasso service so it doesn't set the JWT correctly (but I'm not sure). Here is the output from lasso:

ERRO[0015] no jwt found in request
INFO[0015] | 401 | 120.372µs /validate avgLatency=66.802768ms host="127.0.0.1:9090" ipPort="127.0.0.1:49242" latency=" 120.372µs" method=GET path=/validate referer= request=7 statusCode=401
INFO[0015] | 302 | 242.791µs /login avgLatency=58.482771ms host=ec2-18-234-210-151.compute-1.amazonaws.com ipPort="127.0.0.1:49244" latency=" 242.791µs" method=GET path=/login referer= request=8 statusCode=302
INFO[0015] OpenID userinfo body: {"sub":"00u9cpj0gaOBYVZ4v0h7","email":"[email protected]","email_verified":true}
INFO[0015] | 302 | 208.432955ms /auth avgLatency=75.143902ms host=ec2-18-234-210-151.compute-1.amazonaws.com ipPort="127.0.0.1:49246" latency=208.432955ms method=GET path=/auth referer= request=9 statusCode=302
ERRO[0015] no jwt found in request
INFO[0015] | 401 | 71.296µs /validate avgLatency=67.636642ms host="127.0.0.1:9090" ipPort="127.0.0.1:49248" latency=" 71.296µs" method=GET path=/validate referer= request=10 statusCode=401
INFO[0015] | 302 | 256.479µs /login avgLatency=61.511173ms host=ec2-18-234-210-151.compute-1.amazonaws.com ipPort="127.0.0.1:49250" latency=" 256.479µs" method=GET path=/login referer= request=11 statusCode=302
INFO[0016] OpenID userinfo body: {"sub":"00u9cpj0gaOBYVZ4v0h7","email":"[email protected]","email_verified":true}

Initially nginx redirects to /auth (lasso), which redirects to Okta. I log into okta, and then it redirects back to /auth (lasso), which appears to extract my user info (I had thought from the JWT), but errors with no JWT found, which redirects to /validate back to /login back to Okta, which redirects back to /auth.. yada yada.

If you remember, I'm somewhat faking the 'lasso.mydomain.com' with a proxy set up on a different port, but the same domain. here:

server {
listen 81 ;
server_name ec2-18-234-210-151.compute-1.amazonaws.com;

#location / {

root html;

#        index  index.html index.htm;
 #   }

#ssl_certificate /etc/letsencrypt/live/login.avocado.lol/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/login.avocado.lol/privkey.pem;

Proxy to your Lasso instance

location / {
proxy_set_header Host ec2-18-234-210-151.compute-1.amazonaws.com;
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://127.0.0.1:9090;
}
}

instead of:

server {
listen 80 default_server;
server_name lasso.yourdomain.com;
location / {
proxy_set_header Host lasso.yourdomain.com;
proxy_pass http://127.0.0.1:9090;
}
}

there's a note about setting the setting the proxy header or the jwt isn't set correctly.. (this JWT is probably managed by lasso itself).

authenticating to Gluu auth server and retrieving user info after successful login

I'm using vouch-proxy to connect to a Gluu auth server using the following config:

# vouch config
# bare minimum to get vouch running with OpenID Connect (such as okta)

vouch:
  # domains:
  # valid domains that the jwt cookies can be set into
  # the callback_urls will be to these domains
  # domains:
  #- magnitudesurveys.com
  #- magnitudesurveys.co.uk

  logLevel: debug

  # - OR -
  # instead of setting specific domains you may prefer to allow all users...
  # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider
  allowAllUsers: true

testing: true

cookie:
  name: MSVouchCookie
  domain: magnitudesurveys.com
  secure: true
  httpOnly: true

oauth:
  # Generic OpenID Connect
  # including okta
  provider: oidc
  client_id: "@!XXXXXXXXXXXXX"
  client_secret: "XXXXXXXXXXXXX"
  auth_url: "https://sso.magnitudesurveys.com/oxauth/restv1/authorize"
  token_url: "https://sso.magnitudesurveys.com/oxauth/restv1/token"
  user_info_urls: "https://sso.magnitudesurveys.com/oxauth/restv1/userinfo"
  scopes:
    - email
    - openid
  callback_url: "https://login.magnitudesurveys.com/auth"

I'm getting the following error:

DEBU[0007] /auth
ERRO[0007] Get : unsupported protocol scheme ""

after logging in at gluu

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.