◐ Shell
clean mode source ↗

fix(coderd): use a random value for a simulated hash for built-in use… · coder/coder@0951f90

@@ -167,6 +167,59 @@ func TestPostLogin(t *testing.T) {

167167

require.Equal(t, database.AuditActionLogin, auditor.AuditLogs()[numLogs-1].Action)

168168

})

169169170+

// "hunter2" was the input of the previous hardcoded simulated hash, which

171+

// an empty stored hash wrongly matched; this is a regression test.

172+

t.Run("NonexistentUser401", func(t *testing.T) {

173+

t.Parallel()

174+

client := coderdtest.New(t, nil)

175+

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)

176+

defer cancel()

177+178+

_, err := client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{

179+

Email: "does-not-exist@coder.com",

180+

Password: "hunter2",

181+

})

182+

var apiErr *codersdk.Error

183+

require.ErrorAs(t, err, &apiErr)

184+

require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())

185+

require.Equal(t, "Incorrect email or password.", apiErr.Message)

186+

})

187+188+

// Attempting built-in login as an SSO user returns a 401 to avoid

189+

// divulging login type.

190+

t.Run("SSOReturns401", func(t *testing.T) {

191+

t.Parallel()

192+

client, db := coderdtest.NewWithDatabase(t, nil)

193+

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)

194+

defer cancel()

195+196+

// An SSO user has no password hash stored. Create one directly in the

197+

// database since the API requires OIDC to be configured. dbgen.User

198+

// substitutes a random hash for an empty one, so clear it explicitly.

199+

ssoUser := dbgen.User(t, db, database.User{

200+

Email: "sso-user@coder.com",

201+

LoginType: database.LoginTypeOIDC,

202+

})

203+

//nolint:gocritic // Test setup requires a system context to clear the hash.

204+

err := db.UpdateUserHashedPassword(dbauthz.AsSystemRestricted(ctx), database.UpdateUserHashedPasswordParams{

205+

ID: ssoUser.ID,

206+

HashedPassword: []byte{},

207+

})

208+

require.NoError(t, err)

209+210+

anonClient := codersdk.New(client.URL)

211+

_, err = anonClient.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{

212+

Email: ssoUser.Email,

213+

Password: "hunter2",

214+

})

215+

var apiErr *codersdk.Error

216+

require.ErrorAs(t, err, &apiErr)

217+

require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())

218+

require.Equal(t, "Incorrect email or password.", apiErr.Message)

219+

// The login type must not be leaked.

220+

require.NotContains(t, apiErr.Message, string(codersdk.LoginTypeOIDC))

221+

})

222+170223

t.Run("Suspended", func(t *testing.T) {

171224

t.Parallel()

172225

auditor := audit.NewMock()