forked from influxdata/influxdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdoc.go
141 lines (141 loc) · 11.5 KB
/
doc.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
// Package oauth2 provides http.Handlers necessary for implementing Oauth2
// authentication with multiple Providers.
//
// This is how the pieces of this package fit together:
//
// ┌────────────────────────────────────────┐
// │github.com/influxdata/influxdb/chronograf/oauth2 │
// ├────────────────────────────────────────┴────────────────────────────────────┐
// │┌────────────────────┐ │
// ││ <<interface>> │ ┌─────────────────────────┐ │
// ││ Authenticator │ │ AuthMux │ │
// │├────────────────────┤ ├─────────────────────────┤ │
// ││Authorize() │ Auth │+SuccessURL : string │ │
// ││Validate() ◀────────│+FailureURL : string │──────────┐ │
// ||Expire() | |+Now : func() time.Time | | |
// │└──────────△─────────┘ └─────────────────────────┘ | |
// │ │ │ │ |
// │ │ │ │ │
// │ │ │ │ │
// │ │ Provider│ │ │
// │ │ ┌───┘ │ │
// │┌──────────┴────────────┐ │ ▽ │
// ││ Tokenizer │ │ ┌───────────────┐ │
// │├───────────────────────┤ ▼ │ <<interface>> │ │
// ││Create() │ ┌───────────────┐ │ OAuth2Mux │ │
// ││ValidPrincipal() │ │ <<interface>> │ ├───────────────┤ │
// │└───────────────────────┘ │ Provider │ │Login() │ │
// │ ├───────────────┤ │Logout() │ │
// │ │ID() │ │Callback() │ │
// │ │Scopes() │ └───────────────┘ │
// │ │Secret() │ │
// │ │Authenticator()│ │
// │ └───────────────┘ │
// │ △ │
// │ │ │
// │ ┌─────────────────────────┼─────────────────────────┐ │
// │ │ │ │ │
// │ │ │ │ │
// │ │ │ │ │
// │ ┌───────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐│
// │ │ Github │ │ Google │ │ Heroku ││
// │ ├───────────────────────┤ ├──────────────────────┤ ├──────────────────────┤│
// │ │+ClientID : string │ │+ClientID : string │ │+ClientID : string ││
// │ │+ClientSecret : string │ │+ClientSecret : string│ │+ClientSecret : string││
// │ │+Orgs : []string │ │+Domains : []string │ └──────────────────────┘│
// │ └───────────────────────┘ │+RedirectURL : string │ │
// │ └──────────────────────┘ │
// └─────────────────────────────────────────────────────────────────────────────┘
//
// The design focuses on an Authenticator, a Provider, and an OAuth2Mux. Their
// responsibilities, respectively, are to decode and encode secrets received
// from a Provider, to perform Provider specific operations in order to extract
// information about a user, and to produce the handlers which persist secrets.
// To add a new provider, You need only implement the Provider interface, and
// add its endpoints to the server Mux.
//
// The Oauth2 flow between a browser, backend, and a Provider that this package
// implements is pictured below for reference.
//
// ┌─────────┐ ┌───────────┐ ┌────────┐
// │ Browser │ │Chronograf │ │Provider│
// └─────────┘ └───────────┘ └────────┘
// │ │ │
// ├─────── GET /auth ─────────▶ │
// │ │ │
// │ │ │
// ◀ ─ ─ ─302 to Provider ─ ─ ┤ │
// │ │ │
// │ │ │
// ├──────────────── GET /auth w/ callback ─────────────────────▶
// │ │ │
// │ │ │
// ◀─ ─ ─ ─ ─ ─ ─ 302 to Chronograf Callback ─ ─ ─ ─ ─ ─ ─ ─ ┤
// │ │ │
// │ Code and State from │ │
// │ Provider │ │
// ├───────────────────────────▶ Request token w/ code & │
// │ │ state │
// │ ├────────────────────────────────▶
// │ │ │
// │ │ Response with │
// │ │ Token │
// │ Set cookie, Redirect │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤
// │ to / │ │
// ◀───────────────────────────┤ │
// │ │ │
// │ │ │
// │ │ │
// │ │ │
//
// The browser ultimately receives a cookie from Chronograf, authorizing it.
// Its contents are encoded as a JWT whose "sub" claim is the user's email
// address for whatever provider they have authenticated with. Each request to
// Chronograf will validate the contents of this JWT against the `TOKEN_SECRET`
// and checked for expiration. The JWT's "sub" becomes the
// https://en.wikipedia.org/wiki/Principal_(computer_security) used for
// authorization to resources.
//
// The Mux is responsible for providing three http.Handlers for servicing the
// above interaction. These are mounted at specific endpoints by convention
// shared with the front end. Any future Provider routes should follow the same
// convention to ensure compatibility with the front end logic. These routes
// and their responsibilities are:
//
// /oauth/{provider}/login
//
// The `/oauth` endpoint redirects to the Provider for OAuth. Chronograf sets
// the OAuth `state` request parameter to a JWT with a random "sub". Using
// $TOKEN_SECRET `/oauth/github/callback` can validate the `state` parameter
// without needing `state` to be saved.
//
// /oauth/{provider}/callback
//
// The `/oauth/github/callback` receives the OAuth `authorization code` and `state`.
//
// First, it will validate the `state` JWT from the `/oauth` endpoint. `JWT` validation
// only requires access to the signature token. Therefore, there is no need for `state`
// to be saved. Additionally, multiple Chronograf servers will not need to share third
// party storage to synchronize `state`. If this validation fails, the request
// will be redirected to `/login`.
//
// Secondly, the endpoint will use the `authorization code` to retrieve a valid OAuth token
// with the `user:email` scope. If unable to get a token from Github, the request will
// be redirected to `/login`.
//
// Finally, the endpoint will attempt to get the primary email address of the
// user. Again, if not successful, the request will redirect to `/login`.
//
// The email address is used as the subject claim for a new JWT. This JWT becomes the
// value of the cookie sent back to the browser. The cookie is valid for thirty days.
//
// Next, the request is redirected to `/`.
//
// For all API calls to `/chronograf/v1`, the server checks for the existence and validity
// of the JWT within the cookie value.
// If the request did not have a valid JWT, the API returns `HTTP/1.1 401 Unauthorized`.
//
// /oauth/{provider}/logout
//
// Simply expires the session cookie and redirects to `/`.
package oauth2