From 6e039e1782fc3132e03d13ef1c6ada3f9c8b2e17 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Sun, 2 Sep 2018 18:15:48 +0200 Subject: [PATCH] Trying trings out with SATOSA --- sam/oidc.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sam/start.go | 14 +++++++-- 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 sam/oidc.go diff --git a/sam/oidc.go b/sam/oidc.go new file mode 100644 index 000000000..57c223347 --- /dev/null +++ b/sam/oidc.go @@ -0,0 +1,85 @@ +package sam + +import ( + "context" + "github.com/coreos/go-oidc" + "github.com/davecgh/go-spew/spew" + "golang.org/x/oauth2" + "net/http" +) + +type ( + openIdConnect struct { + provider *oidc.Provider + verifier *oidc.IDTokenVerifier + config oauth2.Config + } +) + +func OpenIdConnect(ctx context.Context, issuer string, cfg oauth2.Config) (c *openIdConnect, err error) { + c = &openIdConnect{} + + c.provider, err = oidc.NewProvider(ctx, issuer) + if err != nil { + return nil, err + } + + // Configure an OpenID Connect aware OAuth2 client. + c.config = oauth2.Config{ + ClientID: cfg.ClientID, + ClientSecret: cfg.ClientSecret, + RedirectURL: cfg.RedirectURL, + + // Discovery returns the OAuth2 endpoints. + Endpoint: c.provider.Endpoint(), + + // "openid" is a required scope for OpenID Connect flows. + Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, + } + + c.verifier = c.provider.Verifier(&oidc.Config{ClientID: cfg.ClientID}) + + return +} + +func (c *openIdConnect) HandleRedirect(w http.ResponseWriter, r *http.Request) { + state := "@todo" + http.Redirect(w, r, c.config.AuthCodeURL(state), http.StatusFound) +} + +func (c *openIdConnect) HandleOAuth2Callback(w http.ResponseWriter, r *http.Request) { + var ctx = r.Context() + + // @todo check state + + // Verify state and errors. + + oauth2Token, err := c.config.Exchange(ctx, r.URL.Query().Get("code")) + if err != nil { + // handle error + } + + // Extract the ID Token from OAuth2 token. + rawIDToken, ok := oauth2Token.Extra("id_token").(string) + if !ok { + // handle missing token + } + + // Parse and verify ID Token payload. + idToken, err := c.verifier.Verify(ctx, rawIDToken) + if err != nil { + // handle error + } + + // Extract custom claims + var claims struct { + Email string `json:"email"` + Verified bool `json:"email_verified"` + } + + if err := idToken.Claims(&claims); err != nil { + // handle error + } + + spew.Dump() +} diff --git a/sam/start.go b/sam/start.go index 2c43b01c1..7313bc94d 100644 --- a/sam/start.go +++ b/sam/start.go @@ -8,16 +8,17 @@ import ( "github.com/SentimensRG/ctx" "github.com/SentimensRG/ctx/sigctx" - authService "github.com/crusttech/crust/auth/service" - samService "github.com/crusttech/crust/sam/service" "github.com/go-chi/chi" "github.com/go-chi/cors" "github.com/pkg/errors" "github.com/titpetric/factory" "github.com/titpetric/factory/resputil" + "golang.org/x/oauth2" + authService "github.com/crusttech/crust/auth/service" "github.com/crusttech/crust/internal/auth" "github.com/crusttech/crust/sam/rest" + samService "github.com/crusttech/crust/sam/service" "github.com/crusttech/crust/sam/websocket" ) @@ -74,6 +75,15 @@ func Start() error { r := chi.NewRouter() r.Use(handleCORS) + if oidc, err := OpenIdConnect(ctx, "https://accounts.google.com", oauth2.Config{}); err != nil { + return errors.Wrap(err, "Could not initialize OIDC") + } else { + r.Route("/oidc/satosa", func(r chi.Router) { + r.Get("/", oidc.HandleRedirect) + r.Get("/callback", oidc.HandleOAuth2Callback) + }) + } + // Only protect application routes with JWT r.Group(func(r chi.Router) { r.Use(jwtAuth.Verifier(), jwtAuth.Authenticator())