oauth2-proxy / oauth2-proxy

A reverse proxy that provides authentication with Google, Azure, OpenID Connect and many more identity providers.
https://oauth2-proxy.github.io/oauth2-proxy
MIT License
9.67k stars 1.58k forks source link

Cross Origin Credential SSO #116

Closed spprod35 closed 4 years ago

spprod35 commented 5 years ago

hello the community

I am setting up an ELK + Grafana server In order to add an authentication layer on Elasticsearch, I configured OAUTH2_Proxy.

For this service (ELK), in direct access, it works correctly.

On grafana, I configured the OAUTH, directly in the grafana.ini http://docs.grafana.org/auth/generic-oauth/ User authentication on grafana works. However, I want to pass Grafana's cookie credentials to ELK through a browser request (see attachment)

Your Environment

Nginx ELK Conf :

upstream elk_srv {
    server 10.22.13.143:9200;
}

#Redirect HTTPS
server {

    if ($host = elk.tvwonder.fr) {

        return 301 https://$host$request_uri;
    }
    listen 80;
    listen [::]:80;
    server_name elk.tvwonder.fr;
    return 404;
}

# HTTPS
server {

    server_name elk.tvwonder.fr;
    location ~ /\.well-known/acme-challenge {

        allow all;
    }

    # http2 pour Nginx >= 1.9.5
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    #root /var/www/elk.tvwonder.fr;
    #index index.html index.htm;
    error_log /var/log/nginx/elk.tvwonder.fr.log notice;
    access_log off;

    ####    Locations
    # On cache les fichiers statiques
    #location ~* \.(html|css|js|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires max; }
    # On interdit les dotfiles
    # location ~ /\. { deny all; }

    #### SSL
    ssl on;
    ssl_certificate /etc/letsencrypt/live/elk.tvwonder.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/elk.tvwonder.fr/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/elk.tvwonder.fr/fullchain.pem;

    # Google DNS, Open DNS, Dyn DNS
    resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 216.146.35.35 216.146.36.36 valid=300s;
    resolver_timeout 3s;

    ####    Session Tickets
    # Session Cache doit avoir la même valeur sur tous les blocs "server".
    ssl_session_tickets on;
    ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
    ssl_dhparam /etc/nginx/ssl/dhparam4.pem;

    ####    ECDH Curve
    ssl_ecdh_curve secp384r1;

    #### Location ####
    # OAuth2_Proxy
    location /oauth2 {

        proxy_pass http://localhost:4180;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 1;
        proxy_send_timeout 30;
        proxy_read_timeout 30;
        if ($request_method = 'POST') {
            add_header 'Access-Control-Allow-Origin' 'https://dashboard.tvwonder.fr';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' 'https://dashboard.tvwonder.fr';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
    }

    # Reverse Proxy ELK
    location / {

        auth_request /oauth2/auth;
        error_page 401 = /oauth2/sign_in;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # proxy_set_header X-Forwarded-Proto https;
        proxy_pass http://elk_srv;
        proxy_read_timeout 90;
        if ($request_method = 'POST') {

            add_header 'Access-Control-Allow-Origin' 'https://dashboard.tvwonder.fr';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {

            add_header 'Access-Control-Allow-Origin' 'https://dashboard.tvwonder.fr';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
    }
}

Javascript Console de grafana :

TypeError: Cannot create property '$$config' on string '
<!DOCTYPE html>
<html lang="en" charset="utf-8">
<head>
    <title>Sign In</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <style>
    body {
        font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
        font-size: 14px;
        line-height: 1.42857143;
        color: #333;
        background: #f0f0f0;
    }
    .signin {
        display:block;
        margin:20px auto;
        max-width:400px;
        background: #fff;
        border:1px solid #ccc;
        border-radius: 10px;
        padding: 20px;
    }
    .center {
        text-align:center;
    }
    .btn {
        color: #fff;
        background-color: #428bca;
        border: 1px solid #357ebd;
        -webkit-border-radius: 4;
        -moz-border-radius: 4;
        border-radius: 4px;
        font-size: 14px;
        padding: 6px 12px;
        text-decoration: none;
        cursor: pointer;
    }

    .btn:hover {
        background-color: #3071a9;
        border-color: #285e8e;
        text-decoration: none;
    }
    label {
        display: inline-block;
        max-width: 100%;
        margin-bottom: 5px;
        font-weight: 700;
    }
    input {
        display: block;
        width: 100%;
        height: 34px;
        padding: 6px 12px;
        font-size: 14px;
        line-height: 1.42857143;
        color: #555;
        background-color: #fff;
        background-image: none;
        border: 1px solid #ccc;
        border-radius: 4px;
        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
        -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
        -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
        transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
        margin:0;
        box-sizing: border-box;
    }
    footer {
        display:block;
        font-size:10px;
        color:#aaa;
        text-align:center;
        margin-bottom:10px;
    }
    footer a {
        display:inline-block;
        height:25px;
        line-height:25px;
        color:#aaa;
        text-decoration:underline;
    }
    footer a:hover {
        color:#aaa;
    }
    </style>
</head>
<body>
    <div class="signin center">
    <form method="GET" action="/oauth2/start">
    <input type="hidden" name="rd" value="/">

    <p>Authenticate using @tvwonder.fr</p>

    <button type="submit" class="btn">Sign in with Azure</button><br/>
    </form>
    </div>

    <script>
        if (window.location.hash) {
            (function() {
                var inputs = document.getElementsByName('rd');
                for (var i = 0; i < inputs.length; i++) {
                    inputs[i].value += window.location.hash;
                }
            })();
        }
    </script>
    <footer>

    Secured with <a href="https://github.com/pusher/oauth2_proxy#oauth2_proxy">OAuth2 Proxy</a> version v3.1.0

    </footer>
</body>
</html>

If I go manually on elk.tvwonder.fr and I click on sign in with Azure, my browser is already connected on azure, I am direct redirected and authenticated.

Returning to grafana, everything works. I just do not want to have to go to elk.tvwonder.fr to click.

Do you have an idea of the configuration to apply?

Regards,

JoelSpeed commented 5 years ago

The easiest way I can think of to achieve this would be to let the OAuth2_Proxy handle authentication for both ELK and Grafana. Have you considered using the OAuth2_Proxy with Grafana using the Auth Proxy configuration?

spprod35 commented 5 years ago

I do not understand where to configure the oauth2_proxy server. I rather feel that grafana includes a proxy of the same kind as oauth2_proxy.

In addition, once authenticated on grafana with my Azure token AD, on elk.tvwonder.fr, I just have to click on "sign with azure" to be connected, no identifier is requested.

How to make oauth2_proxy check that a connection is already active on Azure so as not to present the page with the button?

Regards,

JoelSpeed commented 5 years ago

The OAuth2_proxy cannot read the session from Azure. If you want to have the same authentication for these two endpoints you will need to configure the OAuth2_Proxy to authenticate against Azure and then have it sitting in front of both Grafana and your ELK stack. This was the authentication can be shared between them

spprod35 commented 5 years ago

I'm surprised that oauth_proxy can not automate the click on "Sign In With Azure". When I arrive on the page, I just have to click and I'm connected (Active session at Azure), can you tell me the technical brake that prevents this?

github-actions[bot] commented 4 years ago

This issue has been inactive for 60 days. If the issue is still relevant please comment to re-activate the issue. If no action is taken within 7 days, the issue will be marked closed.