Skip to content

Commit 3addcaf

Browse files
committed
Allow hiding password entry, changing OpenID Connect text and OpenID Connect icon
1 parent 09ee844 commit 3addcaf

File tree

9 files changed

+145
-58
lines changed

9 files changed

+145
-58
lines changed

cli/deployment/config.go

+15
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ func newConfig() *codersdk.DeploymentConfig {
157157
Flag: "postgres-url",
158158
Secret: true,
159159
},
160+
PasswordAuthHidden: &codersdk.DeploymentConfigField[bool]{
161+
Name: "Flag to hide password auth",
162+
Usage: "When this flag is set to true, the user/password form in the UI will be hidden",
163+
Flag: "password-auth-hidden",
164+
},
160165
OAuth2: &codersdk.OAuth2Config{
161166
Github: &codersdk.OAuth2GithubConfig{
162167
ClientID: &codersdk.DeploymentConfigField[string]{
@@ -231,6 +236,16 @@ func newConfig() *codersdk.DeploymentConfig {
231236
Flag: "oidc-scopes",
232237
Default: []string{oidc.ScopeOpenID, "profile", "email"},
233238
},
239+
SignInText: &codersdk.DeploymentConfigField[string]{
240+
Name: "OpenID Connect sign in text",
241+
Usage: "The text to show on the OpenID Connect sign in button",
242+
Flag: "oidc-sign-in-text",
243+
},
244+
IconURL: &codersdk.DeploymentConfigField[string]{
245+
Name: "OpenID connect icon URL",
246+
Usage: "URL pointing to the icon to use on the OepnID Connect login button",
247+
Flag: "oidc-icon-url",
248+
},
234249
},
235250

236251
Telemetry: &codersdk.TelemetryConfig{

cli/server.go

+4
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
370370
options.TLSCertificates = tlsConfig.Certificates
371371
}
372372

373+
options.PasswordAuthHidden = cfg.PasswordAuthHidden.Value
374+
373375
if cfg.OAuth2.Github.ClientSecret.Value != "" {
374376
options.GithubOAuth2Config, err = configureGithubOAuth2(accessURLParsed,
375377
cfg.OAuth2.Github.ClientID.Value,
@@ -419,6 +421,8 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
419421
}),
420422
EmailDomain: cfg.OIDC.EmailDomain.Value,
421423
AllowSignups: cfg.OIDC.AllowSignups.Value,
424+
SignInText: cfg.OIDC.SignInText.Value,
425+
IconURL: cfg.OIDC.IconURL.Value,
422426
}
423427
}
424428

cli/testdata/coder_server_--help.golden

+10
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,22 @@ Flags:
9898
--oidc-email-domain string Email domain that clients logging in with
9999
OIDC must match.
100100
Consumes $CODER_OIDC_EMAIL_DOMAIN
101+
--oidc-icon-url string URL pointing to the icon to use on the
102+
OepnID Connect login button
103+
Consumes $CODER_OIDC_ICON_URL
101104
--oidc-issuer-url string Issuer URL to use for Login with OIDC.
102105
Consumes $CODER_OIDC_ISSUER_URL
103106
--oidc-scopes strings Scopes to grant when authenticating with
104107
OIDC.
105108
Consumes $CODER_OIDC_SCOPES (default
106109
[openid,profile,email])
110+
--oidc-sign-in-text string The text to show on the OpenID Connect
111+
sign in button
112+
Consumes $CODER_OIDC_SIGN_IN_TEXT
113+
--password-auth-hidden When this flag is set to true, the
114+
user/password form in the UI will be
115+
hidden
116+
Consumes $CODER_PASSWORD_AUTH_HIDDEN
107117
--postgres-url string URL of a PostgreSQL database. If empty,
108118
PostgreSQL binaries will be downloaded
109119
from Maven

coderd/coderd.go

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ type Options struct {
7676
Authorizer rbac.Authorizer
7777
AzureCertificates x509.VerifyOptions
7878
GoogleTokenValidator *idtoken.Validator
79+
PasswordAuthHidden bool
7980
GithubOAuth2Config *GithubOAuth2Config
8081
OIDCConfig *OIDCConfig
8182
PrometheusRegistry *prometheus.Registry

coderd/userauth.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,27 @@ type GithubOAuth2Config struct {
4444
}
4545

4646
func (api *API) userAuthMethods(rw http.ResponseWriter, r *http.Request) {
47+
var signInText string
48+
var iconURL string
49+
50+
if api.OIDCConfig != nil {
51+
signInText = api.OIDCConfig.SignInText
52+
}
53+
if api.OIDCConfig != nil {
54+
iconURL = api.OIDCConfig.IconURL
55+
}
56+
4757
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.AuthMethods{
48-
Password: true,
49-
Github: api.GithubOAuth2Config != nil,
50-
OIDC: api.OIDCConfig != nil,
58+
Password: codersdk.PasswordMethod{
59+
AuthMethod: codersdk.AuthMethod{Enabled: true},
60+
Hidden: api.PasswordAuthHidden,
61+
},
62+
Github: codersdk.AuthMethod{Enabled: api.GithubOAuth2Config != nil},
63+
OIDC: codersdk.OIDCMethod{
64+
AuthMethod: codersdk.AuthMethod{Enabled: api.OIDCConfig != nil},
65+
SignInText: signInText,
66+
IconURL: iconURL,
67+
},
5168
})
5269
}
5370

