authenticate/proxy: add user impersonation, refresh, dashboard (#123)

proxy: Add user dashboard. [GH-123]
proxy/authenticate: Add manual refresh of their session. [GH-73]
authorize: Add administrator (super user) account support. [GH-110]
internal/policy: Allow administrators to impersonate other users. [GH-110]
This commit is contained in:
Bobby DeSimone 2019-05-26 12:33:00 -07:00 committed by GitHub
parent dc2eb9668c
commit 66b4c2d3cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 1644 additions and 1006 deletions

View file

@ -183,96 +183,6 @@ func (a mockCipher) Unmarshal(s string, i interface{}) error {
}
return nil
}
func TestAuthenticate_ProxyCallback(t *testing.T) {
tests := []struct {
name string
uri string
state string
authCode string
sessionState *sessions.SessionState
sessionStore sessions.SessionStore
wantCode int
wantBody string
}{
{"good", "https://corp.pomerium.io/", "state", "code",
&sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
&sessions.MockSessionStore{},
302,
"<a href=\"https://corp.pomerium.io/?code=ok&amp;state=state\">Found</a>."},
{"no state",
"https://corp.pomerium.io/",
"",
"code",
&sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
&sessions.MockSessionStore{},
403,
"no state parameter supplied"},
{"no redirect_url",
"",
"state",
"code",
&sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
&sessions.MockSessionStore{},
403,
"no redirect_uri parameter"},
{"malformed redirect_url",
"https://pomerium.com%zzzzz",
"state",
"code",
&sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
&sessions.MockSessionStore{},
400,
"malformed redirect_uri"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &Authenticate{
sessionStore: tt.sessionStore,
cipher: mockCipher{},
}
u, _ := url.Parse("https://pomerium.io/redirect")
params, _ := url.ParseQuery(u.RawQuery)
params.Set("code", tt.authCode)
params.Set("state", tt.state)
params.Set("redirect_uri", tt.uri)
u.RawQuery = params.Encode()
r := httptest.NewRequest("GET", u.String(), nil)
w := httptest.NewRecorder()
a.ProxyCallback(w, r, tt.sessionState)
if status := w.Code; status != tt.wantCode {
t.Errorf("handler returned wrong status code: got %v want %v", status, tt.wantCode)
}
if body := w.Body.String(); !strings.Contains(body, tt.wantBody) {
t.Errorf("handler returned wrong body Body: got \n%s \n%s", body, tt.wantBody)
}
})
}
}
func Test_getAuthCodeRedirectURL(t *testing.T) {
tests := []struct {
@ -350,59 +260,6 @@ func TestAuthenticate_SignOut(t *testing.T) {
},
http.StatusBadRequest,
"could not revoke"},
{"good get",
http.MethodGet,
"https://corp.pomerium.io/",
"sig",
"ts",
identity.MockProvider{},
&sessions.MockSessionStore{
Session: &sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
Email: "blah@blah.com",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
},
http.StatusOK,
"This will also sign you out of other internal apps."},
{"cannot load session",
http.MethodGet,
"https://corp.pomerium.io/",
"sig",
"ts",
identity.MockProvider{},
&sessions.MockSessionStore{
LoadError: errors.New("uh oh"),
Session: &sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
Email: "blah@blah.com",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
},
http.StatusBadRequest,
"No session found to log out"},
{"bad redirect url get",
http.MethodGet,
"https://pomerium.com%zzzzz",
"sig",
"ts",
identity.MockProvider{},
&sessions.MockSessionStore{
Session: &sessions.SessionState{
AccessToken: "AccessToken",
RefreshToken: "RefreshToken",
Email: "blah@blah.com",
RefreshDeadline: time.Now().Add(10 * time.Second),
},
},
http.StatusBadRequest,
"Error"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {