forked from mintel/dex-k8s-authenticator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dex-auth.go
122 lines (105 loc) · 3.46 KB
/
dex-auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/coreos/go-oidc"
"github.com/spf13/viper"
"golang.org/x/oauth2"
"log"
"net/http"
"path"
"time"
)
const exampleAppState = "Vgn2lp5QnymFtLntKX5dM8k773PwcM87T4hQtiESC1q8wkUBgw5D3kH0r5qJ"
func (cluster *Cluster) oauth2Config(scopes []string) *oauth2.Config {
return &oauth2.Config{
ClientID: cluster.Client_ID,
ClientSecret: cluster.Client_Secret,
Endpoint: cluster.Provider.Endpoint(),
Scopes: scopes,
RedirectURL: cluster.Redirect_URI,
}
}
func (config *Config) handleIndex(w http.ResponseWriter, r *http.Request) {
if len(config.Clusters) == 1 && r.URL.String() == config.Web_Path_Prefix {
http.Redirect(w, r, path.Join(config.Web_Path_Prefix, "login", config.Clusters[0].Name), http.StatusSeeOther)
} else {
renderIndex(w, config)
}
}
func (cluster *Cluster) handleLogin(w http.ResponseWriter, r *http.Request) {
var scopes []string
scopes = append(scopes, "openid", "profile", "email", "offline_access", "groups")
log.Printf("Handling login-uri for: %s", cluster.Name)
authCodeURL := cluster.oauth2Config(scopes).AuthCodeURL(exampleAppState, oauth2.AccessTypeOffline)
log.Printf("Redirecting post-loginto: %s", authCodeURL)
http.Redirect(w, r, authCodeURL, http.StatusSeeOther)
}
func (cluster *Cluster) handleCallback(w http.ResponseWriter, r *http.Request) {
var (
err error
token *oauth2.Token
)
log.Printf("Handling callback for: %s", cluster.Name)
ctx := oidc.ClientContext(r.Context(), cluster.Client)
oauth2Config := cluster.oauth2Config(nil)
switch r.Method {
case "GET":
// Authorization redirect callback from OAuth2 auth flow.
if errMsg := r.FormValue("error"); errMsg != "" {
http.Error(w, errMsg+": "+r.FormValue("error_description"), http.StatusBadRequest)
return
}
code := r.FormValue("code")
if code == "" {
http.Error(w, fmt.Sprintf("No code in request: %q", r.Form), http.StatusBadRequest)
return
}
if state := r.FormValue("state"); state != exampleAppState {
http.Error(w, fmt.Sprintf("Expected state %q got %q", exampleAppState, state), http.StatusBadRequest)
return
}
token, err = oauth2Config.Exchange(ctx, code)
case "POST":
// Form request from frontend to refresh a token.
refresh := r.FormValue("refresh_token")
if refresh == "" {
http.Error(w, fmt.Sprintf("No refresh_token in request: %q", r.Form), http.StatusBadRequest)
return
}
t := &oauth2.Token{
RefreshToken: refresh,
Expiry: time.Now().Add(-time.Hour),
}
token, err = oauth2Config.TokenSource(ctx, t).Token()
default:
http.Error(w, fmt.Sprintf("Method not implemented: %s", r.Method), http.StatusBadRequest)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("Failed to get token: %v", err), http.StatusInternalServerError)
return
}
rawIDToken, ok := token.Extra("id_token").(string)
if !ok {
http.Error(w, "No id_token in token response", http.StatusInternalServerError)
return
}
idToken, err := cluster.Verifier.Verify(r.Context(), rawIDToken)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to verify ID token: %v", err), http.StatusInternalServerError)
return
}
var claims json.RawMessage
idToken.Claims(&claims)
buff := new(bytes.Buffer)
json.Indent(buff, []byte(claims), "", " ")
cluster.renderToken(w, rawIDToken, token.RefreshToken,
cluster.Config.IDP_Ca_URI,
cluster.Config.IDP_Ca_Pem,
cluster.Config.Logo_Uri,
cluster.Config.Web_Path_Prefix,
viper.GetString("kubectl_version"),
buff.Bytes())
}