142 lines
3.3 KiB
Go
142 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"github.com/coreos/go-oidc/v3/oidc"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/oauth2"
|
|
"net/http"
|
|
)
|
|
|
|
type OidcClams struct {
|
|
Email string `json:"email"`
|
|
Profile string `json:"profile"`
|
|
}
|
|
|
|
|
|
type OAuth2 struct {
|
|
_ctx context.Context
|
|
_oauth2Config *oauth2.Config
|
|
_oidcVerifier *oidc.IDTokenVerifier
|
|
_oidcProvider *oidc.Provider
|
|
_nonces map[string]string
|
|
}
|
|
|
|
func (o *OAuth2) GetClaims(w http.ResponseWriter, token *oidc.IDToken) (*OidcClams, error) {
|
|
var claims = new(OidcClams)
|
|
err := token.Claims(&claims)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return claims, nil
|
|
}
|
|
|
|
|
|
func (o *OAuth2) checkOAuth(w http.ResponseWriter, r *http.Request, allowRedirect bool) (*oidc.IDToken, bool) {
|
|
|
|
cookie, err := r.Cookie("id_token")
|
|
if err == nil {
|
|
log.Info("got id_token cookie")
|
|
token, err := o._oidcVerifier.Verify(o._ctx, cookie.Value)
|
|
if err != nil {
|
|
http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
|
|
return nil, false
|
|
}
|
|
|
|
dst, _ := base64.URLEncoding.DecodeString(cookie.Value)
|
|
fmt.Printf(string(dst))
|
|
return token, true
|
|
|
|
} else {
|
|
//no Bearer available
|
|
if code := r.URL.Query().Get("code") ; code != "" {
|
|
state := r.URL.Query().Get("state")
|
|
//check if nonce is known by server
|
|
if _, ok := o._nonces[state]; ok == false {
|
|
return nil, false
|
|
}
|
|
delete(o._nonces, state)
|
|
|
|
oauth2Token, err := o._oauth2Config.Exchange(o._ctx, code)
|
|
if err != nil {
|
|
http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
|
|
return nil, false
|
|
}
|
|
|
|
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
|
if !ok {
|
|
http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
|
|
return nil, false
|
|
}
|
|
log.Info(rawIDToken)
|
|
token, err2 := o._oidcVerifier.Verify(o._ctx, rawIDToken)
|
|
if err2 != nil {
|
|
http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
|
|
return nil, false
|
|
}
|
|
|
|
idCookie := http.Cookie{
|
|
Name: "id_token",
|
|
Value: rawIDToken,
|
|
Domain: "",
|
|
Expires: token.Expiry,
|
|
Secure: false,
|
|
HttpOnly: true,
|
|
Path: "/",
|
|
SameSite: http.SameSiteLaxMode,
|
|
}
|
|
|
|
http.SetCookie(w, &idCookie)
|
|
|
|
return token, true
|
|
|
|
|
|
|
|
} else {
|
|
//no auth code and no bearer -> redirect
|
|
if allowRedirect {
|
|
nonce := generateToken()
|
|
o._nonces[nonce] = nonce
|
|
http.Redirect(w, r, o._oauth2Config.AuthCodeURL(nonce), http.StatusFound)
|
|
}
|
|
|
|
return nil, false
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func CreateOAuth2(config *Config) (*OAuth2, error) {
|
|
ctx := context.Background()
|
|
provider, err := oidc.NewProvider(ctx, config.IssuerUrl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
oidcConfig := &oidc.Config{
|
|
ClientID: config.OAuth2ClientID,
|
|
}
|
|
|
|
// Configure an OpenID Connect aware OAuth2 client.
|
|
verifier := provider.Verifier(oidcConfig)
|
|
|
|
oauthConfig := oauth2.Config{
|
|
ClientID: config.OAuth2ClientID,
|
|
ClientSecret: config.OAuth2ClientSecret,
|
|
Endpoint: provider.Endpoint(),
|
|
RedirectURL: config.OAuth2RedirectUrl,
|
|
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
|
}
|
|
|
|
return &OAuth2{
|
|
_ctx: ctx,
|
|
_oauth2Config: &oauthConfig,
|
|
_oidcVerifier: verifier,
|
|
_oidcProvider: provider,
|
|
_nonces: make(map[string]string),
|
|
}, nil
|
|
} |