@@ -195,6 +212,8 @@ type OIDCConfig struct {
195212
// EmailDomain is the domain to enforce when a user authenticates.
196213
EmailDomain string
197214
AllowSignups bool
215+
SignInText string
216+
IconURL string
198217
}
199218

200219
func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {

codersdk/deploymentconfig.go

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type DeploymentConfig struct {
2424
CacheDirectory *DeploymentConfigField[string] `json:"cache_directory" typescript:",notnull"`
2525
InMemoryDatabase *DeploymentConfigField[bool] `json:"in_memory_database" typescript:",notnull"`
2626
PostgresURL *DeploymentConfigField[string] `json:"pg_connection_url" typescript:",notnull"`
27+
PasswordAuthHidden *DeploymentConfigField[bool] `json:"password_auth_hidden" typescript:",notnull"`
2728
OAuth2 *OAuth2Config `json:"oauth2" typescript:",notnull"`
2829
OIDC *OIDCConfig `json:"oidc" typescript:",notnull"`
2930
Telemetry *TelemetryConfig `json:"telemetry" typescript:",notnull"`
@@ -92,6 +93,8 @@ type OIDCConfig struct {
9293
EmailDomain *DeploymentConfigField[string] `json:"email_domain" typescript:",notnull"`
9394
IssuerURL *DeploymentConfigField[string] `json:"issuer_url" typescript:",notnull"`
9495
Scopes *DeploymentConfigField[[]string] `json:"scopes" typescript:",notnull"`
96+
SignInText *DeploymentConfigField[string] `json:"sign_in_text" typescript:",notnull"`
97+
IconURL *DeploymentConfigField[string] `json:"icon_url" typescript:",notnull"`
9598
}
9699

97100
type TelemetryConfig struct {

codersdk/users.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,26 @@ type CreateOrganizationRequest struct {
105105
Name string `json:"name" validate:"required,username"`
106106
}
107107

108-
// AuthMethods contains whether authentication types are enabled or not.
108+
// AuthMethods contains authentication method information like whether they are enabled or not or hidden or not, etc.
109109
type AuthMethods struct {
110-
Password bool `json:"password"`
111-
Github bool `json:"github"`
112-
OIDC bool `json:"oidc"`
110+
Password PasswordMethod `json:"password"`
111+
Github AuthMethod `json:"github"`
112+
OIDC OIDCMethod `json:"oidc"`
113+
}
114+
115+
type AuthMethod struct {
116+
Enabled bool `json:"enabled"`
117+
}
118+
119+
type PasswordMethod struct {
120+
AuthMethod
121+
Hidden bool `json:"hidden"`
122+
}
123+
124+
type OIDCMethod struct {
125+
AuthMethod
126+
SignInText string `json:"signInText"`
127+
IconURL string `json:"iconUrl"`
113128
}
114129

115130
// HasFirstUser returns whether the first user has been created.

site/src/api/typesGenerated.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,16 @@ export interface AuditLogsRequest extends Pagination {
9090
readonly q?: string
9191
}
9292

93+
// From codersdk/users.go
94+
export interface AuthMethod {
95+
readonly enabled: boolean
96+
}
97+
9398
// From codersdk/users.go
9499
export interface AuthMethods {
95-
readonly password: boolean
96-
readonly github: boolean
97-
readonly oidc: boolean
100+
readonly password: PasswordMethod
101+
readonly github: AuthMethod
102+
readonly oidc: OIDCMethod
98103
}
99104

100105
// From codersdk/authorization.go
@@ -289,6 +294,7 @@ export interface DeploymentConfig {
289294
readonly cache_directory: DeploymentConfigField<string>
290295
readonly in_memory_database: DeploymentConfigField<boolean>
291296
readonly pg_connection_url: DeploymentConfigField<string>
297+
readonly password_auth_hidden: DeploymentConfigField<boolean>
292298
readonly oauth2: OAuth2Config
293299
readonly oidc: OIDCConfig
294300
readonly telemetry: TelemetryConfig
@@ -446,6 +452,14 @@ export interface OIDCConfig {
446452
readonly email_domain: DeploymentConfigField<string>
447453
readonly issuer_url: DeploymentConfigField<string>
448454
readonly scopes: DeploymentConfigField<string[]>
455+
readonly sign_in_text: DeploymentConfigField<string>
456+
readonly icon_url: DeploymentConfigField<string>
457+
}
458+
459+
// From codersdk/users.go
460+
export interface OIDCMethod extends AuthMethod {
461+
readonly signInText: string
462+
readonly iconUrl: string
449463
}
450464

451465
// From codersdk/organizations.go
@@ -505,6 +519,11 @@ export interface ParameterSchema {
505519
readonly validation_contains?: string[]
506520
}
507521

522+
// From codersdk/users.go
523+
export interface PasswordMethod extends AuthMethod {
524+
readonly hidden: boolean
525+
}
526+
508527
// From codersdk/groups.go
509528
export interface PatchGroupRequest {
510529
readonly add_users: string[]

site/src/components/SignInForm/SignInForm.tsx

+49-48
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
130130

131131
return (
132132
<>
133-
<Welcome />
134-
<form onSubmit={form.handleSubmit}>
133+
<Welcome/>
134+
{!authMethods?.password.hidden && (<form onSubmit={form.handleSubmit}>
135135
<Stack>
136136
{Object.keys(loginErrors).map(
137137
(errorKey: string) =>
@@ -174,55 +174,56 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
174174
</LoadingButton>
175175
</div>
176176
</Stack>
177-
</form>
178-
{(authMethods?.github || authMethods?.oidc) && (
179-
<>
180-
<div className={styles.divider}>
181-
<div className={styles.dividerLine} />
182-
<div className={styles.dividerLabel}>Or</div>
183-
<div className={styles.dividerLine} />
184-
</div>
185-
186-
<Box display="grid" gridGap="16px">
187-
{authMethods.github && (
188-
<Link
189-
underline="none"
190-
href={`/api/v2/users/oauth2/github/callback?redirect=${encodeURIComponent(
191-
redirectTo,
192-
)}`}
177+
</form>)}
178+
{(!authMethods?.password.hidden && (authMethods?.github.enabled || authMethods?.oidc.enabled)) && (
179+
<div className={styles.divider}>
180+
<div className={styles.dividerLine}/>
181+
<div className={styles.dividerLabel}>Or</div>
182+
<div className={styles.dividerLine}/>
183+
</div>
184+
)}
185+
{(authMethods?.github.enabled || authMethods?.oidc.enabled) && (
186+
<Box display="grid" gridGap="16px">
187+
{authMethods.github.enabled && (
188+
<Link
189+
underline="none"
190+
href={`/api/v2/users/oauth2/github/callback?redirect=${encodeURIComponent(
191+
redirectTo,
192+
)}`}
193+
>
194+
<Button
195+
startIcon={<GitHubIcon className={styles.buttonIcon} />}
196+
disabled={isLoading}
197+
fullWidth
198+
type="submit"
199+
variant="contained"
193200
>
194-
<Button
195-
startIcon={<GitHubIcon className={styles.buttonIcon} />}
196-
disabled={isLoading}
197-
fullWidth
198-
type="submit"
199-
variant="contained"
200-
>
201-
{Language.githubSignIn}
202-
</Button>
203-
</Link>
204-
)}
201+
{Language.githubSignIn}
202+
</Button>
203+
</Link>
204+
)}
205205

206-
{authMethods.oidc && (
207-
<Link
208-
underline="none"
209-
href={`/api/v2/users/oidc/callback?redirect=${encodeURIComponent(
210-
redirectTo,
211-
)}`}
206+
{authMethods.oidc.enabled && (
207+
<Link
208+
underline="none"
209+
href={`/api/v2/users/oidc/callback?redirect=${encodeURIComponent(
210+
redirectTo,
211+
)}`}
212+
>
213+
<Button
214+
startIcon={authMethods.oidc.iconUrl
215+
? <img alt="Open ID Connect icon" src={authMethods.oidc.iconUrl} width="24" height="24"/>
216+
: <KeyIcon className={styles.buttonIcon} />}
217+
disabled={isLoading}
218+
fullWidth
219+
type="submit"
220+
variant="contained"
212221
>
213-
<Button
214-
startIcon={<KeyIcon className={styles.buttonIcon} />}
215-
disabled={isLoading}
216-
fullWidth
217-
type="submit"
218-
variant="contained"
219-
>
220-
{Language.oidcSignIn}
221-
</Button>
222-
</Link>
223-
)}
224-
</Box>
225-
</>
222+
{authMethods.oidc.signInText || Language.oidcSignIn}
223+
</Button>
224+
</Link>
225+
)}
226+
</Box>
226227
)}
227228
</>
228229
)

0 commit comments

Comments
 (0)