Commit b19adefd authored by Joe Bowers's avatar Joe Bowers

Merge pull request #138 from joeatwork/disable-users

server: disable users
parents 72fa4127 fbbb3cc2
-- +migrate Up
ALTER TABLE authd_user ADD COLUMN disabled boolean;
UPDATE authd_user SET "disabled" = FALSE;
This diff is collapsed.
...@@ -417,6 +417,7 @@ type userModel struct { ...@@ -417,6 +417,7 @@ type userModel struct {
Email string `db:"email"` Email string `db:"email"`
EmailVerified bool `db:"email_verified"` EmailVerified bool `db:"email_verified"`
DisplayName string `db:"display_name"` DisplayName string `db:"display_name"`
Disabled bool `db:"disabled"`
Admin bool `db:"admin"` Admin bool `db:"admin"`
CreatedAt int64 `db:"created_at"` CreatedAt int64 `db:"created_at"`
} }
...@@ -428,6 +429,7 @@ func (u *userModel) user() (user.User, error) { ...@@ -428,6 +429,7 @@ func (u *userModel) user() (user.User, error) {
Email: u.Email, Email: u.Email,
EmailVerified: u.EmailVerified, EmailVerified: u.EmailVerified,
Admin: u.Admin, Admin: u.Admin,
Disabled: u.Disabled,
} }
if u.CreatedAt != 0 { if u.CreatedAt != 0 {
...@@ -444,6 +446,7 @@ func newUserModel(u *user.User) (*userModel, error) { ...@@ -444,6 +446,7 @@ func newUserModel(u *user.User) (*userModel, error) {
Email: u.Email, Email: u.Email,
EmailVerified: u.EmailVerified, EmailVerified: u.EmailVerified,
Admin: u.Admin, Admin: u.Admin,
Disabled: u.Disabled,
} }
if !u.CreatedAt.IsZero() { if !u.CreatedAt.IsZero() {
......
...@@ -53,6 +53,14 @@ var ( ...@@ -53,6 +53,14 @@ var (
Email: "Email-3@example.com", Email: "Email-3@example.com",
}, },
}, },
{
User: user.User{
ID: "ID-4",
Email: "Email-4@example.com",
Admin: true,
Disabled: true,
},
},
} }
userPasswords = []user.PasswordInfo{ userPasswords = []user.PasswordInfo{
...@@ -60,6 +68,10 @@ var ( ...@@ -60,6 +68,10 @@ var (
UserID: "ID-1", UserID: "ID-1",
Password: []byte("hi."), Password: []byte("hi."),
}, },
{
UserID: "ID-4",
Password: []byte("hi."),
},
} }
userBadClientID = "ZZZ" userBadClientID = "ZZZ"
...@@ -75,6 +87,9 @@ var ( ...@@ -75,6 +87,9 @@ var (
userBadTokenExpired = makeUserToken(testIssuerURL, userBadTokenExpired = makeUserToken(testIssuerURL,
"ID-1", testClientID, time.Hour*-1, testPrivKey) "ID-1", testClientID, time.Hour*-1, testPrivKey)
userBadTokenDisabled = makeUserToken(testIssuerURL,
"ID-4", testClientID, time.Hour*1, testPrivKey)
) )
func makeUserAPITestFixtures() *userAPITestFixtures { func makeUserAPITestFixtures() *userAPITestFixtures {
...@@ -166,6 +181,11 @@ func TestGetUser(t *testing.T) { ...@@ -166,6 +181,11 @@ func TestGetUser(t *testing.T) {
}, { }, {
id: "ID-1", id: "ID-1",
token: userBadTokenDisabled,
errCode: http.StatusUnauthorized,
}, {
id: "ID-1",
token: "", token: "",
errCode: http.StatusUnauthorized, errCode: http.StatusUnauthorized,
}, { }, {
...@@ -229,20 +249,28 @@ func TestListUsers(t *testing.T) { ...@@ -229,20 +249,28 @@ func TestListUsers(t *testing.T) {
wantIDs [][]string wantIDs [][]string
}{ }{
{ {
pages: 3, pages: 4,
maxResults: 1, maxResults: 1,
token: userGoodToken, token: userGoodToken,
wantIDs: [][]string{{"ID-1"}, {"ID-2"}, {"ID-3"}}, wantIDs: [][]string{{"ID-1"}, {"ID-2"}, {"ID-3"}, {"ID-4"}},
}, },
{ {
pages: 1, pages: 1,
token: userGoodToken, token: userGoodToken,
maxResults: 3, maxResults: 4,
wantIDs: [][]string{{"ID-1", "ID-2", "ID-3"}}, wantIDs: [][]string{{"ID-1", "ID-2", "ID-3", "ID-4"}},
},
{
pages: 1,
token: userBadTokenDisabled,
maxResults: 1,
wantCode: http.StatusUnauthorized, // TODO don't merge until you're sure this is covering what you expect
}, },
{ {
pages: 3, pages: 3,
...@@ -417,6 +445,22 @@ func TestCreateUser(t *testing.T) { ...@@ -417,6 +445,22 @@ func TestCreateUser(t *testing.T) {
// try every variation like in TestGetUser // try every variation like in TestGetUser
token: userBadTokenExpired, token: userBadTokenExpired,
wantCode: http.StatusUnauthorized,
},
{
req: schema.UserCreateRequest{
User: &schema.User{
Email: "newuser@example.com",
DisplayName: "New User",
EmailVerified: true,
Admin: false,
CreatedAt: clock.Now().Format(time.RFC3339),
},
RedirectURL: testRedirectURL.String(),
},
token: userBadTokenDisabled,
wantCode: http.StatusUnauthorized, wantCode: http.StatusUnauthorized,
}, },
} }
......
...@@ -326,6 +326,10 @@ func (s *Server) Login(ident oidc.Identity, key string) (string, error) { ...@@ -326,6 +326,10 @@ func (s *Server) Login(ident oidc.Identity, key string) (string, error) {
return "", err return "", err
} }
if usr.Disabled {
return "", user.ErrorNotFound
}
ses, err = s.SessionManager.AttachUser(sessionID, usr.ID) ses, err = s.SessionManager.AttachUser(sessionID, usr.ID)
if err != nil { if err != nil {
return "", err return "", err
......
...@@ -261,6 +261,74 @@ func TestServerLoginUnrecognizedSessionKey(t *testing.T) { ...@@ -261,6 +261,74 @@ func TestServerLoginUnrecognizedSessionKey(t *testing.T) {
} }
} }
func TestServerLoginDisabledUser(t *testing.T) {
ci := oidc.ClientIdentity{
Credentials: oidc.ClientCredentials{
ID: "XXX",
Secret: "secrete",
},
Metadata: oidc.ClientMetadata{
RedirectURLs: []url.URL{
url.URL{
Scheme: "http",
Host: "client.example.com",
Path: "/callback",
},
},
},
}
ciRepo := client.NewClientIdentityRepo([]oidc.ClientIdentity{ci})
km := &StaticKeyManager{
signer: &StaticSigner{sig: []byte("beer"), err: nil},
}
sm := session.NewSessionManager(session.NewSessionRepo(), session.NewSessionKeyRepo())
sm.GenerateCode = staticGenerateCodeFunc("fakecode")
sessionID, err := sm.NewSession("test_connector_id", ci.Credentials.ID, "bogus", ci.Metadata.RedirectURLs[0], "", false, []string{"openid"})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
userRepo, err := makeNewUserRepo()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = userRepo.Create(nil, user.User{
ID: "disabled-1",
Email: "disabled@example.com",
Disabled: true,
})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = userRepo.AddRemoteIdentity(nil, "disabled-1", user.RemoteIdentity{
ConnectorID: "test_connector_id",
ID: "disabled-connector-id",
})
srv := &Server{
IssuerURL: url.URL{Scheme: "http", Host: "server.example.com"},
KeyManager: km,
SessionManager: sm,
ClientIdentityRepo: ciRepo,
UserRepo: userRepo,
}
ident := oidc.Identity{ID: "disabled-connector-id", Name: "elroy", Email: "elroy@example.com"}
key, err := sm.NewSessionKey(sessionID)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
_, err = srv.Login(ident, key)
if err == nil {
t.Errorf("disabled user was allowed to log in")
}
}
func TestServerCodeToken(t *testing.T) { func TestServerCodeToken(t *testing.T) {
ci := oidc.ClientIdentity{ ci := oidc.ClientIdentity{
Credentials: oidc.ClientCredentials{ Credentials: oidc.ClientCredentials{
......
...@@ -197,7 +197,7 @@ func (u *UsersAPI) ListUsers(creds Creds, maxResults int, nextPageToken string) ...@@ -197,7 +197,7 @@ func (u *UsersAPI) ListUsers(creds Creds, maxResults int, nextPageToken string)
} }
func (u *UsersAPI) Authorize(creds Creds) bool { func (u *UsersAPI) Authorize(creds Creds) bool {
return creds.User.Admin return creds.User.Admin && !creds.User.Disabled
} }
func userToSchemaUser(usr user.User) schema.User { func userToSchemaUser(usr user.User) schema.User {
......
...@@ -52,6 +52,15 @@ var ( ...@@ -52,6 +52,15 @@ var (
}, },
} }
disabledCreds = Creds{
User: user.User{
ID: "ID-1",
Admin: true,
Disabled: true,
},
ClientID: "XXX",
}
resetPasswordURL = url.URL{ resetPasswordURL = url.URL{
Host: "dex.example.com", Host: "dex.example.com",
Path: "resetPassword", Path: "resetPassword",
......
...@@ -41,6 +41,8 @@ type User struct { ...@@ -41,6 +41,8 @@ type User struct {
Admin bool Admin bool
Disabled bool
CreatedAt time.Time CreatedAt time.Time
} }
......
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