2023-09-24 15:36:35 -05:00
< template >
2023-11-22 12:38:11 -06:00
< div id = "authentication-settings" >
2023-09-24 15:36:35 -05:00
< app-settings-content :header-text = "$strings.HeaderAuthentication" >
< div class = "w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25" >
< div class = "flex items-center" >
< ui-checkbox v-model = "enableLocalAuth" checkbox-bg="bg" / >
2023-11-22 12:55:01 -06:00
< p class = "text-lg pl-4" > { { $strings . HeaderPasswordAuthentication } } < / p >
2023-09-24 15:36:35 -05:00
< / div >
< / div >
< div class = "w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25" >
< div class = "flex items-center" >
< ui-checkbox v-model = "enableOpenIDAuth" checkbox-bg="bg" / >
2023-11-22 12:55:01 -06:00
< p class = "text-lg pl-4" > { { $strings . HeaderOpenIDConnectAuthentication } } < / p >
2023-09-24 15:36:35 -05:00
< / div >
2023-11-08 14:45:29 -06:00
< transition name = "slide" >
< div v-if = "enableOpenIDAuth" class="flex flex-wrap pt-4" >
< div class = "w-full flex items-center mb-2" >
< div class = "flex-grow" >
< ui-text-input-with-label ref = "issuerUrl" v-model = "newAuthSettings.authOpenIDIssuerURL" :disabled="savingSettings" :label="'Issuer URL'" / >
< / div >
< div class = "w-36 mx-1 mt-[1.375rem]" >
< ui-btn class = "h-[2.375rem] text-sm inline-flex items-center justify-center w-full" type = "button" :padding-y = "0" :padding-x = "4" @click.stop ="autoPopulateOIDCClick" >
< span class = "material-icons text-base" > auto _fix _high < / span >
< span class = "whitespace-nowrap break-keep pl-1" > Auto - populate < / span > < / u i - b t n
>
2023-11-05 14:11:37 -06:00
< / div >
2023-11-08 14:45:29 -06:00
< / div >
2023-09-24 15:36:35 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "authorizationUrl" v-model = "newAuthSettings.authOpenIDAuthorizationURL" :disabled="savingSettings" :label="'Authorize URL'" class="mb-2" / >
2023-09-24 15:36:35 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "tokenUrl" v-model = "newAuthSettings.authOpenIDTokenURL" :disabled="savingSettings" :label="'Token URL'" class="mb-2" / >
2023-09-24 15:36:35 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "userInfoUrl" v-model = "newAuthSettings.authOpenIDUserInfoURL" :disabled="savingSettings" :label="'Userinfo URL'" class="mb-2" / >
2023-09-24 15:36:35 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "jwksUrl" v-model = "newAuthSettings.authOpenIDJwksURL" :disabled="savingSettings" :label="'JWKS URL'" class="mb-2" / >
2023-11-04 15:36:43 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "logoutUrl" v-model = "newAuthSettings.authOpenIDLogoutURL" :disabled="savingSettings" :label="'Logout URL'" class="mb-2" / >
2023-11-04 15:36:43 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "openidClientId" v-model = "newAuthSettings.authOpenIDClientID" :disabled="savingSettings" :label="'Client ID'" class="mb-2" / >
2023-09-24 15:36:35 -05:00
2023-11-08 14:45:29 -06:00
< ui-text-input-with-label ref = "openidClientSecret" v-model = "newAuthSettings.authOpenIDClientSecret" :disabled="savingSettings" :label="'Client Secret'" class="mb-2" / >
2023-11-02 13:55:01 -05:00
2023-11-22 12:55:01 -06:00
< ui-text-input-with-label ref = "buttonTextInput" v-model = "newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" / >
2023-11-02 13:55:01 -05:00
2023-11-08 14:45:29 -06:00
< div class = "flex items-center pt-1 mb-2" >
< div class = "w-44" >
2023-11-22 12:55:01 -06:00
< ui-dropdown v-model = "newAuthSettings.authOpenIDMatchExistingBy" small :items="matchingExistingOptions" :label="$strings.LabelMatchExistingUsersBy" :disabled="savingSettings" / >
2023-11-02 13:55:01 -05:00
< / div >
2023-11-22 12:55:01 -06:00
< p class = "pl-4 text-sm text-gray-300 mt-5" > { { $strings . LabelMatchExistingUsersByDescription } } < / p >
2023-09-24 15:36:35 -05:00
< / div >
2023-11-08 14:45:29 -06:00
< div class = "flex items-center py-4 px-1" >
< ui-toggle-switch labeledBy = "auto-redirect-toggle" v-model = "newAuthSettings.authOpenIDAutoLaunch" :disabled="savingSettings" / >
2023-11-22 12:55:01 -06:00
< p id = "auto-redirect-toggle" class = "pl-4 whitespace-nowrap" > { { $strings . LabelAutoLaunch } } < / p >
< p class = "pl-4 text-sm text-gray-300" v-html = "$strings.LabelAutoLaunchDescription" / >
2023-11-08 14:45:29 -06:00
< / div >
< div class = "flex items-center py-4 px-1" >
< ui-toggle-switch labeledBy = "auto-register-toggle" v-model = "newAuthSettings.authOpenIDAutoRegister" :disabled="savingSettings" / >
2023-11-22 12:55:01 -06:00
< p id = "auto-register-toggle" class = "pl-4 whitespace-nowrap" > { { $strings . LabelAutoRegister } } < / p >
< p class = "pl-4 text-sm text-gray-300" > { { $strings . LabelAutoRegisterDescription } } < / p >
2023-11-08 14:45:29 -06:00
< / div >
< / div >
< / transition >
2023-09-24 15:36:35 -05:00
< / div >
< div class = "w-full flex items-center justify-end p-4" >
< ui-btn color = "success" :padding-x = "8" small class = "text-base" :loading = "savingSettings" @click ="saveSettings" > {{ $ strings.ButtonSave }} < / ui -btn >
< / div >
< / app-settings-content >
< / div >
< / template >
< script >
export default {
async asyncData ( { store , redirect , app } ) {
if ( ! store . getters [ 'user/getIsAdminOrUp' ] ) {
redirect ( '/' )
return
}
const authSettings = await app . $axios . $get ( '/api/auth-settings' ) . catch ( ( error ) => {
console . error ( 'Failed' , error )
return null
} )
if ( ! authSettings ) {
redirect ( '/config' )
return
}
return {
authSettings
}
} ,
data ( ) {
return {
enableLocalAuth : false ,
enableOpenIDAuth : false ,
savingSettings : false ,
newAuthSettings : { }
}
} ,
computed : {
authMethods ( ) {
return this . authSettings . authActiveAuthMethods || [ ]
2023-11-08 14:45:29 -06:00
} ,
matchingExistingOptions ( ) {
return [
{
text : 'Do not match' ,
value : null
} ,
{
text : 'Match by email' ,
value : 'email'
} ,
{
text : 'Match by username' ,
value : 'username'
}
]
2023-09-24 15:36:35 -05:00
}
} ,
methods : {
2023-11-05 14:11:37 -06:00
autoPopulateOIDCClick ( ) {
if ( ! this . newAuthSettings . authOpenIDIssuerURL ) {
this . $toast . error ( 'Issuer URL required' )
return
}
// Remove trailing slash
let issuerUrl = this . newAuthSettings . authOpenIDIssuerURL
if ( issuerUrl . endsWith ( '/' ) ) issuerUrl = issuerUrl . slice ( 0 , - 1 )
// If the full config path is on the issuer url then remove it
if ( issuerUrl . endsWith ( '/.well-known/openid-configuration' ) ) {
issuerUrl = issuerUrl . replace ( '/.well-known/openid-configuration' , '' )
this . newAuthSettings . authOpenIDIssuerURL = this . newAuthSettings . authOpenIDIssuerURL . replace ( '/.well-known/openid-configuration' , '' )
}
this . $axios
. $get ( ` /auth/openid/config?issuer= ${ issuerUrl } ` )
. then ( ( data ) => {
if ( data . issuer ) this . newAuthSettings . authOpenIDIssuerURL = data . issuer
if ( data . authorization _endpoint ) this . newAuthSettings . authOpenIDAuthorizationURL = data . authorization _endpoint
if ( data . token _endpoint ) this . newAuthSettings . authOpenIDTokenURL = data . token _endpoint
if ( data . userinfo _endpoint ) this . newAuthSettings . authOpenIDUserInfoURL = data . userinfo _endpoint
if ( data . end _session _endpoint ) this . newAuthSettings . authOpenIDLogoutURL = data . end _session _endpoint
if ( data . jwks _uri ) this . newAuthSettings . authOpenIDJwksURL = data . jwks _uri
} )
. catch ( ( error ) => {
console . error ( 'Failed to receive data' , error )
const errorMsg = error . response ? . data || 'Unknown error'
this . $toast . error ( errorMsg )
} )
} ,
2023-09-24 15:36:35 -05:00
validateOpenID ( ) {
let isValid = true
if ( ! this . newAuthSettings . authOpenIDIssuerURL ) {
this . $toast . error ( 'Issuer URL required' )
isValid = false
}
if ( ! this . newAuthSettings . authOpenIDAuthorizationURL ) {
this . $toast . error ( 'Authorize URL required' )
isValid = false
}
if ( ! this . newAuthSettings . authOpenIDTokenURL ) {
this . $toast . error ( 'Token URL required' )
isValid = false
}
if ( ! this . newAuthSettings . authOpenIDUserInfoURL ) {
this . $toast . error ( 'Userinfo URL required' )
isValid = false
}
2023-11-04 15:36:43 -05:00
if ( ! this . newAuthSettings . authOpenIDJwksURL ) {
this . $toast . error ( 'JWKS URL required' )
isValid = false
}
2023-09-24 15:36:35 -05:00
if ( ! this . newAuthSettings . authOpenIDClientID ) {
this . $toast . error ( 'Client ID required' )
isValid = false
}
if ( ! this . newAuthSettings . authOpenIDClientSecret ) {
this . $toast . error ( 'Client Secret required' )
isValid = false
}
return isValid
} ,
async saveSettings ( ) {
if ( ! this . enableLocalAuth && ! this . enableOpenIDAuth ) {
this . $toast . error ( 'Must have at least one authentication method enabled' )
return
}
if ( this . enableOpenIDAuth && ! this . validateOpenID ( ) ) {
return
}
this . newAuthSettings . authActiveAuthMethods = [ ]
if ( this . enableLocalAuth ) this . newAuthSettings . authActiveAuthMethods . push ( 'local' )
if ( this . enableOpenIDAuth ) this . newAuthSettings . authActiveAuthMethods . push ( 'openid' )
this . savingSettings = true
2023-11-10 16:11:51 -06:00
this . $axios
. $patch ( '/api/auth-settings' , this . newAuthSettings )
. then ( ( data ) => {
this . $store . commit ( 'setServerSettings' , data . serverSettings )
this . $toast . success ( 'Server settings updated' )
} )
. catch ( ( error ) => {
console . error ( 'Failed to update server settings' , error )
this . $toast . error ( 'Failed to update server settings' )
} )
. finally ( ( ) => {
this . savingSettings = false
} )
2023-09-24 15:36:35 -05:00
} ,
init ( ) {
this . newAuthSettings = {
... this . authSettings
}
this . enableLocalAuth = this . authMethods . includes ( 'local' )
this . enableOpenIDAuth = this . authMethods . includes ( 'openid' )
}
} ,
mounted ( ) {
this . init ( )
}
}
< / script >
2023-11-22 12:38:11 -06:00
< style >
# authentication - settings code {
font - size : 0.8 rem ;
border - radius : 6 px ;
background - color : rgb ( 82 , 82 , 82 ) ;
color : white ;
padding : 2 px 4 px ;
white - space : nowrap ;
}
< / style >