-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
connector_uaa.go
158 lines (140 loc) · 4.03 KB
/
connector_uaa.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package connector
import (
"encoding/json"
"fmt"
"html/template"
"net/http"
"net/url"
"path"
chttp "github.com/coreos/go-oidc/http"
"github.com/coreos/go-oidc/oauth2"
"github.com/coreos/go-oidc/oidc"
)
const (
UAAConnectorType = "uaa"
)
type UAAConnectorConfig struct {
ID string `json:"id"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
ServerURL string `json:"serverURL"`
}
// standard error form returned by UAA
type uaaError struct {
ErrorDescription string `json:"error_description"`
ErrorType string `json:"error"`
}
type uaaOAuth2Connector struct {
clientID string
clientSecret string
client *oauth2.Client
uaaBaseURL *url.URL
}
func init() {
RegisterConnectorConfigType(UAAConnectorType, func() ConnectorConfig { return &UAAConnectorConfig{} })
}
func (cfg *UAAConnectorConfig) ConnectorID() string {
return cfg.ID
}
func (cfg *UAAConnectorConfig) ConnectorType() string {
return UAAConnectorType
}
func (cfg *UAAConnectorConfig) Connector(ns url.URL, lf oidc.LoginFunc, tpls *template.Template) (Connector, error) {
uaaBaseURL, err := url.ParseRequestURI(cfg.ServerURL)
if err != nil {
return nil, fmt.Errorf("Invalid configuration. UAA URL is invalid: %v", err)
}
if !uaaBaseURL.IsAbs() {
return nil, fmt.Errorf("Invalid configuration. UAA URL must be absolute")
}
ns.Path = path.Join(ns.Path, httpPathCallback)
oauth2Conn, err := newUAAConnector(cfg, uaaBaseURL, ns.String())
if err != nil {
return nil, err
}
return &OAuth2Connector{
id: cfg.ID,
loginFunc: lf,
cbURL: ns,
conn: oauth2Conn,
}, nil
}
func (err uaaError) Error() string {
return fmt.Sprintf("uaa (%s): %s", err.ErrorType, err.ErrorDescription)
}
func (c *uaaOAuth2Connector) Client() *oauth2.Client {
return c.client
}
func (c *uaaOAuth2Connector) Healthy() error {
return nil
}
func (c *uaaOAuth2Connector) Identity(cli chttp.Client) (oidc.Identity, error) {
uaaUserInfoURL := *c.uaaBaseURL
uaaUserInfoURL.Path = path.Join(uaaUserInfoURL.Path, "/userinfo")
req, err := http.NewRequest("GET", uaaUserInfoURL.String(), nil)
if err != nil {
return oidc.Identity{}, err
}
resp, err := cli.Do(req)
if err != nil {
return oidc.Identity{}, fmt.Errorf("get: %v", err)
}
defer resp.Body.Close()
switch {
case resp.StatusCode >= 400 && resp.StatusCode < 600:
// attempt to decode error from UAA
var authErr uaaError
if err := json.NewDecoder(resp.Body).Decode(&authErr); err != nil {
return oidc.Identity{}, oauth2.NewError(oauth2.ErrorAccessDenied)
}
return oidc.Identity{}, authErr
case resp.StatusCode == http.StatusOK:
default:
return oidc.Identity{}, fmt.Errorf("unexpected status from providor %s", resp.Status)
}
var user struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
UserName string `json:"user_name"`
}
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
return oidc.Identity{}, fmt.Errorf("getting user info: %v", err)
}
name := user.Name
if name == "" {
name = user.UserName
}
return oidc.Identity{
ID: user.UserID,
Name: name,
Email: user.Email,
}, nil
}
func (c *uaaOAuth2Connector) TrustedEmailProvider() bool {
return false
}
func newUAAConnector(cfg *UAAConnectorConfig, uaaBaseURL *url.URL, cbURL string) (oauth2Connector, error) {
uaaAuthURL := *uaaBaseURL
uaaTokenURL := *uaaBaseURL
uaaAuthURL.Path = path.Join(uaaAuthURL.Path, "/oauth/authorize")
uaaTokenURL.Path = path.Join(uaaTokenURL.Path, "/oauth/token")
config := oauth2.Config{
Credentials: oauth2.ClientCredentials{ID: cfg.ClientID, Secret: cfg.ClientSecret},
AuthURL: uaaAuthURL.String(),
TokenURL: uaaTokenURL.String(),
Scope: []string{"openid"},
AuthMethod: oauth2.AuthMethodClientSecretPost,
RedirectURL: cbURL,
}
cli, err := oauth2.NewClient(http.DefaultClient, config)
if err != nil {
return nil, err
}
return &uaaOAuth2Connector{
clientID: cfg.ClientID,
clientSecret: cfg.ClientSecret,
client: cli,
uaaBaseURL: uaaBaseURL,
}, nil
}