Commit e0a361b6 authored by ale's avatar ale

Save the UserInfo after a successful login

Fix a pretty fundamental error where group memberships could not be
verified. Also adds tests to ensure this does not happen again.
parent 9ded75b5
......@@ -259,8 +259,11 @@ func (h *Server) handleGrantTicket(w http.ResponseWriter, req *http.Request) {
var groups []string
if groupsStr != "" {
reqGroups := strings.Split(groupsStr, ",")
if len(reqGroups) > 0 && auth.UserInfo != nil {
groups = intersectGroups(reqGroups, auth.UserInfo.Groups)
if len(reqGroups) > 0 {
if auth.UserInfo != nil {
groups = intersectGroups(reqGroups, auth.UserInfo.Groups)
log.Printf("intersectGroups(%+v, %+v) -> %+v", reqGroups, auth.UserInfo.Groups, groups)
}
// We only make this check here as a convenience to
// the user (we may be able to show a nicer UI): the
// actual group ACL must be applied on the destination
......
......@@ -25,7 +25,10 @@ type fakeAuthClient struct{}
func (c *fakeAuthClient) Authenticate(_ context.Context, req *auth.Request) (*auth.Response, error) {
p := string(req.Password)
info := &auth.UserInfo{Shard: "shard1"}
info := &auth.UserInfo{
Shard: "shard1",
Groups: []string{"users"},
}
switch {
case req.Username == "testuser" && p == "password":
return &auth.Response{Status: auth.StatusOK, UserInfo: info}, nil
......@@ -55,10 +58,15 @@ func createTestHTTPServer(t testing.TB, config *Config) *httptest.Server {
return httptest.NewTLSServer(srv.Handler())
}
func startTestHTTPServer(t testing.TB) (string, *httptest.Server) {
func startTestHTTPServerWithConfig(t testing.TB) (string, *httptest.Server, *Config) {
tmpdir, _ := ioutil.TempDir("", "")
config := testConfig(t, tmpdir, "")
return tmpdir, createTestHTTPServer(t, config)
return tmpdir, createTestHTTPServer(t, config), config
}
func startTestHTTPServer(t testing.TB) (string, *httptest.Server) {
tmpdir, srv, _ := startTestHTTPServerWithConfig(t)
return tmpdir, srv
}
func startTestHTTPServerWithKeyStore(t testing.TB) (string, *httptest.Server) {
......@@ -159,6 +167,33 @@ func checkRedirectToTargetService(t testing.TB, resp *http.Response) {
}
}
func checkTargetSSOTicket(config *Config) func(testing.TB, *http.Response) {
return func(t testing.TB, resp *http.Response) {
u, err := url.Parse(resp.Header.Get("Location"))
if err != nil {
t.Fatalf("could not parse Location URL: %v", err)
}
tstr := u.Query().Get("t")
nonce := u.Query().Get("n")
// Validate the ticket in order to read it.
v, err := newValidatorFromConfig(config)
if err != nil {
t.Fatalf("newValidatorFromConfig: %v", err)
}
ticket, err := v.Validate(tstr, nonce, "service.example.com/", nil)
if err != nil {
t.Fatalf("sso.Validate(%s): %v", tstr, err)
}
if n := len(ticket.Groups); n != 1 {
t.Errorf("ticket has %d groups, expected 1", n)
}
if ticket.Groups[0] != "users" {
t.Errorf("group is '%s', expected 'users'", ticket.Groups[0])
}
}
}
var usernameFieldRx = regexp.MustCompile(`<input[^>]*name="username"`)
func checkLoginPasswordPage(t testing.TB, resp *http.Response) {
......@@ -205,7 +240,7 @@ func checkLogoutPage(t testing.TB, resp *http.Response) {
}
func TestHTTP_Login(t *testing.T) {
tmpdir, httpSrv := startTestHTTPServer(t)
tmpdir, httpSrv, config := startTestHTTPServerWithConfig(t)
defer os.RemoveAll(tmpdir)
defer httpSrv.Close()
......@@ -217,6 +252,7 @@ func TestHTTP_Login(t *testing.T) {
v.Set("s", "service.example.com/")
v.Set("d", "https://service.example.com/admin/")
v.Set("n", "averysecretnonce")
v.Set("g", "users")
doGet(t, c, httpSrv.URL+"/?"+v.Encode(), checkStatusOk, checkLoginPasswordPage)
// Attempt to login by submitting the form. We expect the
......@@ -224,7 +260,7 @@ func TestHTTP_Login(t *testing.T) {
v = make(url.Values)
v.Set("username", "testuser")
v.Set("password", "password")
doPostForm(t, c, httpSrv.URL+"/login", v, checkRedirectToTargetService)
doPostForm(t, c, httpSrv.URL+"/login", v, checkRedirectToTargetService, checkTargetSSOTicket(config))
}
func TestHTTP_LoginOnSecondAttempt(t *testing.T) {
......
......@@ -253,6 +253,7 @@ func (l *Login) handleLogin(w http.ResponseWriter, req *http.Request, sess *logi
switch resp.Status {
case auth.StatusOK:
sess.UserInfo = resp.UserInfo
l.loginOk(w, req, sess, password)
return
case auth.StatusInsufficientCredentials:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment