Skip to content

feat: add ability for users to convert their password login type to oauth/github login #8105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 64 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
ba42c17
WIP: working on ability to merge oidc with password auth account
Emyrk Jun 13, 2023
a746952
Fix displaying error on login page
Emyrk Jun 14, 2023
bd93ef9
add migration to add a table for tracking oidc state
Emyrk Jun 14, 2023
b2c9496
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 14, 2023
0078629
WIP: add full functionality, but block the upgrade
Emyrk Jun 14, 2023
fc19a8a
Functionality is working, need to polish and write tests. Currently d…
Emyrk Jun 15, 2023
31a7e78
Begin refactoring to rename and make consistent
Emyrk Jun 15, 2023
069d689
Add dbfakes, delete mergestates, and implement the convert
Emyrk Jun 20, 2023
6d6a46e
Add flag to enable this feature
Emyrk Jun 20, 2023
a4961b9
Add unit test
Emyrk Jun 20, 2023
ab94b85
Add FE unit test for audit logS
Emyrk Jun 20, 2023
8390fb8
Conditionally show account setting
Emyrk Jun 20, 2023
9027c2a
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 20, 2023
b082e49
Make gen
Emyrk Jun 20, 2023
ecf3789
Linting
Emyrk Jun 20, 2023
95ff11a
Remove test lint
Emyrk Jun 20, 2023
6e69f90
Bump migration number
Emyrk Jun 20, 2023
8c2fc33
Swagger annotations
Emyrk Jun 20, 2023
cf19d8c
Swagger annotations
Emyrk Jun 21, 2023
6947021
golden file update
Emyrk Jun 21, 2023
27bf518
Add format tags
Emyrk Jun 21, 2023
3c8ee52
Fix audit log mistake
Emyrk Jun 21, 2023
b4bfc29
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 21, 2023
bc506c1
Make gen
Emyrk Jun 21, 2023
4ea859c
Fix audit log on login failure
Emyrk Jun 21, 2023
847dc64
fixup! Fix audit log on login failure
Emyrk Jun 21, 2023
59e8924
Bump migration
Emyrk Jun 21, 2023
368fa2b
Make gen and add test fixtures
Emyrk Jun 21, 2023
9cfb69c
Add from_login_type
Emyrk Jun 21, 2023
ddabcf7
Extract oauth convert into a helper function
Emyrk Jun 22, 2023
57b3605
chore: add boolean to auth methods to know if the deployment supports…
Emyrk Jun 22, 2023
7aedfbc
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 26, 2023
2be844f
Add back missing code from merge
Emyrk Jun 26, 2023
fde4908
Linting
Emyrk Jun 26, 2023
810e996
Fix merge error
Emyrk Jun 26, 2023
f3bce86
Move error message to route
Emyrk Jun 26, 2023
a2510a2
Rename state_string to state
Emyrk Jun 26, 2023
48db46c
Fix js unit tests
Emyrk Jun 28, 2023
c2aea70
Fix migration fixture
Emyrk Jun 28, 2023
6294fb5
feat(site): add change OIDC UI (#8182)
BrunoQuaresma Jun 28, 2023
68977f5
create a new route for user login type
Emyrk Jun 28, 2023
c8905b6
New route for login type
Emyrk Jun 28, 2023
6ae96c9
Switch state from being stored in the db to a jwt in a cookie
Emyrk Jun 28, 2023
28d2aa9
Fix audit logging changes
Emyrk Jun 28, 2023
92c50cf
Fix audit logs
Emyrk Jun 28, 2023
48f6d30
Linting
Emyrk Jun 28, 2023
af411be
Include mock of new api route
Emyrk Jun 28, 2023
1f2aef9
Do not double commit audit logs
Emyrk Jun 28, 2023
1260546
fmt
Emyrk Jun 28, 2023
31f48a2
Fix js mock rest endpoint
Emyrk Jun 28, 2023
6d7a63f
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 28, 2023
fa76cde
Bump migration
Emyrk Jun 29, 2023
e670557
Make gen
Emyrk Jun 29, 2023
949e687
PR feedback
Emyrk Jun 29, 2023
28e1156
Merge remote-tracking branch 'origin/main' into stevenmasley/merge_oi…
Emyrk Jun 29, 2023
4cee518
Linting
Emyrk Jun 29, 2023
159f12c
Rename Oauth
Emyrk Jun 29, 2023
c9b8fe6
PR Feedback
Emyrk Jun 29, 2023
2ffe5db
Swagger fix
Emyrk Jun 29, 2023
b6d7de5
Make experiment for better tracking
Emyrk Jun 29, 2023
e8d7ec9
experiment make gen
Emyrk Jun 29, 2023
d67e0c7
Update golden files
Emyrk Jun 29, 2023
b124ff4
mock convert endpoint
Emyrk Jun 29, 2023
f393e44
Mock the redirect
Emyrk Jun 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
PR feedback
  • Loading branch information
Emyrk committed Jun 29, 2023
commit 949e6872e3e9104389331a1f341377f11bdd51a3
5 changes: 4 additions & 1 deletion coderd/database/dbfake/dbfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -4887,7 +4887,10 @@ func (q *fakeQuerier) UpdateUserLoginType(_ context.Context, arg database.Update

for i, u := range q.users {
if u.ID == arg.UserID {
u.LoginType = arg.LoginType
u.LoginType = arg.NewLoginType
if arg.NewLoginType != database.LoginTypePassword {
u.HashedPassword = []byte{}
}
q.users[i] = u
return u, nil
}
Expand Down
2 changes: 1 addition & 1 deletion coderd/database/dbgen/dbgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func User(t testing.TB, db database.Store, orig database.User) database.User {
ID: takeFirst(orig.ID, uuid.New()),
Email: takeFirst(orig.Email, namesgenerator.GetRandomName(1)),
Username: takeFirst(orig.Username, namesgenerator.GetRandomName(1)),
HashedPassword: takeFirstSlice(orig.HashedPassword, []byte{}),
HashedPassword: takeFirstSlice(orig.HashedPassword, []byte(must(cryptorand.String(32)))),
CreatedAt: takeFirst(orig.CreatedAt, database.Now()),
UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()),
RBACRoles: takeFirstSlice(orig.RBACRoles, []string{}),
Expand Down
45 changes: 45 additions & 0 deletions coderd/database/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,51 @@ func TestUserLastSeenFilter(t *testing.T) {
})
}

func TestUserChangeLoginType(t *testing.T) {
t.Parallel()
if testing.Short() {
t.SkipNow()
}

sqlDB := testSQLDB(t)
err := migrations.Up(sqlDB)
require.NoError(t, err)
db := database.New(sqlDB)
ctx := context.Background()

alice := dbgen.User(t, db, database.User{
LoginType: database.LoginTypePassword,
})
bob := dbgen.User(t, db, database.User{
LoginType: database.LoginTypePassword,
})
bobExpPass := bob.HashedPassword
require.NotEmpty(t, alice.HashedPassword, "hashed password should not start empty")
require.NotEmpty(t, bob.HashedPassword, "hashed password should not start empty")

alice, err = db.UpdateUserLoginType(ctx, database.UpdateUserLoginTypeParams{
NewLoginType: database.LoginTypeOIDC,
UserID: alice.ID,
})

require.NoError(t, err)
require.Empty(t, alice.HashedPassword, "hashed password should be empty")

// First check other users are not affected
bob, err = db.GetUserByID(ctx, bob.ID)
require.NoError(t, err)
require.Equal(t, bobExpPass, bob.HashedPassword, "hashed password should not change")

// Then check password -> password is a noop
bob, err = db.UpdateUserLoginType(ctx, database.UpdateUserLoginTypeParams{
NewLoginType: database.LoginTypePassword,
UserID: bob.ID,
})
bob, err = db.GetUserByID(ctx, bob.ID)
require.NoError(t, err)
require.Equal(t, bobExpPass, bob.HashedPassword, "hashed password should not change")
}

func requireUsersMatch(t testing.TB, expected []database.User, found []database.GetUsersRow, msg string) {
t.Helper()
require.ElementsMatch(t, expected, database.ConvertUserRows(found), msg)
Expand Down
15 changes: 11 additions & 4 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions coderd/database/queries/siteconfig.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ SELECT
COALESCE((SELECT value FROM site_configs WHERE key = 'default_proxy_icon_url'), '/emojis/1f3e1.png') :: text AS icon_url
;


-- name: InsertDeploymentID :exec
INSERT INTO site_configs (key, value) VALUES ('deployment_id', $1);

Expand Down Expand Up @@ -58,7 +57,6 @@ SELECT value FROM site_configs WHERE key = 'app_signing_key';
INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1)
ON CONFLICT (key) DO UPDATE set value = $1 WHERE site_configs.key = 'app_signing_key';


-- name: GetOauthSigningKey :one
SELECT value FROM site_configs WHERE key = 'oauth_signing_key';

Expand Down
9 changes: 8 additions & 1 deletion coderd/database/queries/users.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
UPDATE
users
SET
login_type = @login_type
login_type = @new_login_type,
hashed_password = CASE WHEN @new_login_type = 'password' :: login_type THEN
users.hashed_password
ELSE
-- If the login type is not password, then the password should be
-- cleared.
'':: bytea
END
WHERE
id = @user_id RETURNING *;

Expand Down
4 changes: 2 additions & 2 deletions coderd/database/types.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package database

import (
"database/sql/driver"
"encoding/json"
"time"

"golang.org/x/xerrors"
"database/sql/driver"

"github.com/google/uuid"
"golang.org/x/xerrors"

"github.com/coder/coder/coderd/rbac"
)
Expand Down
8 changes: 4 additions & 4 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,8 +637,8 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
aReq.New = key
aReq.UserID = key.UserID

for i := range cookies {
http.SetCookie(rw, cookies[i])
for _, cookie := range cookies {
http.SetCookie(rw, cookie)
}

redirect := state.Redirect
Expand Down Expand Up @@ -1392,8 +1392,8 @@ func (api *API) convertUserToOauth(ctx context.Context, r *http.Request, db data
// will be converted.
// nolint:gocritic // system query to update user login type
user, err = db.UpdateUserLoginType(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLoginTypeParams{
LoginType: params.LoginType,
UserID: user.ID,
NewLoginType: params.LoginType,
UserID: user.ID,
})
if err != nil {
return database.User{}, httpError{
Expand Down