mirror of https://github.com/h44z/wg-portal.git
				
				
				
			use the `hide_login_form` parameter in the `auth` settings to configure this feature
This commit is contained in:
		
							parent
							
								
									f994700caf
								
							
						
					
					
						commit
						dd28a8dddf
					
				|  | @ -76,6 +76,7 @@ auth: | |||
|   webauthn: | ||||
|     enabled: true | ||||
|   min_password_length: 16 | ||||
|   hide_login_form: false | ||||
| 
 | ||||
| web: | ||||
|   listening_address: :8888 | ||||
|  | @ -354,6 +355,12 @@ Some core authentication options are shared across all providers, while others a | |||
|   The default admin password strength is also enforced by this setting. | ||||
| - **Important:** The password should be strong and secure. It is recommended to use a password with at least 16 characters, including uppercase and lowercase letters, numbers, and special characters. | ||||
| 
 | ||||
| ### `hide_login_form` | ||||
| - **Default:** `false` | ||||
| - **Description:** If `true`, the login form is hidden and only the OIDC, OAuth, LDAP, or WebAuthn providers are shown. This is useful if you want to enforce a specific authentication method. | ||||
|   If no social login providers are configured, the login form is always shown, regardless of this setting. | ||||
| - **Important:** You can still access the login form by adding the `?all` query parameter to the login URL (e.g. https://wg.portal/#/login?all).  | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### OIDC | ||||
|  |  | |||
|  | @ -16,7 +16,10 @@ const password = ref("") | |||
| const usernameInvalid = computed(() => username.value === "") | ||||
| const passwordInvalid = computed(() => password.value === "") | ||||
| const disableLoginBtn = computed(() => username.value === "" || password.value === "" || loggingIn.value) | ||||
| 
 | ||||
| const showLoginForm = computed(() => { | ||||
|   console.log(router.currentRoute.value.query) | ||||
|   return settings.Setting('LoginFormVisible') || router.currentRoute.value.query.hasOwnProperty('all'); | ||||
| }); | ||||
| 
 | ||||
| onMounted(async () => { | ||||
|   await settings.LoadSettings() | ||||
|  | @ -98,7 +101,7 @@ const externalLogin = function (provider) { | |||
|         </div></div> | ||||
|         <div class="card-body"> | ||||
|           <form method="post"> | ||||
|             <fieldset> | ||||
|             <fieldset v-if="showLoginForm"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label" for="inputUsername">{{ $t('login.username.label') }}</label> | ||||
|                 <div class="input-group mb-3"> | ||||
|  | @ -118,19 +121,40 @@ const externalLogin = function (provider) { | |||
|               </div> | ||||
| 
 | ||||
|               <div class="row mt-5 mb-2"> | ||||
|                 <div class="col-lg-4"> | ||||
|                   <button :disabled="disableLoginBtn" class="btn btn-primary" type="submit" @click.prevent="login"> | ||||
|                 <div class="col-sm-4 col-xs-12"> | ||||
|                   <button :disabled="disableLoginBtn" class="btn btn-primary mb-2" type="submit" @click.prevent="login"> | ||||
|                     {{ $t('login.button') }} <div v-if="loggingIn" class="d-inline"><i class="ms-2 fa-solid fa-circle-notch fa-spin"></i></div> | ||||
|                   </button> | ||||
|                 </div> | ||||
|                 <div class="col-lg-8 mb-2 text-end"> | ||||
|                 <div class="col-sm-8 col-xs-12 text-sm-end"> | ||||
|                   <button v-if="settings.Setting('WebAuthnEnabled')" class="btn btn-primary" type="submit" @click.prevent="loginWebAuthn"> | ||||
|                     {{ $t('login.button-webauthn') }} <div v-if="loggingIn" class="d-inline"><i class="ms-2 fa-solid fa-circle-notch fa-spin"></i></div> | ||||
|                   </button> | ||||
|                 </div> | ||||
|               </div> | ||||
| 
 | ||||
|               <div class="row mt-5 d-flex"> | ||||
|               <div class="row mt-4 d-flex"> | ||||
|                 <div class="col-lg-12 d-flex mb-2"> | ||||
|                   <!-- OpenIdConnect / OAUTH providers --> | ||||
|                   <button v-for="(provider, idx) in auth.LoginProviders" :key="provider.Identifier" :class="{'ms-1':idx > 0}" | ||||
|                           :disabled="loggingIn" :title="provider.Name" class="btn btn-outline-primary flex-fill" | ||||
|                           v-html="provider.Name" @click.prevent="externalLogin(provider)"></button> | ||||
|                 </div> | ||||
|               </div> | ||||
| 
 | ||||
|               <div class="mt-3"> | ||||
|               </div> | ||||
|             </fieldset> | ||||
|             <fieldset v-else> | ||||
|               <div class="row mt-1 mb-2" v-if="settings.Setting('WebAuthnEnabled')"> | ||||
|                 <div class="col-lg-12 d-flex mb-2"> | ||||
|                   <button class="btn btn-outline-primary flex-fill" type="submit" @click.prevent="loginWebAuthn"> | ||||
|                     {{ $t('login.button-webauthn') }} <div v-if="loggingIn" class="d-inline"><i class="ms-2 fa-solid fa-circle-notch fa-spin"></i></div> | ||||
|                   </button> | ||||
|                 </div> | ||||
|               </div> | ||||
| 
 | ||||
|               <div class="row mt-1 d-flex"> | ||||
|                 <div class="col-lg-12 d-flex mb-2"> | ||||
|                   <!-- OpenIdConnect / OAUTH providers --> | ||||
|                   <button v-for="(provider, idx) in auth.LoginProviders" :key="provider.Identifier" :class="{'ms-1':idx > 0}" | ||||
|  | @ -144,7 +168,6 @@ const externalLogin = function (provider) { | |||
|             </fieldset> | ||||
|           </form> | ||||
| 
 | ||||
| 
 | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -2231,6 +2231,9 @@ | |||
|                 "ApiAdminOnly": { | ||||
|                     "type": "boolean" | ||||
|                 }, | ||||
|                 "LoginFormVisible": { | ||||
|                     "type": "boolean" | ||||
|                 }, | ||||
|                 "MailLinkOnly": { | ||||
|                     "type": "boolean" | ||||
|                 }, | ||||
|  |  | |||
|  | @ -381,6 +381,8 @@ definitions: | |||
|     properties: | ||||
|       ApiAdminOnly: | ||||
|         type: boolean | ||||
|       LoginFormVisible: | ||||
|         type: boolean | ||||
|       MailLinkOnly: | ||||
|         type: boolean | ||||
|       MinPasswordLength: | ||||
|  |  | |||
|  | @ -96,10 +96,13 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc { | |||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		sessionUser := domain.GetUserInfo(r.Context()) | ||||
| 
 | ||||
| 		hasSocialLogin := len(e.cfg.Auth.OAuth) > 0 || len(e.cfg.Auth.OpenIDConnect) > 0 || e.cfg.Auth.WebAuthn.Enabled | ||||
| 
 | ||||
| 		// For anonymous users, we return the settings object with minimal information
 | ||||
| 		if sessionUser.Id == domain.CtxUnknownUserId || sessionUser.Id == "" { | ||||
| 			respond.JSON(w, http.StatusOK, model.Settings{ | ||||
| 				WebAuthnEnabled: e.cfg.Auth.WebAuthn.Enabled, | ||||
| 				WebAuthnEnabled:  e.cfg.Auth.WebAuthn.Enabled, | ||||
| 				LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			respond.JSON(w, http.StatusOK, model.Settings{ | ||||
|  | @ -109,6 +112,7 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc { | |||
| 				ApiAdminOnly:              e.cfg.Advanced.ApiAdminOnly, | ||||
| 				WebAuthnEnabled:           e.cfg.Auth.WebAuthn.Enabled, | ||||
| 				MinPasswordLength:         e.cfg.Auth.MinPasswordLength, | ||||
| 				LoginFormVisible:          !e.cfg.Auth.HideLoginForm || !hasSocialLogin, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -12,4 +12,5 @@ type Settings struct { | |||
| 	ApiAdminOnly              bool `json:"ApiAdminOnly"` | ||||
| 	WebAuthnEnabled           bool `json:"WebAuthnEnabled"` | ||||
| 	MinPasswordLength         int  `json:"MinPasswordLength"` | ||||
| 	LoginFormVisible          bool `json:"LoginFormVisible"` | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,9 @@ type Auth struct { | |||
| 	// MinPasswordLength is the minimum password length for user accounts. This also applies to the admin user.
 | ||||
| 	// It is encouraged to set this value to at least 16 characters.
 | ||||
| 	MinPasswordLength int `yaml:"min_password_length"` | ||||
| 	// HideLoginForm specifies whether the login form should be hidden. If no social login providers are configured,
 | ||||
| 	// the login form will be shown regardless of this setting.
 | ||||
| 	HideLoginForm bool `yaml:"hide_login_form"` | ||||
| } | ||||
| 
 | ||||
| // BaseFields contains the basic fields that are used to map user information from the authentication providers.
 | ||||
|  |  | |||
|  | @ -95,6 +95,9 @@ func (c *Config) LogStartupValues() { | |||
| 		"oidcProviders", len(c.Auth.OpenIDConnect), | ||||
| 		"oauthProviders", len(c.Auth.OAuth), | ||||
| 		"ldapProviders", len(c.Auth.Ldap), | ||||
| 		"webauthnEnabled", c.Auth.WebAuthn.Enabled, | ||||
| 		"minPasswordLength", c.Auth.MinPasswordLength, | ||||
| 		"hideLoginForm", c.Auth.HideLoginForm, | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
|  | @ -169,6 +172,7 @@ func defaultConfig() *Config { | |||
| 
 | ||||
| 	cfg.Auth.WebAuthn.Enabled = true | ||||
| 	cfg.Auth.MinPasswordLength = 16 | ||||
| 	cfg.Auth.HideLoginForm = false | ||||
| 
 | ||||
| 	return cfg | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue