Skip to content

Commit 2be844f

Browse files
committed
Add back missing code from merge
1 parent 7aedfbc commit 2be844f

File tree

1 file changed

+106
-2
lines changed

1 file changed

+106
-2
lines changed

coderd/userauth.go

+106-2
Original file line numberDiff line numberDiff line change
@@ -1015,8 +1015,11 @@ type oauthLoginParams struct {
10151015
AvatarURL string
10161016
// Is UsingGroups is true, then the user will be assigned
10171017
// to the Groups provided.
1018-
UsingGroups bool
1019-
Groups []string
1018+
UsingGroups bool
1019+
Groups []string
1020+
OauthConversionEnabled bool
1021+
1022+
InitAuditRequest func(params *audit.RequestParams) (*audit.Request[database.OauthMergeState], func())
10201023
}
10211024

10221025
type httpError struct {
@@ -1048,6 +1051,15 @@ func (api *API) oauthLogin(r *http.Request, params oauthLoginParams) (*http.Cook
10481051
user = params.User
10491052
link = params.Link
10501053

1054+
// If you do a convert to OIDC and your email does not match, we need to
1055+
// catch this and not make a new account.
1056+
if isMergeStateString(params.State.StateString) {
1057+
err := api.convertUserToOauth(ctx, r, tx, params)
1058+
if err != nil {
1059+
return err
1060+
}
1061+
}
1062+
10511063
if user.ID == uuid.Nil && !params.AllowSignups {
10521064
return httpError{
10531065
code: http.StatusForbidden,
@@ -1228,6 +1240,91 @@ func (api *API) oauthLogin(r *http.Request, params oauthLoginParams) (*http.Cook
12281240
return cookie, *key, nil
12291241
}
12301242

1243+
// convertUserToOauth will convert a user from password base loginType to
1244+
// an oauth login type. If it fails, it will return a httpError
1245+
func (api *API) convertUserToOauth(ctx context.Context, r *http.Request, db database.Store, params oauthLoginParams) error {
1246+
user := params.User
1247+
1248+
// Trying to convert to OIDC, but the email does not match.
1249+
// So do not make a new user, just block the request.
1250+
if user.ID == uuid.Nil {
1251+
return httpError{
1252+
code: http.StatusBadRequest,
1253+
msg: fmt.Sprintf("The oidc account with the email %q does not match the email of the account you are trying to convert. Contact your administrator to resolve this issue.", params.Email),
1254+
}
1255+
}
1256+
1257+
// nolint:gocritic // Required to auth the oidc convert
1258+
mergeState, err := db.GetUserOauthMergeState(dbauthz.AsSystemRestricted(ctx), database.GetUserOauthMergeStateParams{
1259+
UserID: user.ID,
1260+
StateString: params.State.StateString,
1261+
})
1262+
if xerrors.Is(err, sql.ErrNoRows) {
1263+
return httpError{
1264+
code: http.StatusBadRequest,
1265+
msg: "No convert login request found with given state. Restart the convert process and try again.",
1266+
}
1267+
}
1268+
if err != nil {
1269+
return httpError{
1270+
code: http.StatusInternalServerError,
1271+
msg: err.Error(),
1272+
}
1273+
}
1274+
1275+
// At this point, this request could be an attempt to convert from
1276+
// password auth to oauth auth. Always log these attempts.
1277+
var (
1278+
auditor = *api.Auditor.Load()
1279+
oauthConvertAudit, commitOauthConvertAudit = params.InitAuditRequest(&audit.RequestParams{
1280+
Audit: auditor,
1281+
Log: api.Logger,
1282+
Request: r,
1283+
Action: database.AuditActionLogin,
1284+
})
1285+
)
1286+
oauthConvertAudit.Old = mergeState
1287+
defer commitOauthConvertAudit()
1288+
1289+
// If we do not allow converting to oauth, return an error.
1290+
if !params.OauthConversionEnabled {
1291+
return httpError{
1292+
code: http.StatusForbidden,
1293+
msg: fmt.Sprintf("Incorrect login type, attempting to use %q but user is of login type %q",
1294+
params.LoginType,
1295+
user.LoginType,
1296+
),
1297+
}
1298+
}
1299+
1300+
// Make sure the merge state generated matches this OIDC login request.
1301+
// It needs to have the correct login type information for this
1302+
// user.
1303+
if user.ID != mergeState.UserID || user.LoginType != mergeState.FromLoginType || params.LoginType != mergeState.ToLoginType {
1304+
return httpError{
1305+
code: http.StatusForbidden,
1306+
msg: fmt.Sprintf("Request to convert login type from %s to %s failed", user.LoginType, params.LoginType),
1307+
}
1308+
}
1309+
1310+
// Convert the user and default to the normal login flow.
1311+
// If the login succeeds, this transaction will commit and the user
1312+
// will be converted.
1313+
// nolint:gocritic // system query to update user login type
1314+
user, err = db.UpdateUserLoginType(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLoginTypeParams{
1315+
LoginType: params.LoginType,
1316+
UserID: user.ID,
1317+
})
1318+
if err != nil {
1319+
return httpError{
1320+
code: http.StatusInternalServerError,
1321+
msg: "Failed to convert user to new login type",
1322+
}
1323+
}
1324+
return nil
1325+
1326+
}
1327+
12311328
// githubLinkedID returns the unique ID for a GitHub user.
12321329
func githubLinkedID(u *github.User) string {
12331330
return strconv.FormatInt(u.GetID(), 10)
@@ -1294,3 +1391,10 @@ func findLinkedUser(ctx context.Context, db database.Store, linkedID string, ema
12941391

12951392
return user, link, nil
12961393
}
1394+
1395+
func isMergeStateString(state string) bool {
1396+
if strings.HasPrefix(state, mergeStateStringPrefix) {
1397+
return true
1398+
}
1399+
return false
1400+
}

0 commit comments

Comments
 (0)