/
oidc.go
110 lines (95 loc) · 3.17 KB
/
oidc.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
package custom
import (
"context"
"errors"
"net/http"
"net/url"
"strings"
"flamingo.me/dingo"
"flamingo.me/flamingo/v3/core/auth"
"flamingo.me/flamingo/v3/framework/config"
"flamingo.me/flamingo/v3/framework/web"
)
// OidcModule configures an "overridden" openid connect module
type OidcModule struct{}
// Configure dependency injection
func (*OidcModule) Configure(injector *dingo.Injector) {
injector.BindMap(new(auth.RequestIdentifierFactory), "customOidcBroker").ToProvider(func(identifierConfig *struct {
Oidc auth.RequestIdentifierFactory `inject:"map:oidc"`
}) auth.RequestIdentifierFactory {
return func(cfg config.Map) (auth.RequestIdentifier, error) {
identifier, err := identifierConfig.Oidc(cfg["oidc"].(map[string]interface{}))
if err != nil {
return nil, err
}
if err := injector.RequestInjection(identifier); err != nil {
return nil, err
}
return &oidcBroker{oidcBroker: identifier}, nil
}
})
}
// CueConfig for oidcBroker
func (*OidcModule) CueConfig() string {
return `
customOidcBroker :: {
typ: "customOidcBroker"
broker: "customOidcBroker"
oidc: {
core.auth.oidc
broker: "customOidcBroker"
clientID: "customOidcBroker"
clientSecret: "customOidcBroker"
"endpoint": "http://127.0.0.1:3351/dex"
}
}
`
}
type oidcBroker struct {
oidcBroker auth.RequestIdentifier
responder *web.Responder
}
// Inject dependencies
func (b *oidcBroker) Inject(responder *web.Responder) {
b.responder = responder
}
// Broker getter
func (*oidcBroker) Broker() string {
return "customOidcBroker"
}
// Identify request
func (b *oidcBroker) Identify(ctx context.Context, request *web.Request) (auth.Identity, error) {
if val, ok := request.Session().Load("customOidcBroker.loggedIn"); !ok || !val.(bool) {
return nil, errors.New("no customOidcBroker loggedIn flag")
}
return b.oidcBroker.Identify(ctx, request)
}
// Authenticate request
func (b *oidcBroker) Authenticate(ctx context.Context, request *web.Request) web.Result {
return b.oidcBroker.(auth.WebAuthenticater).Authenticate(ctx, request)
}
// Callback handler for request
func (b *oidcBroker) Callback(ctx context.Context, request *web.Request, returnTo func(*web.Request) *url.URL) web.Result {
if identity, err := b.oidcBroker.Identify(ctx, request); err != nil && identity == nil {
// okURL marks a final callback, e.g. everything went fine
okURL := new(url.URL)
if result, ok := b.oidcBroker.(auth.WebCallbacker).Callback(ctx, request, func(request *web.Request) *url.URL {
return okURL
}).(*web.URLRedirectResponse); ok && result.URL != okURL {
// upstream callback failed
return result
}
}
if q, err := request.Query1("oidcbroker"); err == nil && q != "" {
request.Session().Store("customOidcBroker.loggedIn", true)
}
if val, ok := request.Session().Load("customOidcBroker.loggedIn"); !ok || !val.(bool) {
return b.responder.HTTP(http.StatusOK, strings.NewReader(`<a href="?oidcbroker=1">Confirm Login</a>`))
}
// we have finished
return b.responder.URLRedirect(returnTo(request))
}
// Logout handler for request
func (b *oidcBroker) Logout(ctx context.Context, request *web.Request) *url.URL {
return b.oidcBroker.(auth.WebLogoutWithRedirect).Logout(ctx, request)
}