feat(oidc): private_key_jwt client auth (#5280)
This adds support for the private_key_jwt client authentication method. Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com> Co-authored-by: Amir Zarrinkafsh <nightah@me.com>pull/5437/head
parent
cef374cdc1
commit
65ecfe4b9a
|
@ -4,7 +4,16 @@
|
|||
# Authelia Configuration #
|
||||
###############################################################################
|
||||
|
||||
## Note: the container by default expects to find this file at /config/configuration.yml.
|
||||
##
|
||||
## Notes:
|
||||
##
|
||||
## - the default location of this file is assumed to be configuration.yml unless otherwise noted
|
||||
## - when using docker the container expects this by default to be at /config/configuration.yml
|
||||
## - the default location where this file is loaded from can be overridden with the X_AUTHELIA_CONFIG environment var
|
||||
## - the comments in this configuration file are helpful but users should consult the official documentation on the
|
||||
## website at https://www.authelia.com/ or https://www.authelia.com/configuration/prologue/introduction/
|
||||
## - this configuration file template is not automatically updated
|
||||
##
|
||||
|
||||
## Certificates directory specifies where Authelia will load trusted certificates (public portion) from in addition to
|
||||
## the system certificates store.
|
||||
|
@ -357,73 +366,37 @@ authentication_backend:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## The distinguished name of the container searched for objects in the directory information tree.
|
||||
|
@ -485,7 +458,7 @@ authentication_backend:
|
|||
# permit_referrals: false
|
||||
|
||||
## The username and password of the admin user.
|
||||
# user: cn=admin,dc=example,dc=com
|
||||
# user: 'cn=admin,dc=example,dc=com'
|
||||
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# password: 'password'
|
||||
|
||||
|
@ -622,7 +595,7 @@ access_control:
|
|||
# networks:
|
||||
# - '10.10.0.0/16'
|
||||
# - '192.168.2.0/24'
|
||||
# - name: VPN
|
||||
# - name: 'VPN'
|
||||
# networks: '10.9.0.0/16'
|
||||
|
||||
# rules:
|
||||
|
@ -748,7 +721,8 @@ session:
|
|||
# expiration: '1h'
|
||||
|
||||
## The time before the cookie expires and the session is destroyed if remember me IS selected by the user. Setting
|
||||
## this value to -1 disables remember me for this session cookie domain.
|
||||
## this value to -1 disables remember me for this session cookie domain. If allowed and the user uses the remember
|
||||
## me checkbox this overrides the expiration option and disables the inactivity option.
|
||||
# remember_me: '1M'
|
||||
|
||||
## Cookie Session Domain default 'name' value.
|
||||
|
@ -816,73 +790,37 @@ session:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## The Redis HA configuration options.
|
||||
|
@ -997,73 +935,37 @@ regulation:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1116,73 +1018,37 @@ regulation:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1270,73 +1136,37 @@ notifier:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1354,80 +1184,88 @@ notifier:
|
|||
## HMAC Secret can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# hmac_secret: 'this_is_a_secret_abc123abc123abc'
|
||||
|
||||
## The issuer_certificate_chain is an optional PEM encoded certificate chain. It's used in conjunction with the
|
||||
## issuer_private_key to sign JWT's. All certificates in the chain must be within the validity period, and every
|
||||
## certificate included must be signed by the certificate immediately after it if provided.
|
||||
# issuer_certificate_chain: |
|
||||
## Issuer JWKS configures multiple JSON Web Keys. It's required that at least one of these is RS256 or the
|
||||
## option issuer_private_key is configured. There must only be one key per algorithm at this time.
|
||||
## For RSA keys the minimum is a 2048 bit key.
|
||||
# issuer_private_keys:
|
||||
# -
|
||||
## Key ID embedded into the JWT header for key matching. Must be an alphanumeric string with 7 or less characters.
|
||||
## This value is automatically generated if not provided. It's recommended to not configure this.
|
||||
# key_id: 'example'
|
||||
|
||||
## The key algorithm used with this key.
|
||||
# algorithm: 'RS256'
|
||||
|
||||
## The key use expected with this key. Currently only 'sig' is supported.
|
||||
# use: 'sig'
|
||||
|
||||
## Required Private Key in PEM DER form.
|
||||
# key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
|
||||
## Optional matching certificate chain in PEM DER form that matches the key. All certificates within the chain
|
||||
## must be valid and current, and from top to bottom each certificate must be signed by the subsequent one.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The issuer_private_key is used to sign the JWT forged by OpenID Connect.
|
||||
## The issuer_private_key is used to sign the JWT forged by OpenID Connect. This is in addition to the
|
||||
## issuer_private_keys option. Assumed to use the RS256 algorithm, and must not be specified if any of the
|
||||
## keys in issuer_private_keys also has the algorithm RS256 or are an RSA key without an algorithm.
|
||||
## Issuer Private Key can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# issuer_private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## Optional matching certificate chain in PEM DER form that matches the issuer_private_key. All certificates within
|
||||
## the chain must be valid and current, and from top to bottom each certificate must be signed by the next
|
||||
## certificate in the chain if provided.
|
||||
# issuer_certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The lifespans configure the expiration for these token types in the duration common syntax.
|
||||
# access_token_lifespan: '1h'
|
||||
# authorize_code_lifespan: '1m'
|
||||
|
@ -1499,6 +1337,11 @@ notifier:
|
|||
# - 'email'
|
||||
# - 'profile'
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - 'authorization_code'
|
||||
|
||||
## Response Types configures which responses this client can be sent.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# response_types:
|
||||
|
@ -1509,25 +1352,19 @@ notifier:
|
|||
# - 'form_post'
|
||||
# - 'query'
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - 'authorization_code'
|
||||
|
||||
## The permitted client authentication method for the Token Endpoint for this client.
|
||||
# token_endpoint_auth_method: 'client_secret_basic'
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: HS256
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: HS256
|
||||
|
||||
## The policy to require for this client; one_factor or two_factor.
|
||||
# authorization_policy: 'two_factor'
|
||||
|
||||
## The consent mode controls how consent is obtained.
|
||||
# consent_mode: 'auto'
|
||||
|
||||
## This value controls the duration a consent on this client remains remembered when the consent mode is
|
||||
## configured as 'auto' or 'pre-configured' in the duration common syntax.
|
||||
# pre_configured_consent_duration: '1w'
|
||||
|
||||
## Enforces the use of Pushed Authorization Requests for this client when set to true.
|
||||
# enforce_par: false
|
||||
|
||||
## Enforces the use of PKCE for this client when set to true.
|
||||
# enforce_pkce: false
|
||||
|
||||
|
@ -1535,13 +1372,69 @@ notifier:
|
|||
## Options are 'plain' and 'S256'.
|
||||
# pkce_challenge_method: 'S256'
|
||||
|
||||
## The permitted client authentication method for the Token Endpoint for this client.
|
||||
# token_endpoint_auth_method: 'client_secret_basic'
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' or 'private_key_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: 'RS256'
|
||||
|
||||
## The signing algorithm which must be used for request objects. A client JWK with a matching algorithm must be
|
||||
## included if configured.
|
||||
# request_object_signing_alg: 'RS256'
|
||||
|
||||
## The signing algorithm used for ID Tokens. Am issuer JWK with a matching algorithm must be included.
|
||||
# id_token_signing_alg: 'RS256'
|
||||
|
||||
## The algorithm used to sign userinfo endpoint responses for this client, either none or RS256.
|
||||
# userinfo_signing_algorithm: 'none'
|
||||
# userinfo_signing_alg: 'none'
|
||||
|
||||
## The consent mode controls how consent is obtained.
|
||||
# consent_mode: 'auto'
|
||||
## Trusted public keys configuration for request object signing for things such as private_key_jwt
|
||||
# public_keys:
|
||||
|
||||
## This value controls the duration a consent on this client remains remembered when the consent mode is
|
||||
## configured as 'auto' or 'pre-configured' in the duration common syntax.
|
||||
# pre_configured_consent_duration: '1w'
|
||||
## URL of the HTTPS endpoint which serves the keys. It's recommended to manually configure them in the
|
||||
## values option below. Please note the URL and the individual values are mutually exclusive.
|
||||
# uri: 'https://app.example.com/jwks.json'
|
||||
|
||||
## Values from the individual keys.
|
||||
# values:
|
||||
# -
|
||||
## Key ID used to match the JWT's to an individual identifier. This option is required if configured.
|
||||
# key_id: 'example'
|
||||
|
||||
## The key algorithm expected with this key.
|
||||
# algorithm: 'RS256'
|
||||
|
||||
## The key use expected with this key. Currently only 'sig' is supported.
|
||||
# use: 'sig'
|
||||
|
||||
## Required Public Key in PEM DER form.
|
||||
# key: |
|
||||
# -----BEGIN RSA PUBLIC KEY-----
|
||||
# MEgCQQDAwV26ZA1lodtOQxNrJ491gWT+VzFum9IeZ+WTmMypYWyW1CzXKwsvTHDz
|
||||
# 9ec+jserR3EMQ0Rr24lj13FL1ib5AgMBAAE=
|
||||
# -----END RSA PUBLIC KEY----
|
||||
|
||||
## The matching certificate chain in PEM DER form that matches the key if available.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
...
|
||||
|
|
|
@ -16,4 +16,4 @@ aliases:
|
|||
|
||||
## OpenID Connect
|
||||
|
||||
The only identity provider implementation supported at this time is [OpenID Connect 1.0](open-id-connect.md).
|
||||
The only identity provider implementation supported at this time is [OpenID Connect 1.0](openid-connect/provider.md).
|
||||
|
|
|
@ -1,671 +0,0 @@
|
|||
---
|
||||
title: "OpenID Connect"
|
||||
description: "OpenID Connect Configuration"
|
||||
lead: "Authelia can operate as an OpenID Connect 1.0 Provider. This section describes how to configure this."
|
||||
date: 2022-06-15T17:51:47+10:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
configuration:
|
||||
parent: "identity-providers"
|
||||
weight: 190200
|
||||
toc: true
|
||||
aliases:
|
||||
- /c/oidc
|
||||
- /docs/configuration/identity-providers/oidc.html
|
||||
---
|
||||
|
||||
__Authelia__ currently supports the [OpenID Connect 1.0] Provider role as an open
|
||||
[__beta__](../../roadmap/active/openid-connect.md) feature. We currently do not support the [OpenID Connect 1.0] Relying
|
||||
Party role. This means other applications that implement the [OpenID Connect 1.0] Relying Party role can use Authelia as
|
||||
an [OpenID Connect 1.0] Provider similar to how you may use social media or development platforms for login.
|
||||
|
||||
The [OpenID Connect 1.0] Relying Party role is the role which allows an application to use GitHub, Google, or other
|
||||
[OpenID Connect 1.0] Providers for authentication and authorization. We do not intend to support this functionality at
|
||||
this moment in time.
|
||||
|
||||
More information about the beta can be found in the [roadmap](../../roadmap/active/openid-connect.md).
|
||||
|
||||
## Configuration
|
||||
|
||||
The following snippet provides a sample-configuration for the OIDC identity provider explaining each field in detail.
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
hmac_secret: this_is_a_secret_abc123abc123abc
|
||||
issuer_certificate_chain: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
qocikt3WAdU^invalid DO NOT USE=
|
||||
-----END CERTIFICATE-----
|
||||
issuer_private_key: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
DO NOT USE==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
issuer_jwks:
|
||||
- key_id: ''
|
||||
algorithm: 'RS256'
|
||||
key: |
|
||||
<private key data>
|
||||
certificate_chain: |
|
||||
<certificate chain data>
|
||||
access_token_lifespan: 1h
|
||||
authorize_code_lifespan: 1m
|
||||
id_token_lifespan: 1h
|
||||
refresh_token_lifespan: 90m
|
||||
enable_client_debug_messages: false
|
||||
enforce_pkce: public_clients_only
|
||||
cors:
|
||||
endpoints:
|
||||
- authorization
|
||||
- token
|
||||
- revocation
|
||||
- introspection
|
||||
allowed_origins:
|
||||
- https://example.com
|
||||
allowed_origins_from_client_redirect_uris: false
|
||||
clients:
|
||||
- id: myapp
|
||||
description: My Application
|
||||
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
|
||||
sector_identifier: ''
|
||||
public: false
|
||||
authorization_policy: two_factor
|
||||
consent_mode: explicit
|
||||
pre_configured_consent_duration: 1w
|
||||
audience: []
|
||||
scopes:
|
||||
- openid
|
||||
- groups
|
||||
- email
|
||||
- profile
|
||||
redirect_uris:
|
||||
- https://oidc.example.com:8080/oauth2/callback
|
||||
grant_types:
|
||||
- refresh_token
|
||||
- authorization_code
|
||||
response_types:
|
||||
- code
|
||||
response_modes:
|
||||
- form_post
|
||||
- query
|
||||
- fragment
|
||||
userinfo_signing_algorithm: none
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### hmac_secret
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
|
||||
especially for containerized deployments.*
|
||||
|
||||
The HMAC secret used to sign the [JWT]'s. The provided string is hashed to a SHA256 ([RFC6234]) byte string for the
|
||||
purpose of meeting the required format.
|
||||
|
||||
It's __strongly recommended__ this is a
|
||||
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string)
|
||||
with 64 or more characters.
|
||||
|
||||
### issuer_private_key
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
|
||||
especially for containerized deployments.*
|
||||
|
||||
The private key used to sign/encrypt the [OpenID Connect 1.0] issued [JWT]'s. The key must be generated by the administrator
|
||||
and can be done by following the
|
||||
[Generating an RSA Keypair](../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
|
||||
The private key *__MUST__*:
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be an RSA Key.
|
||||
* Have a key size of at least 2048 bits.
|
||||
|
||||
If the [issuer_certificate_chain](#issuercertificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
### issuer_certificate_chain
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The certificate chain/bundle to be used with the [issuer_private_key](#issuer_private_key) DER base64 ([RFC4648])
|
||||
encoded PEM format used to sign/encrypt the [OpenID Connect 1.0] [JWT]'s. When configured it enables the [x5c] and [x5t]
|
||||
JSON key's in the JWKs [Discoverable Endpoint](../../integration/openid-connect/introduction.md#discoverable-endpoints)
|
||||
as per [RFC7517].
|
||||
|
||||
[RFC7517]: https://datatracker.ietf.org/doc/html/rfc7517
|
||||
[x5c]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.7
|
||||
[x5t]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.8
|
||||
|
||||
The first certificate in the chain must have the public key for the [issuer_private_key](#issuerprivatekey), each
|
||||
certificate in the chain must be valid for the current date, and each certificate in the chain should be signed by the
|
||||
certificate immediately following it if present.
|
||||
|
||||
### issuer_jwks
|
||||
|
||||
{{< confkey type="list(object" required="no" >}}
|
||||
|
||||
The list of JWKS instead of or in addition to the [issuer_private_key](#issuerprivatekey) and
|
||||
[issuer_certificate_chain](#issuercertificatechain). Can also accept ECDSA Private Key's and Certificates.
|
||||
|
||||
#### key_id
|
||||
|
||||
{{< confkey type="string" default="<thumbprint of public key>" required="no" >}}
|
||||
|
||||
Completely optional, and generally discouraged unless there is a collision between the automatically generated key id's.
|
||||
If provided must be a unique string with 7 or less alphanumeric characters.
|
||||
|
||||
This value is the first 7 characters of the public key thumbprint (SHA1) encoded into hexadecimal.
|
||||
|
||||
#### algorithm
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The algorithm for this key. This value must be unique. It's automatically detected based on the type of key.
|
||||
|
||||
#### key
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The private key associated with this key entry.
|
||||
|
||||
The private key used to sign/encrypt the [OpenID Connect 1.0] issued [JWT]'s. The key must be generated by the administrator
|
||||
and can be done by following the
|
||||
[Generating an RSA Keypair](../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
|
||||
The private key *__MUST__*:
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be one of:
|
||||
* An RSA key with a key size of at least 2048 bits.
|
||||
* An ECDSA private key with one of the P-256, P-384, or P-521 elliptical curves.
|
||||
|
||||
If the [certificate_chain](#certificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
#### certificate_chain
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The certificate chain/bundle to be used with the [key](#key) DER base64 ([RFC4648])
|
||||
encoded PEM format used to sign/encrypt the [OpenID Connect 1.0] [JWT]'s. When configured it enables the [x5c] and [x5t]
|
||||
JSON key's in the JWKs [Discoverable Endpoint](../../integration/openid-connect/introduction.md#discoverable-endpoints)
|
||||
as per [RFC7517].
|
||||
|
||||
[RFC7517]: https://datatracker.ietf.org/doc/html/rfc7517
|
||||
[x5c]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.7
|
||||
[x5t]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.8
|
||||
|
||||
The first certificate in the chain must have the public key for the [key](#key), each certificate in the chain must be
|
||||
valid for the current date, and each certificate in the chain should be signed by the certificate immediately following
|
||||
it if present.
|
||||
|
||||
### access_token_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1h" required="no" >}}
|
||||
|
||||
The maximum lifetime of an access token. It's generally recommended keeping this short similar to the default.
|
||||
For more information read these docs about [token lifespan].
|
||||
|
||||
### authorize_code_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1m" required="no" >}}
|
||||
|
||||
The maximum lifetime of an authorize code. This can be rather short, as the authorize code should only be needed to
|
||||
obtain the other token types. For more information read these docs about [token lifespan].
|
||||
|
||||
### id_token_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1h" required="no" >}}
|
||||
|
||||
The maximum lifetime of an ID token. For more information read these docs about [token lifespan].
|
||||
|
||||
### refresh_token_lifespan
|
||||
|
||||
{{< confkey type="string" default="90m" required="no" >}}
|
||||
|
||||
The maximum lifetime of a refresh token. The
|
||||
refresh token can be used to obtain new refresh tokens as well as access tokens or id tokens with an
|
||||
up-to-date expiration. For more information read these docs about [token lifespan].
|
||||
|
||||
A good starting point is 50% more or 30 minutes more (which ever is less) time than the highest lifespan out of the
|
||||
[access token lifespan](#access_token_lifespan), the [authorize code lifespan](#authorize_code_lifespan), and the
|
||||
[id token lifespan](#id_token_lifespan). For instance the default for all of these is 60 minutes, so the default refresh
|
||||
token lifespan is 90 minutes.
|
||||
|
||||
### enable_client_debug_messages
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Allows additional debug messages to be sent to the clients.
|
||||
|
||||
### minimum_parameter_entropy
|
||||
|
||||
{{< confkey type="integer" default="8" required="no" >}}
|
||||
|
||||
This controls the minimum length of the `nonce` and `state` parameters.
|
||||
|
||||
*__Security Notice:__* Changing this value is generally discouraged, reducing it from the default can theoretically
|
||||
make certain scenarios less secure. It is highly encouraged that if your OpenID Connect RP does not send these
|
||||
parameters or sends parameters with a lower length than the default that they implement a change rather than changing
|
||||
this value.
|
||||
|
||||
### enforce_pkce
|
||||
|
||||
{{< confkey type="string" default="public_clients_only" required="no" >}}
|
||||
|
||||
[Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636) enforcement policy: if specified, must be
|
||||
either `never`, `public_clients_only` or `always`.
|
||||
|
||||
If set to `public_clients_only` (default), [PKCE] will be required for public clients using the
|
||||
[Authorization Code Flow].
|
||||
|
||||
When set to `always`, [PKCE] will be required for all clients using the Authorization Code flow.
|
||||
|
||||
*__Security Notice:__* Changing this value to `never` is generally discouraged, reducing it from the default can
|
||||
theoretically make certain client-side applications (mobile applications, SPA) vulnerable to CSRF and authorization code
|
||||
interception attacks.
|
||||
|
||||
### enable_pkce_plain_challenge
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Allows [PKCE] `plain` challenges when set to `true`.
|
||||
|
||||
*__Security Notice:__* Changing this value is generally discouraged. Applications should use the `S256` [PKCE] challenge
|
||||
method instead.
|
||||
|
||||
### pushed_authorizations
|
||||
|
||||
Controls the behaviour of [Pushed Authorization Requests].
|
||||
|
||||
#### enforce
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
When enabled all authorization requests must use the [Pushed Authorization Requests] flow.
|
||||
|
||||
#### context_lifespan
|
||||
|
||||
{{< confkey type="duration" default="5m" required="no" >}}
|
||||
|
||||
The maximum amount of time between the [Pushed Authorization Requests] flow being initiated and the generated
|
||||
`request_uri` being utilized by a client.
|
||||
|
||||
### cors
|
||||
|
||||
Some [OpenID Connect 1.0] Endpoints need to allow cross-origin resource sharing, however some are optional. This section allows
|
||||
you to configure the optional parts. We reply with CORS headers when the request includes the Origin header.
|
||||
|
||||
#### endpoints
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of endpoints to configure with cross-origin resource sharing headers. It is recommended that the `userinfo`
|
||||
option is at least in this list. The potential endpoints which this can be enabled on are as follows:
|
||||
|
||||
* authorization
|
||||
* pushed-authorization-request
|
||||
* token
|
||||
* revocation
|
||||
* introspection
|
||||
* userinfo
|
||||
|
||||
#### allowed_origins
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of permitted origins.
|
||||
|
||||
Any origin with https is permitted unless this option is configured or the
|
||||
[allowed_origins_from_client_redirect_uris](#allowed_origins_from_client_redirect_uris) option is enabled. This means
|
||||
you must configure this option manually if you want http endpoints to be permitted to make cross-origin requests to the
|
||||
[OpenID Connect 1.0] endpoints, however this is not recommended.
|
||||
|
||||
Origins must only have the scheme, hostname and port, they may not have a trailing slash or path.
|
||||
|
||||
In addition to an Origin URI, you may specify the wildcard origin in the allowed_origins. It MUST be specified by itself
|
||||
and the [allowed_origins_from_client_redirect_uris](#allowedoriginsfromclientredirecturis) MUST NOT be enabled. The
|
||||
wildcard origin is denoted as `*`. Examples:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
cors:
|
||||
allowed_origins: "*"
|
||||
```
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
#### allowed_origins_from_client_redirect_uris
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Automatically adds the origin portion of all redirect URI's on all clients to the list of
|
||||
[allowed_origins](#allowed_origins), provided they have the scheme http or https and do not have the hostname of
|
||||
localhost.
|
||||
|
||||
### clients
|
||||
|
||||
{{< confkey type="list" required="yes" >}}
|
||||
|
||||
A list of clients to configure. The options for each client are described below.
|
||||
|
||||
#### id
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The Client ID for this client. It must exactly match the Client ID configured in the application
|
||||
consuming this client.
|
||||
|
||||
#### description
|
||||
|
||||
{{< confkey type="string" default="*same as id*" required="no" >}}
|
||||
|
||||
A friendly description for this client shown in the UI. This defaults to the same as the ID.
|
||||
|
||||
#### secret
|
||||
|
||||
{{< confkey type="string" required="situational" >}}
|
||||
|
||||
The shared secret between Authelia and the application consuming this client. This secret must match the secret
|
||||
configured in the application.
|
||||
|
||||
This secret must be generated by the administrator and can be done by following the
|
||||
[How Do I Generate Client Secrets](../../integration/openid-connect/frequently-asked-questions.md#how-do-i-generate-client-secrets) FAQ.
|
||||
|
||||
This must be provided when the client is a confidential client type, and must be blank when using the public client
|
||||
type. To set the client type to public see the [public](#public) configuration option.
|
||||
|
||||
#### sector_identifier
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
*__Important Note:__ because adjusting this option will inevitably change the `sub` claim of all tokens generated for
|
||||
the specified client, changing this should cause the relying party to detect all future authorizations as completely new
|
||||
users.*
|
||||
|
||||
Must be an empty string or the host component of a URL. This is commonly just the domain name, but may also include a
|
||||
port.
|
||||
|
||||
Authelia utilizes UUID version 4 subject identifiers. By default the public [Subject Identifier Type] is utilized for
|
||||
all clients. This means the subject identifiers will be the same for all clients. This configuration option enables
|
||||
[Pairwise Identifier Algorithm] for this client, and configures the sector identifier utilized for both the storage and
|
||||
the lookup of the subject identifier.
|
||||
|
||||
1. All clients who do not have this configured will generate the same subject identifier for a particular user
|
||||
regardless of which client obtains the ID token.
|
||||
2. All clients which have the same sector identifier will:
|
||||
1. have the same subject identifier for a particular user when compared to clients with the same sector identifier.
|
||||
2. have a completely different subject identifier for a particular user whe compared to:
|
||||
1. any client with the public subject identifier type.
|
||||
2. any client with a differing sector identifier.
|
||||
|
||||
In specific but limited scenarios this option is beneficial for privacy reasons. In particular this is useful when the
|
||||
party utilizing the *Authelia* [OpenID Connect 1.0] Authorization Server is foreign and not controlled by the user. It would
|
||||
prevent the third party utilizing the subject identifier with another third party in order to track the user.
|
||||
|
||||
Keep in mind depending on the other claims they may still be able to perform this tracking and it is not a silver
|
||||
bullet. There are very few benefits when utilizing this in a homelab or business where no third party is utilizing
|
||||
the server.
|
||||
|
||||
#### public
|
||||
|
||||
{{< confkey type="bool" default="false" required="no" >}}
|
||||
|
||||
This enables the public client type for this client. This is for clients that are not capable of maintaining
|
||||
confidentiality of credentials, you can read more about client types in [RFC6749 Section 2.1]. This is particularly
|
||||
useful for SPA's and CLI tools. This option requires setting the [client secret](#secret) to a blank string.
|
||||
|
||||
#### redirect_uris
|
||||
|
||||
{{< confkey type="list(string)" required="yes" >}}
|
||||
|
||||
A list of valid callback URIs this client will redirect to. All other callbacks will be considered unsafe. The URIs are
|
||||
case-sensitive and they differ from application to application - the community has provided
|
||||
[a list of URL´s for common applications](../../integration/openid-connect/introduction.md).
|
||||
|
||||
Some restrictions that have been placed on clients and
|
||||
their redirect URIs are as follows:
|
||||
|
||||
1. If a client attempts to authorize with Authelia and its redirect URI is not listed in the client configuration the
|
||||
attempt to authorize will fail and an error will be generated.
|
||||
2. The redirect URIs are case-sensitive.
|
||||
3. The URI must include a scheme and that scheme must be one of `http` or `https`.
|
||||
|
||||
#### audience
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of audiences this client is allowed to request.
|
||||
|
||||
#### scopes
|
||||
|
||||
{{< confkey type="list(string)" default="openid, groups, profile, email" required="no" >}}
|
||||
|
||||
A list of scopes to allow this client to consume. See
|
||||
[scope definitions](../../integration/openid-connect/introduction.md#scope-definitions) for more information. The
|
||||
documentation for the application you are trying to configure [OpenID Connect 1.0] for will likely have a list of scopes
|
||||
or claims required which can be matched with the above guide.
|
||||
|
||||
#### response_types
|
||||
|
||||
{{< confkey type="list(string)" default="code" required="no" >}}
|
||||
|
||||
*__Security Note:__ It is recommended that only the `code` response type (i.e. the default) is used. The other response
|
||||
types are not as secure as this response type.*
|
||||
|
||||
A list of response types this client supports. If a response type not in this list is requested by a client then an
|
||||
error will be returned to the client. The response type indicates the types of values that are returned to the client.
|
||||
|
||||
See the [Response Types](../../integration/openid-connect/introduction.md#response-types) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#response-types) for more information.
|
||||
|
||||
#### response_modes
|
||||
|
||||
{{< confkey type="list(string)" default="form_post, query" required="no" >}}
|
||||
|
||||
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
|
||||
|
||||
A list of response modes this client supports. If a response mode not in this list is requested by a client then an
|
||||
error will be returned to the client. The response mode controls how the response type is returned to the client.
|
||||
|
||||
See the [Response Modes](../../integration/openid-connect/introduction.md#response-modes) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#response-modes) for more
|
||||
information.
|
||||
|
||||
The default values are based on the [response_types](#responsetypes) values. When the [response_types](#responsetypes)
|
||||
values include the `code` type then the `query` response mode will be included. When any other type is included the
|
||||
`fragment` response mode will be included. It's important to note at this time we do not support the `none` response
|
||||
type, but when it is supported it will include the `query` response mode.
|
||||
|
||||
#### grant_types
|
||||
|
||||
{{< confkey type="list(string)" default="authorization_code" required="no" >}}
|
||||
|
||||
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
|
||||
|
||||
The list of grant types this client is permitted to use in order to obtain access to the relevant tokens.
|
||||
|
||||
See the [Grant Types](../../integration/openid-connect/introduction.md#grant-types) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#grant-types) for more information.
|
||||
|
||||
#### authorization_policy
|
||||
|
||||
{{< confkey type="string" default="two_factor" required="no" >}}
|
||||
|
||||
The authorization policy for this client: either `one_factor` or `two_factor`.
|
||||
|
||||
#### enforce_par
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Enforces the use of a [Pushed Authorization Requests] flow for this client.
|
||||
|
||||
#### enforce_pkce
|
||||
|
||||
{{< confkey type="bool" default="false" required="no" >}}
|
||||
|
||||
This setting enforces the use of [PKCE] for this individual client. To enforce it for all clients see the global
|
||||
[enforce_pkce](#enforcepkce) setting.
|
||||
|
||||
#### pkce_challenge_method
|
||||
|
||||
{{< confkey type="string" default="" required="no" >}}
|
||||
|
||||
This setting enforces the use of the specified [PKCE] challenge method for this individual client. This setting also
|
||||
effectively enables the [enforce_pkce](#enforcepkce-1) option for this client.
|
||||
|
||||
Valid values are an empty string, `plain`, or `S256`. It should be noted that `S256` is strongly recommended if the
|
||||
relying party supports it.
|
||||
|
||||
#### userinfo_signing_algorithm
|
||||
|
||||
{{< confkey type="string" default="none" required="no" >}}
|
||||
|
||||
The algorithm used to sign the userinfo endpoint responses. This can either be `none` or `RS256`.
|
||||
|
||||
See the [integration guide](../../integration/openid-connect/introduction.md#user-information-signing-algorithm) for
|
||||
more information.
|
||||
|
||||
#### token_endpoint_auth_method
|
||||
|
||||
{{< confkey type="string" default="" required="no" >}}
|
||||
|
||||
The registered client authentication mechanism used by this client for the [Token Endpoint]. If no method is defined
|
||||
the confidential client type will accept any supported method. The public client type defaults to `none` as this
|
||||
is required by the specification. This may be required as a breaking change in future versions.
|
||||
Supported values are `client_secret_basic`, `client_secret_post`, `client_secret_jwt`, and `none`.
|
||||
|
||||
See the [integration guide](../../integration/openid-connect/introduction.md#client-authentication-method) for
|
||||
more information.
|
||||
|
||||
#### token_endpoint_auth_signing_alg
|
||||
|
||||
{{< confkey type="string" default="HS256" required="no" >}}
|
||||
|
||||
The JWT signing algorithm accepted when the [token_endpoint_auth_method](#tokenendpointauthmethod) is configured as
|
||||
`client_secret_jwt`. Supported values are `HS256`, `HS385`, and `HS512`.
|
||||
|
||||
#### consent_mode
|
||||
|
||||
{{< confkey type="string" default="auto" required="no" >}}
|
||||
|
||||
*__Important Note:__ the `implicit` consent mode is not technically part of the specification. It theoretically could be
|
||||
misused in certain conditions specifically with the public client type or when the client credentials (i.e. client
|
||||
secret) has been exposed to an attacker. For these reasons this mode is discouraged.*
|
||||
|
||||
Configures the consent mode. The following table describes the different modes:
|
||||
|
||||
| Value | Description |
|
||||
|:--------------:|:----------------------------------------------------------------------------------------------------------------------------------------------:|
|
||||
| auto | Automatically determined (default). Uses `explicit` unless [pre_configured_consent_duration] is specified in which case uses `pre-configured`. |
|
||||
| explicit | Requires the user provide unique explicit consent for every authorization. |
|
||||
| implicit | Automatically assumes consent for every authorization, never asking the user if they wish to give consent. |
|
||||
| pre-configured | Allows the end-user to remember their consent for the [pre_configured_consent_duration]. |
|
||||
|
||||
[pre_configured_consent_duration]: #preconfiguredconsentduration
|
||||
|
||||
#### pre_configured_consent_duration
|
||||
|
||||
{{< confkey type="duration" default="1w" required="no" >}}
|
||||
|
||||
*__Note:__ This setting uses the [duration notation format](../prologue/common.md#duration-notation-format). Please see
|
||||
the [common options](../prologue/common.md#duration-notation-format) documentation for information on this format.*
|
||||
|
||||
Specifying this in the configuration without a consent [consent_mode] enables the `pre-configured` mode. If this is
|
||||
specified as well as the [consent_mode] then it only has an effect if the [consent_mode] is `pre-configured` or `auto`.
|
||||
|
||||
The period of time dictates how long a users choice to remember the pre-configured consent lasts.
|
||||
|
||||
Pre-configured consents are only valid if the subject, client id are exactly the same and the requested scopes/audience
|
||||
match exactly with the granted scopes/audience.
|
||||
|
||||
[consent_mode]: #consentmode
|
||||
|
||||
## Integration
|
||||
|
||||
To integrate Authelia's [OpenID Connect 1.0] implementation with a relying party please see the
|
||||
[integration docs](../../integration/openid-connect/introduction.md).
|
||||
|
||||
[token lifespan]: https://docs.apigee.com/api-platform/antipatterns/oauth-long-expiration
|
||||
[OpenID Connect 1.0]: https://openid.net/connect/
|
||||
[Token Endpoint]: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||
[JWT]: https://datatracker.ietf.org/doc/html/rfc7519
|
||||
[RFC6234]: https://datatracker.ietf.org/doc/html/rfc6234
|
||||
[RFC4648]: https://datatracker.ietf.org/doc/html/rfc4648
|
||||
[RFC7468]: https://datatracker.ietf.org/doc/html/rfc7468
|
||||
[RFC6749 Section 2.1]: https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
|
||||
[PKCE]: https://datatracker.ietf.org/doc/html/rfc7636
|
||||
[Authorization Code Flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
||||
[Subject Identifier Type]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
||||
[Pairwise Identifier Algorithm]: https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg
|
||||
[Pushed Authorization Requests]: https://datatracker.ietf.org/doc/html/rfc9126
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: "OpenID Connect 1.0"
|
||||
description: ""
|
||||
lead: ""
|
||||
date: 2023-05-08T13:38:08+10:00
|
||||
lastmod: 2022-01-18T20:07:56+01:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
docs:
|
||||
parent: "identity-providers"
|
||||
identifier: "openid-connect"
|
||||
weight: 190120
|
||||
toc: true
|
||||
---
|
|
@ -0,0 +1,413 @@
|
|||
---
|
||||
title: "OpenID Connect 1.0 Clients"
|
||||
description: "OpenID Connect 1.0 Registered Clients Configuration"
|
||||
lead: "Authelia can operate as an OpenID Connect 1.0 Provider. This section describes how to configure the registered clients."
|
||||
date: 2023-05-08T13:38:08+10:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
configuration:
|
||||
parent: "openid-connect"
|
||||
weight: 190220
|
||||
toc: true
|
||||
---
|
||||
|
||||
This section covers specifics regarding configuring the providers registered clients for [OpenID Connect 1.0]. For the
|
||||
provider specific configuration and information not related to clients see the [OpenID Connect 1.0 Provider](provider.md)
|
||||
documentation.
|
||||
|
||||
More information about OpenID Connect can be found in the [roadmap](../../../roadmap/active/openid-connect.md) and in the
|
||||
[integration](../../../integration/openid-connect/introduction.md) documentation.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following snippet provides a configuration example for the [OpenID Connect 1.0] Registered Clients. This is not
|
||||
intended for production use it's used to provide context and an indentation example.
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
clients:
|
||||
- id: myapp
|
||||
description: My Application
|
||||
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
|
||||
sector_identifier: ''
|
||||
public: false
|
||||
redirect_uris:
|
||||
- https://oidc.example.com:8080/oauth2/callback
|
||||
audience: []
|
||||
scopes:
|
||||
- openid
|
||||
- groups
|
||||
- email
|
||||
- profile
|
||||
grant_types:
|
||||
- refresh_token
|
||||
- authorization_code
|
||||
response_types:
|
||||
- code
|
||||
response_modes:
|
||||
- form_post
|
||||
- query
|
||||
- fragment
|
||||
authorization_policy: two_factor
|
||||
consent_mode: explicit
|
||||
pre_configured_consent_duration: 1w
|
||||
enforce_par: false
|
||||
enforce_pkce: false
|
||||
pkce_challenge_method: S256
|
||||
token_endpoint_auth_method: ''
|
||||
token_endpoint_auth_signing_alg: RS256
|
||||
id_token_signing_alg: RS256
|
||||
request_object_signing_alg: RS256
|
||||
userinfo_signing_alg: none
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### id
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The Client ID for this client. It must exactly match the Client ID configured in the application consuming this client.
|
||||
|
||||
### description
|
||||
|
||||
{{< confkey type="string" default="*same as id*" required="no" >}}
|
||||
|
||||
A friendly description for this client shown in the UI. This defaults to the same as the ID.
|
||||
|
||||
### secret
|
||||
|
||||
{{< confkey type="string" required="situational" >}}
|
||||
|
||||
The shared secret between Authelia and the application consuming this client. This secret must match the secret
|
||||
configured in the application.
|
||||
|
||||
This secret must be generated by the administrator and can be done by following the
|
||||
[How Do I Generate Client Secrets](../../../integration/openid-connect/frequently-asked-questions.md#how-do-i-generate-client-secrets) FAQ.
|
||||
|
||||
This must be provided when the client is a confidential client type, and must be blank when using the public client
|
||||
type. To set the client type to public see the [public](#public) configuration option.
|
||||
|
||||
### sector_identifier
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
*__Important Note:__ because adjusting this option will inevitably change the `sub` claim of all tokens generated for
|
||||
the specified client, changing this should cause the relying party to detect all future authorizations as completely new
|
||||
users.*
|
||||
|
||||
Must be an empty string or the host component of a URL. This is commonly just the domain name, but may also include a
|
||||
port.
|
||||
|
||||
Authelia utilizes UUID version 4 subject identifiers. By default the public [Subject Identifier Type] is utilized for
|
||||
all clients. This means the subject identifiers will be the same for all clients. This configuration option enables
|
||||
[Pairwise Identifier Algorithm] for this client, and configures the sector identifier utilized for both the storage and
|
||||
the lookup of the subject identifier.
|
||||
|
||||
1. All clients who do not have this configured will generate the same subject identifier for a particular user
|
||||
regardless of which client obtains the ID token.
|
||||
2. All clients which have the same sector identifier will:
|
||||
1. have the same subject identifier for a particular user when compared to clients with the same sector identifier.
|
||||
2. have a completely different subject identifier for a particular user whe compared to:
|
||||
1. any client with the public subject identifier type.
|
||||
2. any client with a differing sector identifier.
|
||||
|
||||
In specific but limited scenarios this option is beneficial for privacy reasons. In particular this is useful when the
|
||||
party utilizing the *Authelia* [OpenID Connect 1.0] Authorization Server is foreign and not controlled by the user. It would
|
||||
prevent the third party utilizing the subject identifier with another third party in order to track the user.
|
||||
|
||||
Keep in mind depending on the other claims they may still be able to perform this tracking and it is not a silver
|
||||
bullet. There are very few benefits when utilizing this in a homelab or business where no third party is utilizing
|
||||
the server.
|
||||
|
||||
### public
|
||||
|
||||
{{< confkey type="bool" default="false" required="no" >}}
|
||||
|
||||
This enables the public client type for this client. This is for clients that are not capable of maintaining
|
||||
confidentiality of credentials, you can read more about client types in [RFC6749 Section 2.1]. This is particularly
|
||||
useful for SPA's and CLI tools. This option requires setting the [client secret](#secret) to a blank string.
|
||||
|
||||
### redirect_uris
|
||||
|
||||
{{< confkey type="list(string)" required="yes" >}}
|
||||
|
||||
A list of valid callback URIs this client will redirect to. All other callbacks will be considered unsafe. The URIs are
|
||||
case-sensitive and they differ from application to application - the community has provided
|
||||
[a list of URL´s for common applications](../../../integration/openid-connect/introduction.md).
|
||||
|
||||
Some restrictions that have been placed on clients and
|
||||
their redirect URIs are as follows:
|
||||
|
||||
1. If a client attempts to authorize with Authelia and its redirect URI is not listed in the client configuration the
|
||||
attempt to authorize will fail and an error will be generated.
|
||||
2. The redirect URIs are case-sensitive.
|
||||
3. The URI must include a scheme and that scheme must be one of `http` or `https`.
|
||||
|
||||
### audience
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of audiences this client is allowed to request.
|
||||
|
||||
### scopes
|
||||
|
||||
{{< confkey type="list(string)" default="openid, groups, profile, email" required="no" >}}
|
||||
|
||||
A list of scopes to allow this client to consume. See
|
||||
[scope definitions](../../../integration/openid-connect/introduction.md#scope-definitions) for more information. The
|
||||
documentation for the application you are trying to configure [OpenID Connect 1.0] for will likely have a list of scopes
|
||||
or claims required which can be matched with the above guide.
|
||||
|
||||
### grant_types
|
||||
|
||||
{{< confkey type="list(string)" default="authorization_code" required="no" >}}
|
||||
|
||||
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
|
||||
|
||||
The list of grant types this client is permitted to use in order to obtain access to the relevant tokens.
|
||||
|
||||
See the [Grant Types](../../../integration/openid-connect/introduction.md#grant-types) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../../integration/openid-connect/introduction.md#grant-types) for more information.
|
||||
|
||||
### response_types
|
||||
|
||||
{{< confkey type="list(string)" default="code" required="no" >}}
|
||||
|
||||
*__Security Note:__ It is recommended that only the `code` response type (i.e. the default) is used. The other response
|
||||
types are not as secure as this response type.*
|
||||
|
||||
A list of response types this client supports. If a response type not in this list is requested by a client then an
|
||||
error will be returned to the client. The response type indicates the types of values that are returned to the client.
|
||||
|
||||
See the [Response Types](../../../integration/openid-connect/introduction.md#response-types) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../../integration/openid-connect/introduction.md#response-types) for more information.
|
||||
|
||||
### response_modes
|
||||
|
||||
{{< confkey type="list(string)" default="form_post, query" required="no" >}}
|
||||
|
||||
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
|
||||
|
||||
A list of response modes this client supports. If a response mode not in this list is requested by a client then an
|
||||
error will be returned to the client. The response mode controls how the response type is returned to the client.
|
||||
|
||||
See the [Response Modes](../../../integration/openid-connect/introduction.md#response-modes) section of the
|
||||
[OpenID Connect 1.0 Integration Guide](../../../integration/openid-connect/introduction.md#response-modes) for more
|
||||
information.
|
||||
|
||||
The default values are based on the [response_types](#responsetypes) values. When the [response_types](#responsetypes)
|
||||
values include the `code` type then the `query` response mode will be included. When any other type is included the
|
||||
`fragment` response mode will be included. It's important to note at this time we do not support the `none` response
|
||||
type, but when it is supported it will include the `query` response mode.
|
||||
|
||||
### authorization_policy
|
||||
|
||||
{{< confkey type="string" default="two_factor" required="no" >}}
|
||||
|
||||
The authorization policy for this client: either `one_factor` or `two_factor`.
|
||||
|
||||
### consent_mode
|
||||
|
||||
{{< confkey type="string" default="auto" required="no" >}}
|
||||
|
||||
*__Important Note:__ the `implicit` consent mode is not technically part of the specification. It theoretically could be
|
||||
misused in certain conditions specifically with the public client type or when the client credentials (i.e. client
|
||||
secret) has been exposed to an attacker. For these reasons this mode is discouraged.*
|
||||
|
||||
Configures the consent mode. The following table describes the different modes:
|
||||
|
||||
| Value | Description |
|
||||
|:--------------:|:----------------------------------------------------------------------------------------------------------------------------------------------:|
|
||||
| auto | Automatically determined (default). Uses `explicit` unless [pre_configured_consent_duration] is specified in which case uses `pre-configured`. |
|
||||
| explicit | Requires the user provide unique explicit consent for every authorization. |
|
||||
| implicit | Automatically assumes consent for every authorization, never asking the user if they wish to give consent. |
|
||||
| pre-configured | Allows the end-user to remember their consent for the [pre_configured_consent_duration]. |
|
||||
|
||||
[pre_configured_consent_duration]: #preconfiguredconsentduration
|
||||
|
||||
### pre_configured_consent_duration
|
||||
|
||||
{{< confkey type="duration" default="1w" required="no" >}}
|
||||
|
||||
*__Note:__ This setting uses the [duration notation format](../../prologue/common.md#duration-notation-format). Please see
|
||||
the [common options](../../prologue/common.md#duration-notation-format) documentation for information on this format.*
|
||||
|
||||
Specifying this in the configuration without a consent [consent_mode] enables the `pre-configured` mode. If this is
|
||||
specified as well as the [consent_mode] then it only has an effect if the [consent_mode] is `pre-configured` or `auto`.
|
||||
|
||||
The period of time dictates how long a users choice to remember the pre-configured consent lasts.
|
||||
|
||||
Pre-configured consents are only valid if the subject, client id are exactly the same and the requested scopes/audience
|
||||
match exactly with the granted scopes/audience.
|
||||
|
||||
[consent_mode]: #consentmode
|
||||
|
||||
### enforce_par
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
This configuration option enforces the use of a [Pushed Authorization Requests] flow for this registered client.
|
||||
To enforce it for all clients see the global [pushed_authorizations enforce](provider.md#enforce) provider configuration
|
||||
option.
|
||||
|
||||
### enforce_pkce
|
||||
|
||||
{{< confkey type="bool" default="false" required="no" >}}
|
||||
|
||||
This configuration option enforces the use of [PKCE] for this registered client. To enforce it for all clients see the
|
||||
global [enforce_pkce](provider.md#enforcepkce) provider configuration option.
|
||||
|
||||
### pkce_challenge_method
|
||||
|
||||
{{< confkey type="string" default="" required="no" >}}
|
||||
|
||||
This setting enforces the use of the specified [PKCE] challenge method for this individual client. This setting also
|
||||
effectively enables the [enforce_pkce](#enforcepkce) option for this client.
|
||||
|
||||
Valid values are an empty string, `plain`, or `S256`. It should be noted that `S256` is strongly recommended if the
|
||||
relying party supports it.
|
||||
|
||||
### token_endpoint_auth_method
|
||||
|
||||
{{< confkey type="string" default="" required="no" >}}
|
||||
|
||||
The registered client authentication mechanism used by this client for the [Token Endpoint]. If no method is defined
|
||||
the confidential client type will accept any supported method. The public client type defaults to `none` as this
|
||||
is required by the specification. This may be required as a breaking change in future versions.
|
||||
Supported values are `client_secret_basic`, `client_secret_post`, `client_secret_jwt`, `private_key_jwt`, and `none`.
|
||||
|
||||
See the [integration guide](../../../integration/openid-connect/introduction.md#client-authentication-method) for
|
||||
more information.
|
||||
|
||||
### token_endpoint_auth_signing_alg
|
||||
|
||||
{{< confkey type="string" default="RS256" required="no" >}}
|
||||
|
||||
The JWT signing algorithm accepted when the [token_endpoint_auth_method](#tokenendpointauthmethod) is configured as
|
||||
`client_secret_jwt` or `private_key_jwt`.
|
||||
|
||||
See the request object section of the [integration guide](../../../integration/openid-connect/introduction.md#request-object)
|
||||
for more information including the algorithm column for supported values.
|
||||
|
||||
It's recommended that you specifically configure this when the following options are configured to specific values
|
||||
otherwise we assume the default value:
|
||||
|
||||
| Configuration Option | Value | Default |
|
||||
|:----------------------------------------------------------:|:-------------------:|:-------:|
|
||||
| [token_endpoint_auth_method](#tokenendpointauthsigningalg) | `private_key_jwt` | `RS256` |
|
||||
| [token_endpoint_auth_method](#tokenendpointauthsigningalg) | `client_secret_jwt` | `HS256` |
|
||||
|
||||
### request_object_signing_alg
|
||||
|
||||
{{< confkey type="string" default="RSA256" required="no" >}}
|
||||
|
||||
The JWT signing algorithm accepted for request objects.
|
||||
|
||||
See the request object section of the [integration guide](../../../integration/openid-connect/introduction.md#request-object)
|
||||
for more information including the algorithm column for supported values.
|
||||
|
||||
### id_token_signing_alg
|
||||
|
||||
{{< confkey type="string" default="RS256" required="no" >}}
|
||||
|
||||
The algorithm used to sign the ID Tokens in the token responses.
|
||||
|
||||
See the response object section of the [integration guide](../../../integration/openid-connect/introduction.md#response-object)
|
||||
for more information including the algorithm column for supported values. In addition to the values listed we also
|
||||
support `none` as a value for this endpoint.
|
||||
|
||||
### userinfo_signing_alg
|
||||
|
||||
{{< confkey type="string" default="none" required="no" >}}
|
||||
|
||||
The algorithm used to sign the userinfo endpoint responses.
|
||||
|
||||
See the response object section of the [integration guide](../../../integration/openid-connect/introduction.md#response-object)
|
||||
for more information including the algorithm column for supported values. In addition to the values listed we also
|
||||
support `none` as a value for this endpoint.
|
||||
|
||||
### public_keys
|
||||
|
||||
This section configures the trusted JSON Web Keys or JWKS for this registered client. This can either be static values
|
||||
(recommended) or a URI using the `https` scheme. This section is situational required. These are used to validate the
|
||||
[JWT] assertions from clients.
|
||||
|
||||
Required when the following options are configured:
|
||||
|
||||
- [request_object_signing_alg](#requestobjectsigningalg)
|
||||
- [token_endpoint_auth_signing_alg](#tokenendpointauthsigningalg)
|
||||
|
||||
Required when the following options are configured to specific values:
|
||||
|
||||
- [token_endpoint_auth_method](#tokenendpointauthsigningalg): `private_key_jwt`
|
||||
|
||||
#### uri
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The fully qualified, `https` scheme, and appropriately signed URI for the JWKS endpoint that implements
|
||||
[RFC7517 Section 5](https://datatracker.ietf.org/doc/html/rfc7517#section-5). Must not be configured at the same time
|
||||
as [values](#values). It's recommended that you do not configure this option, but statically configure [values](#values)
|
||||
instead.
|
||||
|
||||
*__Important Note:__ the URL given in this value MUST be resolvable by Authelia and MUST present a certificate signed by
|
||||
a certificate trusted by your environment. It is beyond our intentions to support anything other than this.*
|
||||
|
||||
#### values
|
||||
|
||||
{{< confkey type="list(object)" required="situational" >}}
|
||||
|
||||
A list of static keys.
|
||||
|
||||
##### key_id
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The Key ID used to match the request object's JWT header `kid` value against.
|
||||
|
||||
##### key
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The public key portion of the JSON Web Key
|
||||
|
||||
The public key the clients use to sign/encrypt the [OpenID Connect 1.0] asserted [JWT]'s. The key is generated by the
|
||||
client application or the administrator of the client application.
|
||||
|
||||
The key *__MUST__*:
|
||||
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be either:
|
||||
* An RSA public key:
|
||||
* With a key size of at least 2048 bits.
|
||||
* An ECDSA public key with one of:
|
||||
* A P-256 elliptical curve.
|
||||
* A P-384 elliptical curve.
|
||||
* A P-512 elliptical curve.
|
||||
|
||||
If the [issuer_certificate_chain](#issuercertificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
|
||||
## Integration
|
||||
|
||||
To integrate Authelia's [OpenID Connect 1.0] implementation with a relying party please see the
|
||||
[integration docs](../../../integration/openid-connect/introduction.md).
|
||||
|
||||
[token lifespan]: https://docs.apigee.com/api-platform/antipatterns/oauth-long-expiration
|
||||
[OpenID Connect 1.0]: https://openid.net/connect/
|
||||
[Token Endpoint]: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||
[JWT]: https://datatracker.ietf.org/doc/html/rfc7519
|
||||
[RFC6234]: https://datatracker.ietf.org/doc/html/rfc6234
|
||||
[RFC4648]: https://datatracker.ietf.org/doc/html/rfc4648
|
||||
[RFC7468]: https://datatracker.ietf.org/doc/html/rfc7468
|
||||
[RFC6749 Section 2.1]: https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
|
||||
[PKCE]: https://datatracker.ietf.org/doc/html/rfc7636
|
||||
[Authorization Code Flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
||||
[Subject Identifier Type]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
||||
[Pairwise Identifier Algorithm]: https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg
|
||||
[Pushed Authorization Requests]: https://datatracker.ietf.org/doc/html/rfc9126
|
||||
|
|
@ -0,0 +1,428 @@
|
|||
---
|
||||
title: "OpenID Connect 1.0 Provider"
|
||||
description: "OpenID Connect 1.0 Provider Configuration"
|
||||
lead: "Authelia can operate as an OpenID Connect 1.0 Provider. This section describes how to configure this."
|
||||
date: 2023-05-08T13:38:08+10:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
configuration:
|
||||
parent: "openid-connect"
|
||||
weight: 190200
|
||||
toc: true
|
||||
aliases:
|
||||
- /c/oidc
|
||||
- /docs/configuration/identity-providers/oidc.html
|
||||
---
|
||||
|
||||
__Authelia__ currently supports the [OpenID Connect 1.0] Provider role as an open
|
||||
[__beta__](../../../roadmap/active/openid-connect.md) feature. We currently do not support the [OpenID Connect 1.0] Relying
|
||||
Party role. This means other applications that implement the [OpenID Connect 1.0] Relying Party role can use Authelia as
|
||||
an [OpenID Connect 1.0] Provider similar to how you may use social media or development platforms for login.
|
||||
|
||||
The [OpenID Connect 1.0] Relying Party role is the role which allows an application to use GitHub, Google, or other
|
||||
[OpenID Connect 1.0] Providers for authentication and authorization. We do not intend to support this functionality at
|
||||
this moment in time.
|
||||
|
||||
This section covers the [OpenID Connect 1.0] Provider configuration. For information on configuring individual
|
||||
registered clients see the [OpenID Connect 1.0 Clients](clients.md) documentation.
|
||||
|
||||
More information about the beta can be found in the [roadmap](../../../roadmap/active/openid-connect.md) and in the
|
||||
[integration](../../../integration/openid-connect/introduction.md) documentation.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following snippet provides a configuration example for the [OpenID Connect 1.0] Provider. This is not
|
||||
intended for production use it's used to provide context and an indentation example.
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
hmac_secret: this_is_a_secret_abc123abc123abc
|
||||
issuer_private_keys:
|
||||
- key_id: example
|
||||
algorithm: RS256
|
||||
use: sig
|
||||
key: |
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MEgCQQDAwV26ZA1lodtOQxNrJ491gWT+VzFum9IeZ+WTmMypYWyW1CzXKwsvTHDz
|
||||
9ec+jserR3EMQ0Rr24lj13FL1ib5AgMBAAE=
|
||||
-----END RSA PUBLIC KEY----
|
||||
certificate_chain: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
-----END CERTIFICATE-----
|
||||
issuer_private_key: |
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MEgCQQDAwV26ZA1lodtOQxNrJ491gWT+VzFum9IeZ+WTmMypYWyW1CzXKwsvTHDz
|
||||
9ec+jserR3EMQ0Rr24lj13FL1ib5AgMBAAE=
|
||||
-----END RSA PUBLIC KEY----
|
||||
issuer_certificate_chain: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
-----END CERTIFICATE-----
|
||||
access_token_lifespan: 1h
|
||||
authorize_code_lifespan: 1m
|
||||
id_token_lifespan: 1h
|
||||
refresh_token_lifespan: 90m
|
||||
enable_client_debug_messages: false
|
||||
minimum_parameter_entropy: 8
|
||||
enforce_pkce: public_clients_only
|
||||
enable_pkce_plain_challenge: false
|
||||
pushed_authorizations:
|
||||
enforce: false
|
||||
context_lifespan: 5m
|
||||
cors:
|
||||
endpoints:
|
||||
- authorization
|
||||
- token
|
||||
- revocation
|
||||
- introspection
|
||||
allowed_origins:
|
||||
- https://example.com
|
||||
allowed_origins_from_client_redirect_uris: false
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### hmac_secret
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
*__Important Note:__ This can also be defined using a [secret](../../methods/secrets.md) which is __strongly recommended__
|
||||
especially for containerized deployments.*
|
||||
|
||||
The HMAC secret used to sign the [JWT]'s. The provided string is hashed to a SHA256 ([RFC6234]) byte string for the
|
||||
purpose of meeting the required format.
|
||||
|
||||
It's __strongly recommended__ this is a
|
||||
[Random Alphanumeric String](../../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string)
|
||||
with 64 or more characters.
|
||||
|
||||
### issuer_private_keys
|
||||
|
||||
The key *__MUST__*:
|
||||
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be either:
|
||||
* An RSA public key:
|
||||
* With a key size of at least 2048 bits.
|
||||
* An ECDSA public key with one of:
|
||||
* A P-256 elliptical curve.
|
||||
* A P-384 elliptical curve.
|
||||
* A P-512 elliptical curve.
|
||||
|
||||
### issuer_private_keys
|
||||
|
||||
{{< confkey type="list(object" required="no" >}}
|
||||
|
||||
The list of JWKS instead of or in addition to the [issuer_private_key](#issuerprivatekey) and
|
||||
[issuer_certificate_chain](#issuercertificatechain). Can also accept ECDSA Private Key's and Certificates.
|
||||
|
||||
#### key_id
|
||||
|
||||
{{< confkey type="string" default="<thumbprint of public key>" required="no" >}}
|
||||
|
||||
Completely optional, and generally discouraged unless there is a collision between the automatically generated key id's.
|
||||
If provided must be a unique string with 7 or less alphanumeric characters.
|
||||
|
||||
This value is the first 7 characters of the public key thumbprint (SHA1) encoded into hexadecimal.
|
||||
|
||||
#### algorithm
|
||||
|
||||
{{< confkey type="string" default="RS256" required="no" >}}
|
||||
|
||||
The algorithm for this key. This value must be unique. It's automatically detected based on the type of key.
|
||||
|
||||
See the response object table in the [integration guide](../../../integration/openid-connect/introduction.md#response-object)
|
||||
including the algorithm column for the supported values and the key type column for the default algorithm value.
|
||||
|
||||
#### use
|
||||
|
||||
{{< confkey type="string" default="sig" required="no" >}}
|
||||
|
||||
The key usage. Defaults to `sig` which is the only available option at this time.
|
||||
|
||||
#### key
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
The private key associated with this key entry.
|
||||
|
||||
The private key used to sign/encrypt the [OpenID Connect 1.0] issued [JWT]'s. The key must be generated by the administrator
|
||||
and can be done by following the
|
||||
[Generating an RSA Keypair](../../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
|
||||
The private key *__MUST__*:
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be one of:
|
||||
* An RSA key with a key size of at least 2048 bits.
|
||||
* An ECDSA private key with one of the P-256, P-384, or P-521 elliptical curves.
|
||||
|
||||
If the [certificate_chain](#certificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
#### certificate_chain
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The certificate chain/bundle to be used with the [key](#key) DER base64 ([RFC4648])
|
||||
encoded PEM format used to sign/encrypt the [OpenID Connect 1.0] [JWT]'s. When configured it enables the [x5c] and [x5t]
|
||||
JSON key's in the JWKs [Discoverable Endpoint](../../../integration/openid-connect/introduction.md#discoverable-endpoints)
|
||||
as per [RFC7517].
|
||||
|
||||
[RFC7517]: https://datatracker.ietf.org/doc/html/rfc7517
|
||||
[x5c]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.7
|
||||
[x5t]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.8
|
||||
|
||||
The first certificate in the chain must have the public key for the [key](#key), each certificate in the chain must be
|
||||
valid for the current date, and each certificate in the chain should be signed by the certificate immediately following
|
||||
it if present.
|
||||
|
||||
### issuer_private_key
|
||||
|
||||
{{< confkey type="string" required="yes" >}}
|
||||
|
||||
*__Important Note:__ This can also be defined using a [secret](../../methods/secrets.md) which is __strongly recommended__
|
||||
especially for containerized deployments.*
|
||||
|
||||
The private key used to sign/encrypt the [OpenID Connect 1.0] issued [JWT]'s. The key must be generated by the administrator
|
||||
and can be done by following the
|
||||
[Generating an RSA Keypair](../../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
|
||||
This private key is automatically appended to the [issuer_private_keys](#issuerprivatekeys) and assumed to be for the
|
||||
RS256 algorithm. As such no other key in this list should be RS256 if this is configured.
|
||||
|
||||
The issuer private key *__MUST__*:
|
||||
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be an RSA private key:
|
||||
* With a key size of at least 2048 bits.
|
||||
|
||||
If the [issuer_certificate_chain](#issuercertificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
### issuer_certificate_chain
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The certificate chain/bundle to be used with the [issuer_private_key](#issuer_private_key) DER base64 ([RFC4648])
|
||||
encoded PEM format used to sign/encrypt the [OpenID Connect 1.0] [JWT]'s. When configured it enables the [x5c] and [x5t]
|
||||
JSON key's in the JWKs [Discoverable Endpoint](../../../integration/openid-connect/introduction.md#discoverable-endpoints)
|
||||
as per [RFC7517].
|
||||
|
||||
[RFC7517]: https://datatracker.ietf.org/doc/html/rfc7517
|
||||
[x5c]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.7
|
||||
[x5t]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.8
|
||||
|
||||
The first certificate in the chain must have the public key for the [issuer_private_key](#issuerprivatekey), each
|
||||
certificate in the chain must be valid for the current date, and each certificate in the chain should be signed by the
|
||||
certificate immediately following it if present.
|
||||
|
||||
### access_token_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1h" required="no" >}}
|
||||
|
||||
The maximum lifetime of an access token. It's generally recommended keeping this short similar to the default.
|
||||
For more information read these docs about [token lifespan].
|
||||
|
||||
### authorize_code_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1m" required="no" >}}
|
||||
|
||||
The maximum lifetime of an authorize code. This can be rather short, as the authorize code should only be needed to
|
||||
obtain the other token types. For more information read these docs about [token lifespan].
|
||||
|
||||
### id_token_lifespan
|
||||
|
||||
{{< confkey type="duration" default="1h" required="no" >}}
|
||||
|
||||
The maximum lifetime of an ID token. For more information read these docs about [token lifespan].
|
||||
|
||||
### refresh_token_lifespan
|
||||
|
||||
{{< confkey type="string" default="90m" required="no" >}}
|
||||
|
||||
The maximum lifetime of a refresh token. The
|
||||
refresh token can be used to obtain new refresh tokens as well as access tokens or id tokens with an
|
||||
up-to-date expiration. For more information read these docs about [token lifespan].
|
||||
|
||||
A good starting point is 50% more or 30 minutes more (which ever is less) time than the highest lifespan out of the
|
||||
[access token lifespan](#accesstokenlifespan), the [authorize code lifespan](#authorizecodelifespan), and the
|
||||
[id token lifespan](#idtokenlifespan). For instance the default for all of these is 60 minutes, so the default refresh
|
||||
token lifespan is 90 minutes.
|
||||
|
||||
### enable_client_debug_messages
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Allows additional debug messages to be sent to the clients.
|
||||
|
||||
### minimum_parameter_entropy
|
||||
|
||||
{{< confkey type="integer" default="8" required="no" >}}
|
||||
|
||||
This controls the minimum length of the `nonce` and `state` parameters.
|
||||
|
||||
*__Security Notice:__* Changing this value is generally discouraged, reducing it from the default can theoretically
|
||||
make certain scenarios less secure. It is highly encouraged that if your OpenID Connect RP does not send these
|
||||
parameters or sends parameters with a lower length than the default that they implement a change rather than changing
|
||||
this value.
|
||||
|
||||
### enforce_pkce
|
||||
|
||||
{{< confkey type="string" default="public_clients_only" required="no" >}}
|
||||
|
||||
[Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636) enforcement policy: if specified, must be
|
||||
either `never`, `public_clients_only` or `always`.
|
||||
|
||||
If set to `public_clients_only` (default), [PKCE] will be required for public clients using the
|
||||
[Authorization Code Flow].
|
||||
|
||||
When set to `always`, [PKCE] will be required for all clients using the Authorization Code flow.
|
||||
|
||||
*__Security Notice:__* Changing this value to `never` is generally discouraged, reducing it from the default can
|
||||
theoretically make certain client-side applications (mobile applications, SPA) vulnerable to CSRF and authorization code
|
||||
interception attacks.
|
||||
|
||||
### enable_pkce_plain_challenge
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Allows [PKCE] `plain` challenges when set to `true`.
|
||||
|
||||
*__Security Notice:__* Changing this value is generally discouraged. Applications should use the `S256` [PKCE] challenge
|
||||
method instead.
|
||||
|
||||
### pushed_authorizations
|
||||
|
||||
Controls the behaviour of [Pushed Authorization Requests].
|
||||
|
||||
#### enforce
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
When enabled all authorization requests must use the [Pushed Authorization Requests] flow.
|
||||
|
||||
#### context_lifespan
|
||||
|
||||
{{< confkey type="duration" default="5m" required="no" >}}
|
||||
|
||||
The maximum amount of time between the [Pushed Authorization Requests] flow being initiated and the generated
|
||||
`request_uri` being utilized by a client.
|
||||
|
||||
### cors
|
||||
|
||||
Some [OpenID Connect 1.0] Endpoints need to allow cross-origin resource sharing, however some are optional. This section allows
|
||||
you to configure the optional parts. We reply with CORS headers when the request includes the Origin header.
|
||||
|
||||
#### endpoints
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of endpoints to configure with cross-origin resource sharing headers. It is recommended that the `userinfo`
|
||||
option is at least in this list. The potential endpoints which this can be enabled on are as follows:
|
||||
|
||||
* authorization
|
||||
* pushed-authorization-request
|
||||
* token
|
||||
* revocation
|
||||
* introspection
|
||||
* userinfo
|
||||
|
||||
#### allowed_origins
|
||||
|
||||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
A list of permitted origins.
|
||||
|
||||
Any origin with https is permitted unless this option is configured or the
|
||||
[allowed_origins_from_client_redirect_uris](#allowedoriginsfromclientredirecturis) option is enabled. This means
|
||||
you must configure this option manually if you want http endpoints to be permitted to make cross-origin requests to the
|
||||
[OpenID Connect 1.0] endpoints, however this is not recommended.
|
||||
|
||||
Origins must only have the scheme, hostname and port, they may not have a trailing slash or path.
|
||||
|
||||
In addition to an Origin URI, you may specify the wildcard origin in the allowed_origins. It MUST be specified by itself
|
||||
and the [allowed_origins_from_client_redirect_uris](#allowedoriginsfromclientredirecturis) MUST NOT be enabled. The
|
||||
wildcard origin is denoted as `*`. Examples:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
cors:
|
||||
allowed_origins: "*"
|
||||
```
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
#### allowed_origins_from_client_redirect_uris
|
||||
|
||||
{{< confkey type="boolean" default="false" required="no" >}}
|
||||
|
||||
Automatically adds the origin portion of all redirect URI's on all clients to the list of
|
||||
[allowed_origins](#allowed_origins), provided they have the scheme http or https and do not have the hostname of
|
||||
localhost.
|
||||
|
||||
### clients
|
||||
|
||||
See the [OpenID Connect 1.0 Registered Clients](clients.md) documentation for configuring clients.
|
||||
|
||||
## Integration
|
||||
|
||||
To integrate Authelia's [OpenID Connect 1.0] implementation with a relying party please see the
|
||||
[integration docs](../../integration/openid-connect/introduction.md).
|
||||
|
||||
[token lifespan]: https://docs.apigee.com/api-platform/antipatterns/oauth-long-expiration
|
||||
[OpenID Connect 1.0]: https://openid.net/connect/
|
||||
[Token Endpoint]: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||
[JWT]: https://datatracker.ietf.org/doc/html/rfc7519
|
||||
[RFC6234]: https://datatracker.ietf.org/doc/html/rfc6234
|
||||
[RFC4648]: https://datatracker.ietf.org/doc/html/rfc4648
|
||||
[RFC7468]: https://datatracker.ietf.org/doc/html/rfc7468
|
||||
[RFC6749 Section 2.1]: https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
|
||||
[PKCE]: https://datatracker.ietf.org/doc/html/rfc7636
|
||||
[Authorization Code Flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
||||
[Subject Identifier Type]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
||||
[Pairwise Identifier Algorithm]: https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg
|
||||
[Pushed Authorization Requests]: https://datatracker.ietf.org/doc/html/rfc9126
|
|
@ -77,9 +77,9 @@ other configuration using the environment but instead of loading a file the valu
|
|||
[authentication_backend.ldap.password]: ../first-factor/ldap.md#password
|
||||
[authentication_backend.ldap.tls.certificate_chain]: ../first-factor/ldap.md#tls
|
||||
[authentication_backend.ldap.tls.private_key]: ../first-factor/ldap.md#tls
|
||||
[identity_providers.oidc.issuer_certificate_chain]: ../identity-providers/open-id-connect.md#issuercertificatechain
|
||||
[identity_providers.oidc.issuer_private_key]: ../identity-providers/open-id-connect.md#issuerprivatekey
|
||||
[identity_providers.oidc.hmac_secret]: ../identity-providers/open-id-connect.md#hmacsecret
|
||||
[identity_providers.oidc.issuer_certificate_chain]: ../identity-providers/openid-connect.md#issuercertificatechain
|
||||
[identity_providers.oidc.issuer_private_key]: ../identity-providers/openid-connect.md#issuerprivatekey
|
||||
[identity_providers.oidc.hmac_secret]: ../identity-providers/openid-connect.md#hmacsecret
|
||||
|
||||
|
||||
## Secrets in configuration file
|
||||
|
|
|
@ -44,7 +44,7 @@ accepted is recorded and checked in the browser
|
|||
If the user has not accepted the policy they should not be able to interact with the Authelia UI via normal means.
|
||||
|
||||
Administrators who are required to abide by the [GDPR] or other privacy laws should be advised that
|
||||
[OpenID Connect 1.0](../identity-providers/open-id-connect.md) clients configured with the `implicit` consent mode are
|
||||
[OpenID Connect 1.0](../identity-providers/openid-connect.md) clients configured with the `implicit` consent mode are
|
||||
unlikely to trigger the display of the Authelia UI if the user is already authenticated.
|
||||
|
||||
We wont be adding checks like this to the `implicit` consent mode when that mode in particular is unlikely to be
|
||||
|
|
|
@ -53,7 +53,7 @@ openid-groups-claim-type: groups
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with
|
||||
[Apache Guacamole] which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -78,7 +78,7 @@ identity_providers:
|
|||
- 'id_token'
|
||||
grant_types:
|
||||
- 'implicit'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -56,7 +56,7 @@ requestedScopes:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Argo CD]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Argo CD]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -77,7 +77,7 @@ identity_providers:
|
|||
- 'groups'
|
||||
- 'email'
|
||||
- 'profile'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
- id: 'argocd-cli'
|
||||
description: 'Argo CD (CLI)'
|
||||
public: true
|
||||
|
@ -90,7 +90,7 @@ identity_providers:
|
|||
- 'email'
|
||||
- 'profile'
|
||||
- 'offline_access'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -58,7 +58,7 @@ To configure [BookStack] to utilize Authelia as an [OpenID Connect 1.0] Provider
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [BookStack]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [BookStack]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -78,7 +78,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -66,7 +66,7 @@ To configure [Cloudflare Zero Trust] to utilize Authelia as an [OpenID Connect 1
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Cloudflare]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Cloudflare]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -86,7 +86,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -67,7 +67,7 @@ descriptions.
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Firezone] which
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Firezone] which
|
||||
will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -89,7 +89,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'email'
|
||||
- 'profile'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -77,7 +77,7 @@ descriptions.
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Gitea] which
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Gitea] which
|
||||
will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -97,7 +97,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'email'
|
||||
- 'profile'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -69,7 +69,7 @@ gitlab_rails['omniauth_providers'] = [
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [GitLab]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [GitLab]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -90,7 +90,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -87,7 +87,7 @@ Configure the following environment variables:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Grafana]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Grafana]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -108,7 +108,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -60,7 +60,7 @@ To configure [Harbor] to utilize Authelia as an [OpenID Connect 1.0] Provider:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Harbor]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Harbor]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -81,7 +81,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -43,7 +43,7 @@ To configure [HashiCorp Vault] to utilize Authelia as an [OpenID Connect 1.0] Pr
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [HashiCorp Vault]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [HashiCorp Vault]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -65,7 +65,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -18,8 +18,10 @@ Authelia can act as an [OpenID Connect 1.0] Provider as part of an open beta. Th
|
|||
specifics that can be used for integrating Authelia with an [OpenID Connect 1.0] Relying Party, as well as specific
|
||||
documentation for some [OpenID Connect 1.0] Relying Party implementations.
|
||||
|
||||
See the [configuration documentation](../../configuration/identity-providers/open-id-connect.md) for information on how
|
||||
to configure the Authelia [OpenID Connect 1.0] Provider.
|
||||
See the [OpenID Connect 1.0 Provider](../../configuration/identity-providers/openid-connect/provider.md) and
|
||||
[OpenID Connect 1.0 Clients](../../configuration/identity-providers/openid-connect/clients.md) configuration guides for
|
||||
information on how to configure the Authelia [OpenID Connect 1.0] Provider (note the clients guide is for configuring
|
||||
the registered clients in the provider).
|
||||
|
||||
This page is intended as an integration reference point for any implementers who wish to integrate an
|
||||
[OpenID Connect 1.0] Relying Party (client application) either as a developer or user of the third party Reyling Party.
|
||||
|
@ -124,6 +126,7 @@ Authelia's response objects can have the following signature algorithms:
|
|||
|
||||
### Request Object
|
||||
|
||||
Authelia accepts a wide variety of request object types.
|
||||
|
||||
| Algorithm | Key Type | Hashing Algorithm | Use | Notes |
|
||||
|:---------:|:------------------:|:-----------------:|:---------:|:--------------------------------------------------:|
|
||||
|
@ -131,6 +134,15 @@ Authelia's response objects can have the following signature algorithms:
|
|||
| HS256 | HMAC Shared Secret | SHA-256 | Signature | [Client Authentication Method] `client_secret_jwt` |
|
||||
| HS384 | HMAC Shared Secret | SHA-384 | Signature | [Client Authentication Method] `client_secret_jwt` |
|
||||
| HS512 | HMAC Shared Secret | SHA-512 | Signature | [Client Authentication Method] `client_secret_jwt` |
|
||||
| RS256 | RSA | SHA-256 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| RS384 | RSA | SHA-384 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| RS512 | RSA | SHA-512 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| ES256 | ECDSA P-256 | SHA-256 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| ES384 | ECDSA P-384 | SHA-384 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| ES512 | ECDSA P-521 | SHA-512 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| PS256 | RSA (MFG1) | SHA-256 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| PS384 | RSA (MFG1) | SHA-384 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
| PS512 | RSA (MFG1) | SHA-512 | Signature | [Client Authentication Method] `private_key_jwt` |
|
||||
|
||||
[Client Authentication Method]: #client-authentication-method
|
||||
|
||||
|
@ -208,7 +220,7 @@ specification and the [OAuth 2.0 - Client Types] specification for more informat
|
|||
| Secret via HTTP Basic Auth Scheme | `client_secret_basic` | `confidential` | N/A | N/A |
|
||||
| Secret via HTTP POST Body | `client_secret_post` | `confidential` | N/A | N/A |
|
||||
| JWT (signed by secret) | `client_secret_jwt` | `confidential` | N/A | `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
|
||||
| JWT (signed by private key) | `private_key_jwt` | Not Supported | N/A | `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
|
||||
| JWT (signed by private key) | `private_key_jwt` | `confidential` | N/A | `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
|
||||
| [OAuth 2.0 Mutual-TLS] | `tls_client_auth` | Not Supported | N/A | N/A |
|
||||
| [OAuth 2.0 Mutual-TLS] (Self Signed) | `self_signed_tls_client_auth` | Not Supported | N/A | N/A |
|
||||
| No Authentication | `none` | `public` | `public` | N/A |
|
||||
|
@ -243,7 +255,7 @@ Below is a list of the potential values we place in the [Claim] and their meanin
|
|||
## User Information Signing Algorithm
|
||||
|
||||
The following table describes the response from the [UserInfo] endpoint depending on the
|
||||
[userinfo_signing_algorithm](../../configuration/identity-providers/open-id-connect.md#userinfosigningalgorithm).
|
||||
[userinfo_signing_alg](../../configuration/identity-providers/openid-connect/clients.md#userinfosigningalg).
|
||||
|
||||
| Signing Algorithm | Encoding | Content Type |
|
||||
|:-----------------:|:------------:|:-----------------------------------:|
|
||||
|
|
|
@ -80,7 +80,7 @@ identity_providers:
|
|||
- 'groups'
|
||||
- 'email'
|
||||
consent_mode: 'implicit'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -65,7 +65,7 @@ spring:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Komga]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Komga]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -87,7 +87,7 @@ identity_providers:
|
|||
- 'email'
|
||||
grant_types:
|
||||
- 'authorization_code'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -63,7 +63,7 @@ To configure [MinIO] to utilize Authelia as an [OpenID Connect 1.0] Provider:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [MinIO]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [MinIO]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -84,7 +84,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'email'
|
||||
- 'groups'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -79,7 +79,7 @@ To configure [Misago] to utilize Authelia as an [OpenID Connect 1.0](https://www
|
|||
|
||||
### Authelia
|
||||
|
||||
The following YAML configuration is an example **Authelia** [client configuration](https://www.authelia.com/configuration/identity-providers/open-id-connect/#clients) for use with [Misago] which will operate with the above example:
|
||||
The following YAML configuration is an example **Authelia** [client configuration](https://www.authelia.com/configuration/identity-providers/openid-connect/#clients) for use with [Misago] which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
|
@ -104,7 +104,7 @@ identity_providers:
|
|||
- 'code'
|
||||
response_modes:
|
||||
- 'query'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
@ -86,7 +86,7 @@ $CONFIG = array (
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Nextcloud]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Nextcloud]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -107,7 +107,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'email'
|
||||
- 'groups'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -60,7 +60,7 @@ OIDC_SCOPES="openid offline_access profile email"
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Outline]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Outline]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -81,7 +81,7 @@ identity_providers:
|
|||
- 'offline_access'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -61,7 +61,7 @@ To configure [Portainer] to utilize Authelia as an [OpenID Connect 1.0] Provider
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Portainer]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Portainer]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -82,7 +82,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -65,7 +65,7 @@ To configure [Proxmox] to utilize Authelia as an [OpenID Connect 1.0] Provider:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Proxmox]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Proxmox]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -85,7 +85,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -69,7 +69,7 @@ OAUTH_ATTRIBUTE_MAP = {
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Seafile]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Seafile]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -89,7 +89,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -63,7 +63,7 @@ oidc_providers:
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Synapse]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Synapse]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -83,7 +83,7 @@ identity_providers:
|
|||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -65,7 +65,7 @@ To configure [Synology DSM] to utilize Authelia as an [OpenID Connect 1.0] Provi
|
|||
### Authelia
|
||||
|
||||
The following YAML configuration is an example __Authelia__
|
||||
[client configuration](../../../configuration/identity-providers/open-id-connect.md#clients) for use with [Synology DSM]
|
||||
[client configuration](../../../configuration/identity-providers/openid-connect/clients.md) for use with [Synology DSM]
|
||||
which will operate with the above example:
|
||||
|
||||
```yaml
|
||||
|
@ -86,7 +86,7 @@ identity_providers:
|
|||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
userinfo_signing_algorithm: 'none'
|
||||
userinfo_signing_alg: 'none'
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
|
|
@ -58,7 +58,7 @@ In addition this represents a bad user experience in some instances such as:
|
|||
* Users sometimes visit the `https://app.example.com/authelia` URL which doesn't automatically redirect the user to
|
||||
`https://app.example.com` (if they visit `https://app.example.com` then they'll be redirected to authenticate then
|
||||
redirected back to their original URL)
|
||||
* Administrators may wish to setup [OpenID Connect 1.0](../../configuration/identity-providers/open-id-connect.md) in
|
||||
* Administrators may wish to setup [OpenID Connect 1.0](../../configuration/identity-providers/openid-connect/provider.md) in
|
||||
which case it also doesn't represent a good user experience as the `issuer` will be
|
||||
`https://app.example.com/authelia` for example
|
||||
* Using the [SWAG] default configurations are more difficult to support as our specific familiarity is with our own
|
||||
|
|
|
@ -16,6 +16,6 @@ configure your applications to use Authelia as an [OpenID Connect 1.0 Provider](
|
|||
currently operate as an [OpenID Connect 1.0 Relying Party](https://openid.net/connect/). This like all single-sign on
|
||||
technologies requires support by the protected application.
|
||||
|
||||
See the [OpenID Connect 1.0 Configuration Guide](../../configuration/identity-providers/open-id-connect.md) and the
|
||||
See the [OpenID Connect 1.0 Provider Configuration Guide](../../configuration/identity-providers/openid-connect/provider.md), and the
|
||||
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md) for more information.
|
||||
|
||||
|
|
|
@ -115,8 +115,15 @@ Feature List:
|
|||
|
||||
{{< roadmap-status stage="in-progress" version="v4.38.0" >}}
|
||||
|
||||
* [OAuth 2.0 Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126)
|
||||
* [RFC9126: OAuth 2.0 Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126)
|
||||
* [RFC7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants](https://datatracker.ietf.org/doc/html/rfc7523):
|
||||
* Client Auth Method `client_secret_jwt`
|
||||
* Client Auth Method `private_key_jwt`
|
||||
* Per-Client [Proof Key Code Exchange (PKCE)] Policy
|
||||
* Multiple Issuer JWKs:
|
||||
* RS256, RS384, RS512
|
||||
* PS256, PS384, PS512
|
||||
* ES256, ES384, ES512
|
||||
|
||||
### Beta 7
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
{{ $faq := "../frequently-asked-questions/" }}{{ $config := "../../../configuration/identity-providers/open-id-connect.md" }}
|
||||
{{ $faq := "../frequently-asked-questions/" }}{{ $config := "../../../configuration/identity-providers/openid-connect/" }}
|
||||
{{- with .Get "faq" }}{{ $faq = . }}{{ end }}
|
||||
{{- with .Get "config" }}{{ $config = . }}{{ end }}
|
||||
### Common Notes
|
||||
|
@ -15,4 +15,6 @@
|
|||
guaranteed to be supported in the future. See the [Plaintext]({{ $faq }}#plaintext) guide for more
|
||||
information.
|
||||
3. The Configuration example for Authelia is only a portion of the required configuration and it should be used as a
|
||||
guide in conjunction with the standard [OpenID Connect 1.0 Configuration]({{ $config }}) guide.
|
||||
guide in conjunction with the standard
|
||||
[OpenID Connect 1.0 Provider Configuration]({{ printf "%s/provider.md" $config }}) and
|
||||
[OpenID Connect 1.0 Clients Configuration]({{ printf "%s/clients.md" $config }}) guides.
|
|
@ -4,7 +4,16 @@
|
|||
# Authelia Configuration #
|
||||
###############################################################################
|
||||
|
||||
## Note: the container by default expects to find this file at /config/configuration.yml.
|
||||
##
|
||||
## Notes:
|
||||
##
|
||||
## - the default location of this file is assumed to be configuration.yml unless otherwise noted
|
||||
## - when using docker the container expects this by default to be at /config/configuration.yml
|
||||
## - the default location where this file is loaded from can be overridden with the X_AUTHELIA_CONFIG environment var
|
||||
## - the comments in this configuration file are helpful but users should consult the official documentation on the
|
||||
## website at https://www.authelia.com/ or https://www.authelia.com/configuration/prologue/introduction/
|
||||
## - this configuration file template is not automatically updated
|
||||
##
|
||||
|
||||
## Certificates directory specifies where Authelia will load trusted certificates (public portion) from in addition to
|
||||
## the system certificates store.
|
||||
|
@ -357,73 +366,37 @@ authentication_backend:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## The distinguished name of the container searched for objects in the directory information tree.
|
||||
|
@ -485,7 +458,7 @@ authentication_backend:
|
|||
# permit_referrals: false
|
||||
|
||||
## The username and password of the admin user.
|
||||
# user: cn=admin,dc=example,dc=com
|
||||
# user: 'cn=admin,dc=example,dc=com'
|
||||
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# password: 'password'
|
||||
|
||||
|
@ -622,7 +595,7 @@ access_control:
|
|||
# networks:
|
||||
# - '10.10.0.0/16'
|
||||
# - '192.168.2.0/24'
|
||||
# - name: VPN
|
||||
# - name: 'VPN'
|
||||
# networks: '10.9.0.0/16'
|
||||
|
||||
# rules:
|
||||
|
@ -748,7 +721,8 @@ session:
|
|||
# expiration: '1h'
|
||||
|
||||
## The time before the cookie expires and the session is destroyed if remember me IS selected by the user. Setting
|
||||
## this value to -1 disables remember me for this session cookie domain.
|
||||
## this value to -1 disables remember me for this session cookie domain. If allowed and the user uses the remember
|
||||
## me checkbox this overrides the expiration option and disables the inactivity option.
|
||||
# remember_me: '1M'
|
||||
|
||||
## Cookie Session Domain default 'name' value.
|
||||
|
@ -816,73 +790,37 @@ session:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## The Redis HA configuration options.
|
||||
|
@ -997,73 +935,37 @@ regulation:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1116,73 +1018,37 @@ regulation:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1270,73 +1136,37 @@ notifier:
|
|||
## i.e. Mutual TLS.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||
## i.e. Mutual TLS.
|
||||
# private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
##
|
||||
|
@ -1354,80 +1184,88 @@ notifier:
|
|||
## HMAC Secret can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# hmac_secret: 'this_is_a_secret_abc123abc123abc'
|
||||
|
||||
## The issuer_certificate_chain is an optional PEM encoded certificate chain. It's used in conjunction with the
|
||||
## issuer_private_key to sign JWT's. All certificates in the chain must be within the validity period, and every
|
||||
## certificate included must be signed by the certificate immediately after it if provided.
|
||||
# issuer_certificate_chain: |
|
||||
## Issuer JWKS configures multiple JSON Web Keys. It's required that at least one of these is RS256 or the
|
||||
## option issuer_private_key is configured. There must only be one key per algorithm at this time.
|
||||
## For RSA keys the minimum is a 2048 bit key.
|
||||
# issuer_private_keys:
|
||||
# -
|
||||
## Key ID embedded into the JWT header for key matching. Must be an alphanumeric string with 7 or less characters.
|
||||
## This value is automatically generated if not provided. It's recommended to not configure this.
|
||||
# key_id: 'example'
|
||||
|
||||
## The key algorithm used with this key.
|
||||
# algorithm: 'RS256'
|
||||
|
||||
## The key use expected with this key. Currently only 'sig' is supported.
|
||||
# use: 'sig'
|
||||
|
||||
## Required Private Key in PEM DER form.
|
||||
# key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
|
||||
## Optional matching certificate chain in PEM DER form that matches the key. All certificates within the chain
|
||||
## must be valid and current, and from top to bottom each certificate must be signed by the subsequent one.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
|
||||
# /Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
|
||||
# LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
|
||||
# 91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
|
||||
# kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
|
||||
# Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
||||
# AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
||||
# AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
|
||||
# /ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
|
||||
# lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
|
||||
# wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
|
||||
# OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
|
||||
# ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
|
||||
# EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
|
||||
# MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
# ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
|
||||
# zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
|
||||
# 5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
|
||||
# kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
|
||||
# ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
|
||||
# Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
|
||||
# AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
|
||||
# Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
|
||||
# kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
|
||||
# 71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
|
||||
# HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
|
||||
# D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
|
||||
# 2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
|
||||
# qocikt3WAdU^invalid DO NOT USE=
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The issuer_private_key is used to sign the JWT forged by OpenID Connect.
|
||||
## The issuer_private_key is used to sign the JWT forged by OpenID Connect. This is in addition to the
|
||||
## issuer_private_keys option. Assumed to use the RS256 algorithm, and must not be specified if any of the
|
||||
## keys in issuer_private_keys also has the algorithm RS256 or are an RSA key without an algorithm.
|
||||
## Issuer Private Key can also be set using a secret: https://www.authelia.com/c/secrets
|
||||
# issuer_private_key: |
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
|
||||
# T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
|
||||
# KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
|
||||
# +5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
|
||||
# LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
|
||||
# txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
|
||||
# aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
|
||||
# Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
|
||||
# ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
|
||||
# LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
|
||||
# jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
|
||||
# BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
|
||||
# Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
|
||||
# R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
|
||||
# tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
|
||||
# ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
|
||||
# lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
|
||||
# 6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
|
||||
# fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
|
||||
# 9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
|
||||
# jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
|
||||
# rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
|
||||
# n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
|
||||
# yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
|
||||
# 27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
|
||||
# DO NOT USE==
|
||||
# MIIBPAIBAAJBAK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZF
|
||||
# p7aTcToHMf00z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAQJBAJdpB0+RQ9ZFwy9Uk38P
|
||||
# 5zZpUB8cL8ZFeEFluQeVbt0vyNa+cPLvDLouY87onduXtMz5AKIatLaTOjuG2thh
|
||||
# SKECIQDY6G8gvsYJdXCE9UJ7ukoLrRHxt/frhAtmSY5lVAPuMwIhAMzuDrJo73LH
|
||||
# ZyEaqIXc5pIiX3Sag43csPDHfuXdtT2NAiEAhyRKGJzDxiDlefFU+sGWYK/z/iYg
|
||||
# 0Rvz/kbV8UvnJwECIQDAYN6VJ6NZmc27qv33JIejOfdoTEEhZMMKVg1PlxE0ZQIg
|
||||
# HFpJiFxZES3QvVPr8deBXORPurqD5uU85NKsf61AdRsDO_NOT_USE=
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
|
||||
## Optional matching certificate chain in PEM DER form that matches the issuer_private_key. All certificates within
|
||||
## the chain must be valid and current, and from top to bottom each certificate must be signed by the next
|
||||
## certificate in the chain if provided.
|
||||
# issuer_certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
## The lifespans configure the expiration for these token types in the duration common syntax.
|
||||
# access_token_lifespan: '1h'
|
||||
# authorize_code_lifespan: '1m'
|
||||
|
@ -1499,6 +1337,11 @@ notifier:
|
|||
# - 'email'
|
||||
# - 'profile'
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - 'authorization_code'
|
||||
|
||||
## Response Types configures which responses this client can be sent.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# response_types:
|
||||
|
@ -1509,25 +1352,19 @@ notifier:
|
|||
# - 'form_post'
|
||||
# - 'query'
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - 'authorization_code'
|
||||
|
||||
## The permitted client authentication method for the Token Endpoint for this client.
|
||||
# token_endpoint_auth_method: 'client_secret_basic'
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: HS256
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: HS256
|
||||
|
||||
## The policy to require for this client; one_factor or two_factor.
|
||||
# authorization_policy: 'two_factor'
|
||||
|
||||
## The consent mode controls how consent is obtained.
|
||||
# consent_mode: 'auto'
|
||||
|
||||
## This value controls the duration a consent on this client remains remembered when the consent mode is
|
||||
## configured as 'auto' or 'pre-configured' in the duration common syntax.
|
||||
# pre_configured_consent_duration: '1w'
|
||||
|
||||
## Enforces the use of Pushed Authorization Requests for this client when set to true.
|
||||
# enforce_par: false
|
||||
|
||||
## Enforces the use of PKCE for this client when set to true.
|
||||
# enforce_pkce: false
|
||||
|
||||
|
@ -1535,13 +1372,69 @@ notifier:
|
|||
## Options are 'plain' and 'S256'.
|
||||
# pkce_challenge_method: 'S256'
|
||||
|
||||
## The permitted client authentication method for the Token Endpoint for this client.
|
||||
# token_endpoint_auth_method: 'client_secret_basic'
|
||||
|
||||
## The permitted client authentication signing algorithm for the Token Endpoint for this client when using
|
||||
## the 'client_secret_jwt' or 'private_key_jwt' token_endpoint_auth_method.
|
||||
# token_endpoint_auth_signing_alg: 'RS256'
|
||||
|
||||
## The signing algorithm which must be used for request objects. A client JWK with a matching algorithm must be
|
||||
## included if configured.
|
||||
# request_object_signing_alg: 'RS256'
|
||||
|
||||
## The signing algorithm used for ID Tokens. Am issuer JWK with a matching algorithm must be included.
|
||||
# id_token_signing_alg: 'RS256'
|
||||
|
||||
## The algorithm used to sign userinfo endpoint responses for this client, either none or RS256.
|
||||
# userinfo_signing_algorithm: 'none'
|
||||
# userinfo_signing_alg: 'none'
|
||||
|
||||
## The consent mode controls how consent is obtained.
|
||||
# consent_mode: 'auto'
|
||||
## Trusted public keys configuration for request object signing for things such as private_key_jwt
|
||||
# public_keys:
|
||||
|
||||
## This value controls the duration a consent on this client remains remembered when the consent mode is
|
||||
## configured as 'auto' or 'pre-configured' in the duration common syntax.
|
||||
# pre_configured_consent_duration: '1w'
|
||||
## URL of the HTTPS endpoint which serves the keys. It's recommended to manually configure them in the
|
||||
## values option below. Please note the URL and the individual values are mutually exclusive.
|
||||
# uri: 'https://app.example.com/jwks.json'
|
||||
|
||||
## Values from the individual keys.
|
||||
# values:
|
||||
# -
|
||||
## Key ID used to match the JWT's to an individual identifier. This option is required if configured.
|
||||
# key_id: 'example'
|
||||
|
||||
## The key algorithm expected with this key.
|
||||
# algorithm: 'RS256'
|
||||
|
||||
## The key use expected with this key. Currently only 'sig' is supported.
|
||||
# use: 'sig'
|
||||
|
||||
## Required Public Key in PEM DER form.
|
||||
# key: |
|
||||
# -----BEGIN RSA PUBLIC KEY-----
|
||||
# MEgCQQDAwV26ZA1lodtOQxNrJ491gWT+VzFum9IeZ+WTmMypYWyW1CzXKwsvTHDz
|
||||
# 9ec+jserR3EMQ0Rr24lj13FL1ib5AgMBAAE=
|
||||
# -----END RSA PUBLIC KEY----
|
||||
|
||||
## The matching certificate chain in PEM DER form that matches the key if available.
|
||||
# certificate_chain: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# MIIBWzCCAQWgAwIBAgIQYAKsXhJOXKfyySlmpKicTzANBgkqhkiG9w0BAQsFADAT
|
||||
# MREwDwYDVQQKEwhBdXRoZWxpYTAeFw0yMzA0MjEwMDA3NDRaFw0yNDA0MjAwMDA3
|
||||
# NDRaMBMxETAPBgNVBAoTCEF1dGhlbGlhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
|
||||
# AK2i7RlJEYo/Xa6mQmv9zmT0XUj3DcEhRJGPVw2qMyadUFxNg/ZFp7aTcToHMf00
|
||||
# z6T3b7mwdBkCFQOL3Kb7WRcCAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
# JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADQQB8
|
||||
# Of2iM7fPadmtChCMna8lYWH+lEplj6BxOJlRuGRawxszLwi78bnq0sCR33LU6xMx
|
||||
# 1oAPwIHNaJJwC4z6oG9E_DO_NOT_USE=
|
||||
# -----END CERTIFICATE-----
|
||||
...
|
||||
|
|
|
@ -253,4 +253,12 @@ var deprecations = map[string]Deprecation{
|
|||
MapFunc: nil,
|
||||
ErrFunc: nil,
|
||||
},
|
||||
"identity_providers.oidc.clients[].userinfo_signing_algorithm": {
|
||||
Version: model.SemanticVersion{Major: 4, Minor: 38},
|
||||
Key: "identity_providers.oidc.clients[].userinfo_signing_algorithm",
|
||||
NewKey: "identity_providers.oidc.clients[].userinfo_signing_alg",
|
||||
AutoMap: true,
|
||||
MapFunc: nil,
|
||||
ErrFunc: nil,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -245,37 +245,6 @@ func TestShouldLoadURLList(t *testing.T) {
|
|||
assert.Equal(t, "https://example.com", config.IdentityProviders.OIDC.CORS.AllowedOrigins[1].String())
|
||||
}
|
||||
|
||||
/*
|
||||
func TestShouldLoadNewOIDCConfig(t *testing.T) {
|
||||
val := schema.NewStructValidator()
|
||||
_, config, err := Load(val, NewDefaultSources([]string{"./test_resources/config_oidc_modern.yml"}, DefaultEnvPrefix, DefaultEnvDelimiter)...)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, val.Errors(), 0)
|
||||
assert.Len(t, val.Warnings(), 0)
|
||||
|
||||
val.Clear()
|
||||
|
||||
validator.ValidateIdentityProviders(&config.IdentityProviders, val)
|
||||
|
||||
assert.Len(t, val.Errors(), 0)
|
||||
|
||||
assert.Len(t, config.IdentityProviders.OIDC.IssuerJWKS.Keys, 2)
|
||||
assert.Equal(t, "keya", config.IdentityProviders.OIDC.IssuerJWKS.DefaultKeyID)
|
||||
|
||||
assert.Equal(t, oidc.KeyUseSignature, config.IdentityProviders.OIDC.IssuerJWKS.Keys["keya"].Use)
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, config.IdentityProviders.OIDC.IssuerJWKS.Keys["keya"].Algorithm)
|
||||
|
||||
assert.Equal(t, oidc.KeyUseSignature, config.IdentityProviders.OIDC.IssuerJWKS.Keys["ec521"].Use)
|
||||
assert.Equal(t, oidc.SigningAlgECDSAUsingP521AndSHA512, config.IdentityProviders.OIDC.IssuerJWKS.Keys["ec521"].Algorithm)
|
||||
|
||||
assert.Contains(t, config.IdentityProviders.OIDC.Discovery.RegisteredJWKSigningAlgs, oidc.SigningAlgRSAUsingSHA256)
|
||||
assert.Contains(t, config.IdentityProviders.OIDC.Discovery.RegisteredJWKSigningAlgs, oidc.SigningAlgECDSAUsingP521AndSHA512)
|
||||
}.
|
||||
|
||||
*/
|
||||
|
||||
func TestShouldConfigureConsent(t *testing.T) {
|
||||
val := schema.NewStructValidator()
|
||||
keys, config, err := Load(val, NewDefaultSources([]string{"./test_resources/config_oidc.yml"}, DefaultEnvPrefix, DefaultEnvDelimiter)...)
|
||||
|
@ -289,6 +258,7 @@ func TestShouldConfigureConsent(t *testing.T) {
|
|||
|
||||
require.Len(t, config.IdentityProviders.OIDC.Clients, 1)
|
||||
assert.Equal(t, config.IdentityProviders.OIDC.Clients[0].ConsentMode, "explicit")
|
||||
assert.Equal(t, "none", config.IdentityProviders.OIDC.Clients[0].UserinfoSigningAlg)
|
||||
}
|
||||
|
||||
func TestShouldValidateAndRaiseErrorsOnBadConfiguration(t *testing.T) {
|
||||
|
|
|
@ -14,11 +14,11 @@ type IdentityProvidersConfiguration struct {
|
|||
// OpenIDConnectConfiguration configuration for OpenID Connect.
|
||||
type OpenIDConnectConfiguration struct {
|
||||
HMACSecret string `koanf:"hmac_secret"`
|
||||
IssuerPrivateKeys []JWK `koanf:"issuer_private_keys"`
|
||||
|
||||
IssuerCertificateChain X509CertificateChain `koanf:"issuer_certificate_chain"`
|
||||
IssuerPrivateKey *rsa.PrivateKey `koanf:"issuer_private_key"`
|
||||
|
||||
IssuerJWKS []JWK `koanf:"issuer_jwks"`
|
||||
|
||||
AccessTokenLifespan time.Duration `koanf:"access_token_lifespan"`
|
||||
AuthorizeCodeLifespan time.Duration `koanf:"authorize_code_lifespan"`
|
||||
IDTokenLifespan time.Duration `koanf:"id_token_lifespan"`
|
||||
|
@ -30,8 +30,8 @@ type OpenIDConnectConfiguration struct {
|
|||
EnforcePKCE string `koanf:"enforce_pkce"`
|
||||
EnablePKCEPlainChallenge bool `koanf:"enable_pkce_plain_challenge"`
|
||||
|
||||
CORS OpenIDConnectCORSConfiguration `koanf:"cors"`
|
||||
PAR OpenIDConnectPARConfiguration `koanf:"pushed_authorizations"`
|
||||
CORS OpenIDConnectCORSConfiguration `koanf:"cors"`
|
||||
|
||||
Clients []OpenIDConnectClientConfiguration `koanf:"clients"`
|
||||
|
||||
|
@ -40,7 +40,8 @@ type OpenIDConnectConfiguration struct {
|
|||
|
||||
type OpenIDConnectDiscovery struct {
|
||||
DefaultKeyID string
|
||||
RegisteredJWKSigningAlgs []string
|
||||
ResponseObjectSigningAlgs []string
|
||||
RequestObjectSigningAlgs []string
|
||||
}
|
||||
|
||||
// OpenIDConnectPARConfiguration represents an OpenID Connect PAR config.
|
||||
|
@ -73,21 +74,31 @@ type OpenIDConnectClientConfiguration struct {
|
|||
ResponseTypes []string `koanf:"response_types"`
|
||||
ResponseModes []string `koanf:"response_modes"`
|
||||
|
||||
TokenEndpointAuthMethod string `koanf:"token_endpoint_auth_method"`
|
||||
TokenEndpointAuthSigningAlg string `koanf:"token_endpoint_auth_signing_alg"`
|
||||
|
||||
IDTokenSigningAlg string `koanf:"id_token_signing_alg"`
|
||||
|
||||
Policy string `koanf:"authorization_policy"`
|
||||
|
||||
ConsentMode string `koanf:"consent_mode"`
|
||||
ConsentPreConfiguredDuration *time.Duration `koanf:"pre_configured_consent_duration"`
|
||||
|
||||
EnforcePAR bool `koanf:"enforce_par"`
|
||||
EnforcePKCE bool `koanf:"enforce_pkce"`
|
||||
|
||||
PKCEChallengeMethod string `koanf:"pkce_challenge_method"`
|
||||
UserinfoSigningAlg string `koanf:"userinfo_signing_algorithm"`
|
||||
|
||||
ConsentMode string `koanf:"consent_mode"`
|
||||
ConsentPreConfiguredDuration *time.Duration `koanf:"pre_configured_consent_duration"`
|
||||
TokenEndpointAuthMethod string `koanf:"token_endpoint_auth_method"`
|
||||
|
||||
TokenEndpointAuthSigningAlg string `koanf:"token_endpoint_auth_signing_alg"`
|
||||
RequestObjectSigningAlg string `koanf:"request_object_signing_alg"`
|
||||
IDTokenSigningAlg string `koanf:"id_token_signing_alg"`
|
||||
UserinfoSigningAlg string `koanf:"userinfo_signing_alg"`
|
||||
|
||||
PublicKeys OpenIDConnectClientPublicKeys `koanf:"public_keys"`
|
||||
|
||||
Discovery OpenIDConnectDiscovery
|
||||
}
|
||||
|
||||
type OpenIDConnectClientPublicKeys struct {
|
||||
URI *url.URL `koanf:"uri"`
|
||||
Values []JWK `koanf:"values"`
|
||||
}
|
||||
|
||||
// DefaultOpenIDConnectConfiguration contains defaults for OIDC.
|
||||
|
|
|
@ -18,14 +18,14 @@ var Keys = []string{
|
|||
"log.file_path",
|
||||
"log.keep_stdout",
|
||||
"identity_providers.oidc.hmac_secret",
|
||||
"identity_providers.oidc.issuer_private_keys",
|
||||
"identity_providers.oidc.issuer_private_keys[].key_id",
|
||||
"identity_providers.oidc.issuer_private_keys[]",
|
||||
"identity_providers.oidc.issuer_private_keys[].algorithm",
|
||||
"identity_providers.oidc.issuer_private_keys[].key",
|
||||
"identity_providers.oidc.issuer_private_keys[].certificate_chain",
|
||||
"identity_providers.oidc.issuer_certificate_chain",
|
||||
"identity_providers.oidc.issuer_private_key",
|
||||
"identity_providers.oidc.issuer_jwks",
|
||||
"identity_providers.oidc.issuer_jwks[].key_id",
|
||||
"identity_providers.oidc.issuer_jwks[]",
|
||||
"identity_providers.oidc.issuer_jwks[].algorithm",
|
||||
"identity_providers.oidc.issuer_jwks[].key",
|
||||
"identity_providers.oidc.issuer_jwks[].certificate_chain",
|
||||
"identity_providers.oidc.access_token_lifespan",
|
||||
"identity_providers.oidc.authorize_code_lifespan",
|
||||
"identity_providers.oidc.id_token_lifespan",
|
||||
|
@ -34,11 +34,11 @@ var Keys = []string{
|
|||
"identity_providers.oidc.minimum_parameter_entropy",
|
||||
"identity_providers.oidc.enforce_pkce",
|
||||
"identity_providers.oidc.enable_pkce_plain_challenge",
|
||||
"identity_providers.oidc.pushed_authorizations.enforce",
|
||||
"identity_providers.oidc.pushed_authorizations.context_lifespan",
|
||||
"identity_providers.oidc.cors.endpoints",
|
||||
"identity_providers.oidc.cors.allowed_origins",
|
||||
"identity_providers.oidc.cors.allowed_origins_from_client_redirect_uris",
|
||||
"identity_providers.oidc.pushed_authorizations.enforce",
|
||||
"identity_providers.oidc.pushed_authorizations.context_lifespan",
|
||||
"identity_providers.oidc.clients",
|
||||
"identity_providers.oidc.clients[].id",
|
||||
"identity_providers.oidc.clients[].description",
|
||||
|
@ -51,16 +51,25 @@ var Keys = []string{
|
|||
"identity_providers.oidc.clients[].grant_types",
|
||||
"identity_providers.oidc.clients[].response_types",
|
||||
"identity_providers.oidc.clients[].response_modes",
|
||||
"identity_providers.oidc.clients[].token_endpoint_auth_method",
|
||||
"identity_providers.oidc.clients[].token_endpoint_auth_signing_alg",
|
||||
"identity_providers.oidc.clients[].id_token_signing_alg",
|
||||
"identity_providers.oidc.clients[].authorization_policy",
|
||||
"identity_providers.oidc.clients[].consent_mode",
|
||||
"identity_providers.oidc.clients[].pre_configured_consent_duration",
|
||||
"identity_providers.oidc.clients[].enforce_par",
|
||||
"identity_providers.oidc.clients[].enforce_pkce",
|
||||
"identity_providers.oidc.clients[].pkce_challenge_method",
|
||||
"identity_providers.oidc.clients[].userinfo_signing_algorithm",
|
||||
"identity_providers.oidc.clients[].consent_mode",
|
||||
"identity_providers.oidc.clients[].pre_configured_consent_duration",
|
||||
"identity_providers.oidc.clients[].token_endpoint_auth_method",
|
||||
"identity_providers.oidc.clients[].token_endpoint_auth_signing_alg",
|
||||
"identity_providers.oidc.clients[].request_object_signing_alg",
|
||||
"identity_providers.oidc.clients[].id_token_signing_alg",
|
||||
"identity_providers.oidc.clients[].userinfo_signing_alg",
|
||||
"identity_providers.oidc.clients[].public_keys.uri",
|
||||
"identity_providers.oidc.clients[].public_keys.values",
|
||||
"identity_providers.oidc.clients[].public_keys.values[].key_id",
|
||||
"identity_providers.oidc.clients[].public_keys.values[]",
|
||||
"identity_providers.oidc.clients[].public_keys.values[].algorithm",
|
||||
"identity_providers.oidc.clients[].public_keys.values[].key",
|
||||
"identity_providers.oidc.clients[].public_keys.values[].certificate_chain",
|
||||
"identity_providers.oidc.clients[]",
|
||||
"identity_providers.oidc",
|
||||
"authentication_backend.password_reset.disable",
|
||||
"authentication_backend.password_reset.custom_url",
|
||||
|
|
|
@ -102,6 +102,7 @@ func NewX509CertificateChain(in string) (chain *X509CertificateChain, err error)
|
|||
return chain, nil
|
||||
}
|
||||
|
||||
// NewX509CertificateChainFromCerts returns a chain from a given list of certificates without validation.
|
||||
func NewX509CertificateChainFromCerts(in []*x509.Certificate) (chain X509CertificateChain) {
|
||||
return X509CertificateChain{certs: in}
|
||||
}
|
||||
|
|
|
@ -218,6 +218,11 @@ func TestNewX509CertificateChain(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewX509CertificateChainFromCerts(t *testing.T) {
|
||||
have := NewX509CertificateChainFromCerts(nil)
|
||||
assert.NotNil(t, have)
|
||||
}
|
||||
|
||||
func TestX509CertificateChain(t *testing.T) {
|
||||
chain := &X509CertificateChain{}
|
||||
|
||||
|
|
|
@ -131,4 +131,5 @@ identity_providers:
|
|||
- id: 'abc'
|
||||
secret: '123'
|
||||
consent_mode: 'explicit'
|
||||
userinfo_signing_alg: 'none'
|
||||
...
|
||||
|
|
|
@ -127,7 +127,7 @@ notifier:
|
|||
identity_providers:
|
||||
oidc:
|
||||
hmac_secret: 1nb2j3kh1b23kjh1b23jh1b23j1h2b3
|
||||
issuer_jwks:
|
||||
issuer_private_keys:
|
||||
keys:
|
||||
keya:
|
||||
key: |
|
||||
|
|
|
@ -142,15 +142,25 @@ const (
|
|||
|
||||
// OpenID Error constants.
|
||||
const (
|
||||
errFmtOIDCNoClientsConfigured = "identity_providers: oidc: option 'clients' must have one or " +
|
||||
errFmtOIDCProviderNoClientsConfigured = "identity_providers: oidc: option 'clients' must have one or " +
|
||||
"more clients configured"
|
||||
errFmtOIDCNoPrivateKey = "identity_providers: oidc: option 'issuer_private_key' or `issuer_jwks` is required"
|
||||
errFmtOIDCInvalidPrivateKeyBitSize = "identity_providers: oidc: option 'issuer_private_key' must be an RSA private key with %d bits or more but it only has %d bits"
|
||||
errFmtOIDCInvalidPrivateKeyMalformedMissingPublicKey = "identity_providers: oidc: option 'issuer_private_key' must be a valid RSA private key but the provided data is missing the public key bits"
|
||||
errFmtOIDCCertificateMismatch = "identity_providers: oidc: option 'issuer_private_key' does not appear to be the private key the certificate provided by option 'issuer_certificate_chain'"
|
||||
errFmtOIDCCertificateChain = "identity_providers: oidc: option 'issuer_certificate_chain' produced an error during validation of the chain: %w"
|
||||
errFmtOIDCEnforcePKCEInvalidValue = "identity_providers: oidc: option 'enforce_pkce' must be 'never', " +
|
||||
errFmtOIDCProviderNoPrivateKey = "identity_providers: oidc: option `issuer_private_keys` or 'issuer_private_key' is required"
|
||||
errFmtOIDCProviderEnforcePKCEInvalidValue = "identity_providers: oidc: option 'enforce_pkce' must be 'never', " +
|
||||
"'public_clients_only' or 'always', but it's configured as '%s'"
|
||||
errFmtOIDCProviderInsecureParameterEntropy = "openid connect provider: SECURITY ISSUE - minimum parameter entropy is " +
|
||||
"configured to an unsafe value, it should be above 8 but it's configured to %d"
|
||||
errFmtOIDCProviderPrivateKeysInvalid = "identity_providers: oidc: issuer_private_keys: key #%d: option 'key' must be a valid private key but the provided data is malformed as it's missing the public key bits"
|
||||
errFmtOIDCProviderPrivateKeysCalcThumbprint = "identity_providers: oidc: issuer_private_keys: key #%d: option 'key' failed to calculate thumbprint to configure key id value: %w"
|
||||
errFmtOIDCProviderPrivateKeysKeyIDLength = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option `key_id`` must be 7 characters or less"
|
||||
errFmtOIDCProviderPrivateKeysAttributeNotUnique = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option '%s' must be unique"
|
||||
errFmtOIDCProviderPrivateKeysKeyIDNotAlphaNumeric = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'key_id' must only have alphanumeric characters"
|
||||
errFmtOIDCProviderPrivateKeysProperties = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'key' failed to get key properties: %w"
|
||||
errFmtOIDCProviderPrivateKeysInvalidOptionOneOf = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'"
|
||||
errFmtOIDCProviderPrivateKeysRSAKeyLessThan2048Bits = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'key' is an RSA %d bit private key but it must at minimum be a RSA 2048 bit private key"
|
||||
errFmtOIDCProviderPrivateKeysKeyNotRSAOrECDSA = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'key' must be a RSA private key or ECDSA private key but it's type is %T"
|
||||
errFmtOIDCProviderPrivateKeysKeyCertificateMismatch = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'certificate_chain' does not appear to contain the public key for the private key provided by option 'key'"
|
||||
errFmtOIDCProviderPrivateKeysCertificateChainInvalid = "identity_providers: oidc: issuer_private_keys: key #%d with key id '%s': option 'certificate_chain' produced an error during validation of the chain: %w"
|
||||
errFmtOIDCProviderPrivateKeysNoRS256 = "identity_providers: oidc: issuer_private_keys: keys: must at least have one key supporting the '%s' algorithm but only has %s"
|
||||
|
||||
errFmtOIDCCORSInvalidOrigin = "identity_providers: oidc: cors: option 'allowed_origins' contains an invalid value '%s' as it has a %s: origins must only be scheme, hostname, and an optional port"
|
||||
errFmtOIDCCORSInvalidOriginWildcard = "identity_providers: oidc: cors: option 'allowed_origins' contains the wildcard origin '*' with more than one origin but the wildcard origin must be defined by itself"
|
||||
|
@ -161,45 +171,61 @@ const (
|
|||
errFmtOIDCClientsWithEmptyID = "identity_providers: oidc: clients: option 'id' is required but was absent on the clients in positions %s"
|
||||
errFmtOIDCClientsDeprecated = "identity_providers: oidc: clients: warnings for clients above indicate deprecated functionality and it's strongly suggested these issues are checked and fixed if they're legitimate issues or reported if they are not as in a future version these warnings will become errors"
|
||||
|
||||
errFmtOIDCClientInvalidSecret = "identity_providers: oidc: client '%s': option 'secret' is required"
|
||||
errFmtOIDCClientInvalidSecretPlainText = "identity_providers: oidc: client '%s': option 'secret' is plaintext but for clients not using the 'token_endpoint_auth_method' of 'client_secret_jwt' it should be a hashed value as plaintext values are deprecated with the exception of 'client_secret_jwt' and will be removed when oidc becomes stable"
|
||||
errFmtOIDCClientInvalidSecretNotPlainText = "identity_providers: oidc: client '%s': option 'secret' must be plaintext with option 'token_endpoint_auth_method' with a value of 'client_secret_jwt'"
|
||||
errFmtOIDCClientPublicInvalidSecret = "identity_providers: oidc: client '%s': option 'secret' is " +
|
||||
errFmtOIDCClientInvalidSecret = "identity_providers: oidc: clients: client '%s': option 'secret' is required"
|
||||
errFmtOIDCClientInvalidSecretPlainText = "identity_providers: oidc: clients: client '%s': option 'secret' is plaintext but for clients not using the 'token_endpoint_auth_method' of 'client_secret_jwt' it should be a hashed value as plaintext values are deprecated with the exception of 'client_secret_jwt' and will be removed when oidc becomes stable"
|
||||
errFmtOIDCClientInvalidSecretNotPlainText = "identity_providers: oidc: clients: client '%s': option 'secret' must be plaintext with option 'token_endpoint_auth_method' with a value of 'client_secret_jwt'"
|
||||
errFmtOIDCClientPublicInvalidSecret = "identity_providers: oidc: clients: client '%s': option 'secret' is " +
|
||||
"required to be empty when option 'public' is true"
|
||||
errFmtOIDCClientRedirectURICantBeParsed = "identity_providers: oidc: client '%s': option 'redirect_uris' has an " +
|
||||
errFmtOIDCClientRedirectURICantBeParsed = "identity_providers: oidc: clients: client '%s': option 'redirect_uris' has an " +
|
||||
"invalid value: redirect uri '%s' could not be parsed: %v"
|
||||
errFmtOIDCClientRedirectURIPublic = "identity_providers: oidc: client '%s': option 'redirect_uris' has the " +
|
||||
errFmtOIDCClientRedirectURIPublic = "identity_providers: oidc: clients: client '%s': option 'redirect_uris' has the " +
|
||||
"redirect uri '%s' when option 'public' is false but this is invalid as this uri is not valid " +
|
||||
"for the openid connect confidential client type"
|
||||
errFmtOIDCClientRedirectURIAbsolute = "identity_providers: oidc: client '%s': option 'redirect_uris' has an " +
|
||||
errFmtOIDCClientRedirectURIAbsolute = "identity_providers: oidc: clients: client '%s': option 'redirect_uris' has an " +
|
||||
"invalid value: redirect uri '%s' must have a scheme but it's absent"
|
||||
errFmtOIDCClientInvalidConsentMode = "identity_providers: oidc: client '%s': consent: option 'mode' must be one of " +
|
||||
errFmtOIDCClientInvalidConsentMode = "identity_providers: oidc: clients: client '%s': consent: option 'mode' must be one of " +
|
||||
"%s but it's configured as '%s'"
|
||||
errFmtOIDCClientInvalidEntries = "identity_providers: oidc: client '%s': option '%s' must only have the values " +
|
||||
errFmtOIDCClientInvalidEntries = "identity_providers: oidc: clients: client '%s': option '%s' must only have the values " +
|
||||
"%s but the values %s are present"
|
||||
errFmtOIDCClientInvalidEntryDuplicates = "identity_providers: oidc: client '%s': option '%s' must have unique values but the values %s are duplicated"
|
||||
errFmtOIDCClientInvalidValue = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidEntryDuplicates = "identity_providers: oidc: clients: client '%s': option '%s' must have unique values but the values %s are duplicated"
|
||||
errFmtOIDCClientInvalidValue = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'%s' must be one of %s but it's configured as '%s'"
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthMethod = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthMethod = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'token_endpoint_auth_method' must be one of %s when configured as the confidential client type unless it only includes implicit flow response types such as %s but it's configured as '%s'"
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthMethodPublic = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthMethodPublic = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'token_endpoint_auth_method' must be 'none' when configured as the public client type but it's configured as '%s'"
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthSigAlg = "identity_providers: oidc: client '%s': option " +
|
||||
"'token_endpoint_auth_signing_alg' must be %s when option 'token_endpoint_auth_method' is %s"
|
||||
errFmtOIDCClientInvalidSectorIdentifier = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthSigAlg = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'token_endpoint_auth_signing_alg' must be one of %s when option 'token_endpoint_auth_method' is configured to '%s'"
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthSigAlgReg = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'token_endpoint_auth_signing_alg' must be one of registered public key algorithm values %s when option 'token_endpoint_auth_method' is configured to '%s'"
|
||||
errFmtOIDCClientInvalidTokenEndpointAuthSigAlgMissingPrivateKeyJWT = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'token_endpoint_auth_signing_alg' is required when option 'token_endpoint_auth_method' is configured to 'private_key_jwt'"
|
||||
errFmtOIDCClientInvalidPublicKeysPrivateKeyJWT = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'public_keys' is required with 'token_endpoint_auth_method' set to 'private_key_jwt'"
|
||||
errFmtOIDCClientInvalidSectorIdentifier = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'sector_identifier' with value '%s': must be a URL with only the host component for example '%s' but it has a %s with the value '%s'"
|
||||
errFmtOIDCClientInvalidSectorIdentifierWithoutValue = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidSectorIdentifierWithoutValue = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'sector_identifier' with value '%s': must be a URL with only the host component for example '%s' but it has a %s"
|
||||
errFmtOIDCClientInvalidSectorIdentifierHost = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidSectorIdentifierHost = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'sector_identifier' with value '%s': must be a URL with only the host component but appears to be invalid"
|
||||
errFmtOIDCClientInvalidGrantTypeMatch = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidGrantTypeMatch = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'grant_types' should only have grant type values which are valid with the configured 'response_types' for the client but '%s' expects a response type %s such as %s but the response types are %s"
|
||||
errFmtOIDCClientInvalidGrantTypeRefresh = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidGrantTypeRefresh = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'grant_types' should only have the 'refresh_token' value if the client is also configured with the 'offline_access' scope"
|
||||
errFmtOIDCClientInvalidRefreshTokenOptionWithoutCodeResponseType = "identity_providers: oidc: client '%s': option " +
|
||||
errFmtOIDCClientInvalidRefreshTokenOptionWithoutCodeResponseType = "identity_providers: oidc: clients: client '%s': option " +
|
||||
"'%s' should only have the values %s if the client is also configured with a 'response_type' such as %s which respond with authorization codes"
|
||||
errFmtOIDCServerInsecureParameterEntropy = "openid connect provider: SECURITY ISSUE - minimum parameter entropy is " +
|
||||
"configured to an unsafe value, it should be above 8 but it's configured to %d"
|
||||
|
||||
errFmtOIDCClientPublicKeysBothURIAndValuesConfigured = "identity_providers: oidc: clients: client '%s': public_keys: option 'uri' must not be defined at the same time as option 'values'"
|
||||
errFmtOIDCClientPublicKeysURIInvalidScheme = "identity_providers: oidc: clients: client '%s': public_keys: option 'uri' must have the 'https' scheme but the scheme is '%s'"
|
||||
errFmtOIDCClientPublicKeysProperties = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option 'key' failed to get key properties: %w"
|
||||
errFmtOIDCClientPublicKeysInvalidOptionOneOf = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'"
|
||||
errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d: option '%s' must be provided"
|
||||
errFmtOIDCClientPublicKeysKeyMalformed = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d: option 'key' option 'key' must be a valid private key but the provided data is malformed as it's missing the public key bits"
|
||||
errFmtOIDCClientPublicKeysRSAKeyLessThan2048Bits = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option 'key' is an RSA %d bit private key but it must at minimum be a RSA 2048 bit private key"
|
||||
errFmtOIDCClientPublicKeysKeyNotRSAOrECDSA = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option 'key' must be a RSA public key or ECDSA public key but it's type is %T"
|
||||
errFmtOIDCClientPublicKeysCertificateChainKeyMismatch = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option 'certificate_chain' does not appear to contain the public key for the public key provided by option 'key'"
|
||||
errFmtOIDCClientPublicKeysCertificateChainInvalid = "identity_providers: oidc: clients: client '%s': public_keys: values: key #%d with key id '%s': option 'certificate_chain' produced an error during validation of the chain: %w"
|
||||
errFmtOIDCClientPublicKeysROSAMissingAlgorithm = "identity_providers: oidc: clients: client '%s': option 'request_object_signing_alg' must be one of %s configured in the client option 'public_keys'"
|
||||
)
|
||||
|
||||
// WebAuthn Error constants.
|
||||
|
@ -290,9 +316,6 @@ const (
|
|||
const (
|
||||
errFmtServerTLSCert = "server: tls: option 'key' must also be accompanied by option 'certificate'"
|
||||
errFmtServerTLSKey = "server: tls: option 'certificate' must also be accompanied by option 'key'"
|
||||
errFmtServerTLSFileNotExist = "server: tls: option '%s' the file '%s' does not exist"
|
||||
errFmtServerTLSFileNotExistErr = "server: tls: option '%s' could not determine if the file '%s' exists: %w"
|
||||
|
||||
errFmtServerTLSClientAuthNoAuth = "server: tls: client authentication cannot be configured if no server certificate and key are provided"
|
||||
|
||||
errFmtServerAddressLegacyAndModern = "server: option 'host' and 'port' can't be configured at the same time as 'address'"
|
||||
|
@ -402,13 +425,17 @@ var (
|
|||
var validDefault2FAMethods = []string{"totp", "webauthn", "mobile_push"}
|
||||
|
||||
const (
|
||||
attrOIDCKey = "key"
|
||||
attrOIDCKeyID = "key_id"
|
||||
attrOIDCKeyUse = "use"
|
||||
attrOIDCAlgorithm = "algorithm"
|
||||
attrOIDCScopes = "scopes"
|
||||
attrOIDCResponseTypes = "response_types"
|
||||
attrOIDCResponseModes = "response_modes"
|
||||
attrOIDCGrantTypes = "grant_types"
|
||||
attrOIDCRedirectURIs = "redirect_uris"
|
||||
attrOIDCTokenAuthMethod = "token_endpoint_auth_method"
|
||||
attrOIDCUsrSigAlg = "userinfo_signing_algorithm"
|
||||
attrOIDCUsrSigAlg = "userinfo_signing_alg"
|
||||
attrOIDCIDTokenSigAlg = "id_token_signing_alg"
|
||||
attrOIDCPKCEChallengeMethod = "pkce_challenge_method"
|
||||
)
|
||||
|
@ -425,9 +452,9 @@ var (
|
|||
validOIDCClientResponseTypesRefreshToken = []string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeHybridFlowIDToken, oidc.ResponseTypeHybridFlowToken, oidc.ResponseTypeHybridFlowBoth}
|
||||
validOIDCClientGrantTypes = []string{oidc.GrantTypeImplicit, oidc.GrantTypeRefreshToken, oidc.GrantTypeAuthorizationCode}
|
||||
|
||||
validOIDCClientTokenEndpointAuthMethods = []string{oidc.ClientAuthMethodNone, oidc.ClientAuthMethodClientSecretPost, oidc.ClientAuthMethodClientSecretBasic, oidc.ClientAuthMethodClientSecretJWT}
|
||||
validOIDCClientTokenEndpointAuthMethodsConfidential = []string{oidc.ClientAuthMethodClientSecretPost, oidc.ClientAuthMethodClientSecretBasic}
|
||||
validOIDCClientTokenEndpointAuthSigAlgs = []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512}
|
||||
validOIDCClientTokenEndpointAuthMethods = []string{oidc.ClientAuthMethodNone, oidc.ClientAuthMethodClientSecretPost, oidc.ClientAuthMethodClientSecretBasic, oidc.ClientAuthMethodPrivateKeyJWT, oidc.ClientAuthMethodClientSecretJWT}
|
||||
validOIDCClientTokenEndpointAuthMethodsConfidential = []string{oidc.ClientAuthMethodClientSecretPost, oidc.ClientAuthMethodClientSecretBasic, oidc.ClientAuthMethodPrivateKeyJWT}
|
||||
validOIDCClientTokenEndpointAuthSigAlgsClientSecretJWT = []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512}
|
||||
validOIDCIssuerJWKSigningAlgs = []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgRSAPSSUsingSHA256, oidc.SigningAlgECDSAUsingP256AndSHA256, oidc.SigningAlgRSAUsingSHA384, oidc.SigningAlgRSAPSSUsingSHA384, oidc.SigningAlgECDSAUsingP384AndSHA384, oidc.SigningAlgRSAUsingSHA512, oidc.SigningAlgRSAPSSUsingSHA512, oidc.SigningAlgECDSAUsingP521AndSHA512}
|
||||
)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ const (
|
|||
|
||||
const (
|
||||
exampleDotCom = "example.com"
|
||||
rs256 = "rs256"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
|
@ -33,20 +33,23 @@ func validateOIDC(config *schema.OpenIDConnectConfiguration, val *schema.StructV
|
|||
|
||||
validateOIDCIssuer(config, val)
|
||||
|
||||
sort.Sort(oidc.SortedSigningAlgs(config.Discovery.RegisteredJWKSigningAlgs))
|
||||
sort.Sort(oidc.SortedSigningAlgs(config.Discovery.ResponseObjectSigningAlgs))
|
||||
|
||||
if config.MinimumParameterEntropy != 0 && config.MinimumParameterEntropy < 8 {
|
||||
val.PushWarning(fmt.Errorf(errFmtOIDCServerInsecureParameterEntropy, config.MinimumParameterEntropy))
|
||||
val.PushWarning(fmt.Errorf(errFmtOIDCProviderInsecureParameterEntropy, config.MinimumParameterEntropy))
|
||||
}
|
||||
|
||||
if config.EnforcePKCE != "never" && config.EnforcePKCE != "public_clients_only" && config.EnforcePKCE != "always" {
|
||||
val.Push(fmt.Errorf(errFmtOIDCEnforcePKCEInvalidValue, config.EnforcePKCE))
|
||||
switch config.EnforcePKCE {
|
||||
case "always", "never", "public_clients_only":
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderEnforcePKCEInvalidValue, config.EnforcePKCE))
|
||||
}
|
||||
|
||||
validateOIDCOptionsCORS(config, val)
|
||||
|
||||
if len(config.Clients) == 0 {
|
||||
val.Push(fmt.Errorf(errFmtOIDCNoClientsConfigured))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderNoClientsConfigured))
|
||||
} else {
|
||||
validateOIDCClients(config, val)
|
||||
}
|
||||
|
@ -55,158 +58,159 @@ func validateOIDC(config *schema.OpenIDConnectConfiguration, val *schema.StructV
|
|||
func validateOIDCIssuer(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
switch {
|
||||
case config.IssuerPrivateKey != nil:
|
||||
validateOIDCIssuerLegacy(config, val)
|
||||
validateOIDCIssuerPrivateKey(config)
|
||||
|
||||
fallthrough
|
||||
case len(config.IssuerJWKS) != 0:
|
||||
validateOIDCIssuerModern(config, val)
|
||||
case len(config.IssuerPrivateKeys) != 0:
|
||||
validateOIDCIssuerPrivateKeys(config, val)
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCNoPrivateKey))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderNoPrivateKey))
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCIssuerLegacy(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
j := &jose.JSONWebKey{Key: &config.IssuerPrivateKey.PublicKey}
|
||||
|
||||
thumbprint, err := j.Thumbprint(crypto.SHA1)
|
||||
if err != nil {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: option 'issuer_private_key' failed to calculate thumbprint to configure key id value: %w", err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
config.IssuerJWKS = append(config.IssuerJWKS, schema.JWK{
|
||||
KeyID: fmt.Sprintf("%x", thumbprint)[:6],
|
||||
func validateOIDCIssuerPrivateKey(config *schema.OpenIDConnectConfiguration) {
|
||||
config.IssuerPrivateKeys = append([]schema.JWK{{
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Key: config.IssuerPrivateKey,
|
||||
CertificateChain: config.IssuerCertificateChain,
|
||||
})
|
||||
}}, config.IssuerPrivateKeys...)
|
||||
}
|
||||
|
||||
//nolint:gocyclo // Refactor time permitting.
|
||||
func validateOIDCIssuerModern(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
func jwkCalculateThumbprint(key schema.CryptographicKey) (thumbprintStr string, err error) {
|
||||
j := jose.JSONWebKey{}
|
||||
|
||||
switch k := key.(type) {
|
||||
case schema.CryptographicPrivateKey:
|
||||
j.Key = k.Public()
|
||||
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
|
||||
j.Key = k
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var thumbprint []byte
|
||||
|
||||
if thumbprint, err = j.Thumbprint(crypto.SHA256); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", thumbprint)[:6], nil
|
||||
}
|
||||
|
||||
func validateOIDCIssuerPrivateKeys(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
var (
|
||||
props *JWKProperties
|
||||
err error
|
||||
)
|
||||
|
||||
kids := make([]string, len(config.IssuerJWKS))
|
||||
kids := make([]string, len(config.IssuerPrivateKeys))
|
||||
|
||||
for i := 0; i < len(config.IssuerJWKS); i++ {
|
||||
if key, ok := config.IssuerJWKS[i].Key.(*rsa.PrivateKey); ok && key.PublicKey.N == nil {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d: option 'key' must be a valid RSA private key but the provided data is malformed as it's missing the public key bits", i+1))
|
||||
for i := 0; i < len(config.IssuerPrivateKeys); i++ {
|
||||
if key, ok := config.IssuerPrivateKeys[i].Key.(*rsa.PrivateKey); ok && key.PublicKey.N == nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysInvalid, i+1))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
switch n := len(config.IssuerJWKS[i].KeyID); {
|
||||
switch n := len(config.IssuerPrivateKeys[i].KeyID); {
|
||||
case n == 0:
|
||||
j := jose.JSONWebKey{}
|
||||
|
||||
switch key := config.IssuerJWKS[i].Key.(type) {
|
||||
case schema.CryptographicPrivateKey:
|
||||
j.Key = key.Public()
|
||||
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
|
||||
j.Key = key
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if j.Key == nil {
|
||||
break
|
||||
}
|
||||
|
||||
var thumbprint []byte
|
||||
|
||||
if thumbprint, err = j.Thumbprint(crypto.SHA1); err != nil {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d: option 'key' failed to calculate thumbprint to configure key id value: %w", i+1, err))
|
||||
if config.IssuerPrivateKeys[i].KeyID, err = jwkCalculateThumbprint(config.IssuerPrivateKeys[i].Key); err != nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysCalcThumbprint, i+1, err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
config.IssuerJWKS[i].KeyID = fmt.Sprintf("%x", thumbprint)[:6]
|
||||
case n > 7:
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option `key_id`` must be 7 characters or less", i+1, config.IssuerJWKS[i].KeyID))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysKeyIDLength, i+1, config.IssuerPrivateKeys[i].KeyID))
|
||||
}
|
||||
|
||||
if config.IssuerJWKS[i].KeyID != "" && utils.IsStringInSlice(config.IssuerJWKS[i].KeyID, kids) {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key_id' must be unique", i+1, config.IssuerJWKS[i].KeyID))
|
||||
if config.IssuerPrivateKeys[i].KeyID != "" && utils.IsStringInSlice(config.IssuerPrivateKeys[i].KeyID, kids) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysAttributeNotUnique, i+1, config.IssuerPrivateKeys[i].KeyID, attrOIDCKeyID))
|
||||
}
|
||||
|
||||
kids[i] = config.IssuerJWKS[i].KeyID
|
||||
kids[i] = config.IssuerPrivateKeys[i].KeyID
|
||||
|
||||
if !utils.IsStringAlphaNumeric(config.IssuerJWKS[i].KeyID) {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key_id' must only have alphanumeric characters", i+1, config.IssuerJWKS[i].KeyID))
|
||||
if !utils.IsStringAlphaNumeric(config.IssuerPrivateKeys[i].KeyID) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysKeyIDNotAlphaNumeric, i+1, config.IssuerPrivateKeys[i].KeyID))
|
||||
}
|
||||
|
||||
if props, err = schemaJWKGetProperties(config.IssuerJWKS[i]); err != nil {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key' failed to get key properties: %w", i+1, config.IssuerJWKS[i].KeyID, err))
|
||||
if props, err = schemaJWKGetProperties(config.IssuerPrivateKeys[i]); err != nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysProperties, i+1, config.IssuerPrivateKeys[i].KeyID, err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
switch config.IssuerJWKS[i].Use {
|
||||
validateOIDCIssuerPrivateKeysUseAlg(i, props, config, val)
|
||||
validateOIDCIssuerPrivateKeyPair(i, config, val)
|
||||
}
|
||||
|
||||
if len(config.Discovery.ResponseObjectSigningAlgs) != 0 && !utils.IsStringInSlice(oidc.SigningAlgRSAUsingSHA256, config.Discovery.ResponseObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysNoRS256, oidc.SigningAlgRSAUsingSHA256, strJoinAnd(config.Discovery.ResponseObjectSigningAlgs)))
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCIssuerPrivateKeysUseAlg(i int, props *JWKProperties, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
switch config.IssuerPrivateKeys[i].Use {
|
||||
case "":
|
||||
config.IssuerJWKS[i].Use = props.Use
|
||||
config.IssuerPrivateKeys[i].Use = props.Use
|
||||
case oidc.KeyUseSignature:
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'", i+1, config.IssuerJWKS[i].KeyID, "use", strJoinOr([]string{oidc.KeyUseSignature}), config.IssuerJWKS[i].Use))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysInvalidOptionOneOf, i+1, config.IssuerPrivateKeys[i].KeyID, attrOIDCKeyUse, strJoinOr([]string{oidc.KeyUseSignature}), config.IssuerPrivateKeys[i].Use))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.IssuerJWKS[i].Algorithm == "":
|
||||
config.IssuerJWKS[i].Algorithm = props.Algorithm
|
||||
case utils.IsStringInSlice(config.IssuerJWKS[i].Algorithm, validOIDCIssuerJWKSigningAlgs):
|
||||
case config.IssuerPrivateKeys[i].Algorithm == "":
|
||||
config.IssuerPrivateKeys[i].Algorithm = props.Algorithm
|
||||
case utils.IsStringInSlice(config.IssuerPrivateKeys[i].Algorithm, validOIDCIssuerJWKSigningAlgs):
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'", i+1, config.IssuerJWKS[i].KeyID, "algorithm", strJoinOr(validOIDCIssuerJWKSigningAlgs), config.IssuerJWKS[i].Algorithm))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysInvalidOptionOneOf, i+1, config.IssuerPrivateKeys[i].KeyID, attrOIDCAlgorithm, strJoinOr(validOIDCIssuerJWKSigningAlgs), config.IssuerPrivateKeys[i].Algorithm))
|
||||
}
|
||||
|
||||
if config.IssuerJWKS[i].Algorithm != "" {
|
||||
if utils.IsStringInSlice(config.IssuerJWKS[i].Algorithm, config.Discovery.RegisteredJWKSigningAlgs) {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'algorithm' must be unique but another key is using it", i+1, config.IssuerJWKS[i].KeyID))
|
||||
if config.IssuerPrivateKeys[i].Algorithm != "" {
|
||||
if utils.IsStringInSlice(config.IssuerPrivateKeys[i].Algorithm, config.Discovery.ResponseObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysAttributeNotUnique, i+1, config.IssuerPrivateKeys[i].KeyID, attrOIDCAlgorithm))
|
||||
} else {
|
||||
config.Discovery.RegisteredJWKSigningAlgs = append(config.Discovery.RegisteredJWKSigningAlgs, config.IssuerJWKS[i].Algorithm)
|
||||
config.Discovery.ResponseObjectSigningAlgs = append(config.Discovery.ResponseObjectSigningAlgs, config.IssuerPrivateKeys[i].Algorithm)
|
||||
}
|
||||
}
|
||||
|
||||
if config.IssuerJWKS[i].Algorithm == oidc.SigningAlgRSAUsingSHA256 && config.Discovery.DefaultKeyID == "" {
|
||||
config.Discovery.DefaultKeyID = config.IssuerJWKS[i].KeyID
|
||||
if config.IssuerPrivateKeys[i].Algorithm == oidc.SigningAlgRSAUsingSHA256 && config.Discovery.DefaultKeyID == "" {
|
||||
config.Discovery.DefaultKeyID = config.IssuerPrivateKeys[i].KeyID
|
||||
}
|
||||
}
|
||||
|
||||
var checkEqualKey bool
|
||||
func validateOIDCIssuerPrivateKeyPair(i int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
var (
|
||||
checkEqualKey bool
|
||||
err error
|
||||
)
|
||||
|
||||
switch key := config.IssuerJWKS[i].Key.(type) {
|
||||
switch key := config.IssuerPrivateKeys[i].Key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
checkEqualKey = true
|
||||
|
||||
if key.Size() < 256 {
|
||||
checkEqualKey = false
|
||||
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key' is an RSA %d bit private key but it must be a RSA 2048 bit private key", i+1, config.IssuerJWKS[i].KeyID, key.Size()*8))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysRSAKeyLessThan2048Bits, i+1, config.IssuerPrivateKeys[i].KeyID, key.Size()*8))
|
||||
}
|
||||
case *ecdsa.PrivateKey:
|
||||
checkEqualKey = true
|
||||
default:
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key' must be a *rsa.PrivateKey or *ecdsa.PrivateKey but it's a %T", i+1, config.IssuerJWKS[i].KeyID, key))
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysKeyNotRSAOrECDSA, i+1, config.IssuerPrivateKeys[i].KeyID, key))
|
||||
}
|
||||
|
||||
if config.IssuerJWKS[i].CertificateChain.HasCertificates() {
|
||||
if checkEqualKey && !config.IssuerJWKS[i].CertificateChain.EqualKey(config.IssuerJWKS[i].Key) {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'key' does not appear to be the private key the certificate provided by option 'certificate_chain'", i+1, config.IssuerJWKS[i].KeyID))
|
||||
if config.IssuerPrivateKeys[i].CertificateChain.HasCertificates() {
|
||||
if checkEqualKey && !config.IssuerPrivateKeys[i].CertificateChain.EqualKey(config.IssuerPrivateKeys[i].Key) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysKeyCertificateMismatch, i+1, config.IssuerPrivateKeys[i].KeyID))
|
||||
}
|
||||
|
||||
if err = config.IssuerJWKS[i].CertificateChain.Validate(); err != nil {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: key #%d with key id '%s': option 'certificate_chain' produced an error during validation of the chain: %w", i+1, config.IssuerJWKS[i].KeyID, err))
|
||||
if err = config.IssuerPrivateKeys[i].CertificateChain.Validate(); err != nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysCertificateChainInvalid, i+1, config.IssuerPrivateKeys[i].KeyID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(config.Discovery.RegisteredJWKSigningAlgs) != 0 && !utils.IsStringInSlice(oidc.SigningAlgRSAUsingSHA256, config.Discovery.RegisteredJWKSigningAlgs) {
|
||||
val.Push(fmt.Errorf("identity_providers: oidc: issuer_jwks: keys: must at least have one key supporting the '%s' algorithm but only has %s", oidc.SigningAlgRSAUsingSHA256, strJoinAnd(config.Discovery.RegisteredJWKSigningAlgs)))
|
||||
}
|
||||
}
|
||||
|
||||
func setOIDCDefaults(config *schema.OpenIDConnectConfiguration) {
|
||||
|
@ -356,7 +360,7 @@ func validateOIDCClient(c int, config *schema.OpenIDConnectConfiguration, val *s
|
|||
case policyOneFactor, policyTwoFactor:
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, "policy", strJoinOr([]string{policyOneFactor, policyTwoFactor}), config.Clients[c].Policy))
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, "authorization_policy", strJoinOr([]string{policyOneFactor, policyTwoFactor}), config.Clients[c].Policy))
|
||||
}
|
||||
|
||||
switch config.Clients[c].PKCEChallengeMethod {
|
||||
|
@ -374,10 +378,113 @@ func validateOIDCClient(c int, config *schema.OpenIDConnectConfiguration, val *s
|
|||
validateOIDCClientGrantTypes(c, config, val, errDeprecatedFunc)
|
||||
validateOIDCClientRedirectURIs(c, config, val, errDeprecatedFunc)
|
||||
|
||||
validateOIDCClientTokenEndpointAuth(c, config, val)
|
||||
validateOIDDClientSigningAlgs(c, config, val)
|
||||
|
||||
validateOIDCClientSectorIdentifier(c, config, val)
|
||||
|
||||
validateOIDCClientPublicKeys(c, config, val)
|
||||
validateOIDCClientTokenEndpointAuth(c, config, val)
|
||||
}
|
||||
|
||||
func validateOIDCClientPublicKeys(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
switch {
|
||||
case config.Clients[c].PublicKeys.URI != nil && len(config.Clients[c].PublicKeys.Values) != 0:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysBothURIAndValuesConfigured, config.Clients[c].ID))
|
||||
case config.Clients[c].PublicKeys.URI != nil:
|
||||
if config.Clients[c].PublicKeys.URI.Scheme != schemeHTTPS {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysURIInvalidScheme, config.Clients[c].ID, config.Clients[c].PublicKeys.URI.Scheme))
|
||||
}
|
||||
case len(config.Clients[c].PublicKeys.Values) != 0:
|
||||
validateOIDCClientJSONWebKeysList(c, config, val)
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCClientJSONWebKeysList(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
var (
|
||||
props *JWKProperties
|
||||
err error
|
||||
)
|
||||
|
||||
for i := 0; i < len(config.Clients[c].PublicKeys.Values); i++ {
|
||||
if config.Clients[c].PublicKeys.Values[i].KeyID == "" {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf, config.Clients[c].ID, i+1, attrOIDCKeyID))
|
||||
}
|
||||
|
||||
if props, err = schemaJWKGetProperties(config.Clients[c].PublicKeys.Values[i]); err != nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysProperties, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
validateOIDCClientJSONWebKeysListKeyUseAlg(c, i, props, config, val)
|
||||
|
||||
var checkEqualKey bool
|
||||
|
||||
switch key := config.Clients[c].PublicKeys.Values[i].Key.(type) {
|
||||
case nil:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf, config.Clients[c].ID, i+1, attrOIDCKey))
|
||||
case *rsa.PublicKey:
|
||||
checkEqualKey = true
|
||||
|
||||
if key.N == nil {
|
||||
checkEqualKey = false
|
||||
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysKeyMalformed, config.Clients[c].ID, i+1))
|
||||
} else if key.Size() < 256 {
|
||||
checkEqualKey = false
|
||||
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysRSAKeyLessThan2048Bits, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, key.Size()*8))
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
checkEqualKey = true
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysKeyNotRSAOrECDSA, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, key))
|
||||
}
|
||||
|
||||
if config.Clients[c].PublicKeys.Values[i].CertificateChain.HasCertificates() {
|
||||
if checkEqualKey && !config.Clients[c].PublicKeys.Values[i].CertificateChain.EqualKey(config.Clients[c].PublicKeys.Values[i].Key) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysCertificateChainKeyMismatch, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID))
|
||||
}
|
||||
|
||||
if err = config.Clients[c].PublicKeys.Values[i].CertificateChain.Validate(); err != nil {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysCertificateChainInvalid, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if config.Clients[c].RequestObjectSigningAlg != "" && !utils.IsStringInSlice(config.Clients[c].RequestObjectSigningAlg, config.Clients[c].Discovery.RequestObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysROSAMissingAlgorithm, config.Clients[c].ID, strJoinOr(config.Clients[c].Discovery.RequestObjectSigningAlgs)))
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCClientJSONWebKeysListKeyUseAlg(c, i int, props *JWKProperties, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
switch config.Clients[c].PublicKeys.Values[i].Use {
|
||||
case "":
|
||||
config.Clients[c].PublicKeys.Values[i].Use = props.Use
|
||||
case oidc.KeyUseSignature:
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionOneOf, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, attrOIDCKeyUse, strJoinOr([]string{oidc.KeyUseSignature}), config.Clients[c].PublicKeys.Values[i].Use))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.Clients[c].PublicKeys.Values[i].Algorithm == "":
|
||||
config.Clients[c].PublicKeys.Values[i].Algorithm = props.Algorithm
|
||||
case utils.IsStringInSlice(config.Clients[c].PublicKeys.Values[i].Algorithm, validOIDCIssuerJWKSigningAlgs):
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionOneOf, config.Clients[c].ID, i+1, config.Clients[c].PublicKeys.Values[i].KeyID, attrOIDCAlgorithm, strJoinOr(validOIDCIssuerJWKSigningAlgs), config.Clients[c].PublicKeys.Values[i].Algorithm))
|
||||
}
|
||||
|
||||
if config.Clients[c].PublicKeys.Values[i].Algorithm != "" {
|
||||
if !utils.IsStringInSlice(config.Clients[c].PublicKeys.Values[i].Algorithm, config.Discovery.RequestObjectSigningAlgs) {
|
||||
config.Discovery.RequestObjectSigningAlgs = append(config.Discovery.RequestObjectSigningAlgs, config.Clients[c].PublicKeys.Values[i].Algorithm)
|
||||
}
|
||||
|
||||
if !utils.IsStringInSlice(config.Clients[c].PublicKeys.Values[i].Algorithm, config.Clients[c].Discovery.RequestObjectSigningAlgs) {
|
||||
config.Clients[c].Discovery.RequestObjectSigningAlgs = append(config.Clients[c].Discovery.RequestObjectSigningAlgs, config.Clients[c].PublicKeys.Values[i].Algorithm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCClientSectorIdentifier(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
|
@ -654,11 +761,34 @@ func validateOIDCClientTokenEndpointAuth(c int, config *schema.OpenIDConnectConf
|
|||
case "":
|
||||
break
|
||||
case oidc.ClientAuthMethodClientSecretJWT:
|
||||
validateOIDCClientTokenEndpointAuthClientSecretJWT(c, config, val)
|
||||
case oidc.ClientAuthMethodPrivateKeyJWT:
|
||||
validateOIDCClientTokenEndpointAuthPublicKeyJWT(config.Clients[c], val)
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCClientTokenEndpointAuthClientSecretJWT(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
switch {
|
||||
case config.Clients[c].TokenEndpointAuthSigningAlg == "":
|
||||
config.Clients[c].TokenEndpointAuthSigningAlg = oidc.SigningAlgHMACUsingSHA256
|
||||
case !utils.IsStringInSlice(config.Clients[c].TokenEndpointAuthSigningAlg, validOIDCClientTokenEndpointAuthSigAlgs):
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthSigAlg, config.Clients[c].ID, strJoinOr(validOIDCClientTokenEndpointAuthSigAlgs), config.Clients[c].TokenEndpointAuthMethod))
|
||||
case !utils.IsStringInSlice(config.Clients[c].TokenEndpointAuthSigningAlg, validOIDCClientTokenEndpointAuthSigAlgsClientSecretJWT):
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthSigAlg, config.Clients[c].ID, strJoinOr(validOIDCClientTokenEndpointAuthSigAlgsClientSecretJWT), config.Clients[c].TokenEndpointAuthMethod))
|
||||
}
|
||||
}
|
||||
|
||||
func validateOIDCClientTokenEndpointAuthPublicKeyJWT(config schema.OpenIDConnectClientConfiguration, val *schema.StructValidator) {
|
||||
switch {
|
||||
case config.TokenEndpointAuthSigningAlg == "":
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthSigAlgMissingPrivateKeyJWT, config.ID))
|
||||
case !utils.IsStringInSlice(config.TokenEndpointAuthSigningAlg, validOIDCIssuerJWKSigningAlgs):
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthSigAlg, config.ID, strJoinOr(validOIDCIssuerJWKSigningAlgs), config.TokenEndpointAuthMethod))
|
||||
}
|
||||
|
||||
if config.PublicKeys.URI == nil {
|
||||
if len(config.PublicKeys.Values) == 0 {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidPublicKeysPrivateKeyJWT, config.ID))
|
||||
} else if len(config.Discovery.RequestObjectSigningAlgs) != 0 && !utils.IsStringInSlice(config.TokenEndpointAuthSigningAlg, config.Discovery.RequestObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthSigAlgReg, config.ID, strJoinOr(config.Discovery.RequestObjectSigningAlgs), config.TokenEndpointAuthMethod))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -666,15 +796,15 @@ func validateOIDCClientTokenEndpointAuth(c int, config *schema.OpenIDConnectConf
|
|||
func validateOIDDClientSigningAlgs(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
|
||||
if config.Clients[c].UserinfoSigningAlg == "" {
|
||||
config.Clients[c].UserinfoSigningAlg = schema.DefaultOpenIDConnectClientConfiguration.UserinfoSigningAlg
|
||||
} else if config.Clients[c].UserinfoSigningAlg != oidc.SigningAlgNone && !utils.IsStringInSlice(config.Clients[c].UserinfoSigningAlg, config.Discovery.RegisteredJWKSigningAlgs) {
|
||||
} else if config.Clients[c].UserinfoSigningAlg != oidc.SigningAlgNone && !utils.IsStringInSlice(config.Clients[c].UserinfoSigningAlg, config.Discovery.ResponseObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue,
|
||||
config.Clients[c].ID, attrOIDCUsrSigAlg, strJoinOr(append(config.Discovery.RegisteredJWKSigningAlgs, oidc.SigningAlgNone)), config.Clients[c].UserinfoSigningAlg))
|
||||
config.Clients[c].ID, attrOIDCUsrSigAlg, strJoinOr(append(config.Discovery.ResponseObjectSigningAlgs, oidc.SigningAlgNone)), config.Clients[c].UserinfoSigningAlg))
|
||||
}
|
||||
|
||||
if config.Clients[c].IDTokenSigningAlg == "" {
|
||||
config.Clients[c].IDTokenSigningAlg = schema.DefaultOpenIDConnectClientConfiguration.IDTokenSigningAlg
|
||||
} else if !utils.IsStringInSlice(config.Clients[c].IDTokenSigningAlg, config.Discovery.RegisteredJWKSigningAlgs) {
|
||||
} else if !utils.IsStringInSlice(config.Clients[c].IDTokenSigningAlg, config.Discovery.ResponseObjectSigningAlgs) {
|
||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue,
|
||||
config.Clients[c].ID, attrOIDCIDTokenSigAlg, strJoinOr(config.Discovery.RegisteredJWKSigningAlgs), config.Clients[c].IDTokenSigningAlg))
|
||||
config.Clients[c].ID, attrOIDCIDTokenSigAlg, strJoinOr(config.Discovery.ResponseObjectSigningAlgs), config.Clients[c].IDTokenSigningAlg))
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -37,13 +37,7 @@ func validateNotifierTemplates(config *schema.NotifierConfiguration, validator *
|
|||
return
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
_, err = os.Stat(config.TemplatePath)
|
||||
|
||||
switch {
|
||||
switch _, err := os.Stat(config.TemplatePath); {
|
||||
case os.IsNotExist(err):
|
||||
validator.Push(fmt.Errorf(errFmtNotifierTemplatePathNotExist, config.TemplatePath))
|
||||
return
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
|
@ -284,3 +285,17 @@ func (suite *NotifierSuite) TestFileShouldEnsureFilenameIsProvided() {
|
|||
func TestNotifierSuite(t *testing.T) {
|
||||
suite.Run(t, new(NotifierSuite))
|
||||
}
|
||||
|
||||
func TestNotifierMiscMissingTemplateTests(t *testing.T) {
|
||||
config := &schema.NotifierConfiguration{
|
||||
TemplatePath: string([]byte{0x0, 0x1}),
|
||||
}
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
|
||||
validateNotifierTemplates(config, val)
|
||||
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
||||
assert.EqualError(t, val.Errors()[0], "notifier: option 'template_path' refers to location '\x00\x01' which couldn't be opened: stat \x00\x01: invalid argument")
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package validator
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -19,11 +20,11 @@ func ValidateServerTLS(config *schema.Configuration, validator *schema.StructVal
|
|||
}
|
||||
|
||||
if config.Server.TLS.Key != "" {
|
||||
validateFileExists(config.Server.TLS.Key, validator, "key")
|
||||
validateServerTLSFileExists("key", config.Server.TLS.Key, validator)
|
||||
}
|
||||
|
||||
if config.Server.TLS.Certificate != "" {
|
||||
validateFileExists(config.Server.TLS.Certificate, validator, "certificate")
|
||||
validateServerTLSFileExists("certificate", config.Server.TLS.Certificate, validator)
|
||||
}
|
||||
|
||||
if config.Server.TLS.Key == "" && config.Server.TLS.Certificate == "" &&
|
||||
|
@ -32,7 +33,24 @@ func ValidateServerTLS(config *schema.Configuration, validator *schema.StructVal
|
|||
}
|
||||
|
||||
for _, clientCertPath := range config.Server.TLS.ClientCertificates {
|
||||
validateFileExists(clientCertPath, validator, "client_certificates")
|
||||
validateServerTLSFileExists("client_certificates", clientCertPath, validator)
|
||||
}
|
||||
}
|
||||
|
||||
// validateServerTLSFileExists checks whether a file exist.
|
||||
func validateServerTLSFileExists(name, path string, validator *schema.StructValidator) {
|
||||
var (
|
||||
info os.FileInfo
|
||||
err error
|
||||
)
|
||||
|
||||
switch info, err = os.Stat(path); {
|
||||
case os.IsNotExist(err):
|
||||
validator.Push(fmt.Errorf("server: tls: option '%s' with path '%s' refers to a file that doesn't exist", name, path))
|
||||
case err != nil:
|
||||
validator.Push(fmt.Errorf("server: tls: option '%s' with path '%s' could not be verified due to a file system error: %w", name, path, err))
|
||||
case info.IsDir():
|
||||
validator.Push(fmt.Errorf("server: tls: option '%s' with path '%s' refers to a directory but it should refer to a file", name, path))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,13 +215,3 @@ func validateServerEndpointsAuthzStrategies(name string, strategies []schema.Ser
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validateFileExists checks whether a file exist.
|
||||
func validateFileExists(path string, validator *schema.StructValidator, opt string) {
|
||||
exist, err := utils.FileExists(path)
|
||||
if err != nil {
|
||||
validator.Push(fmt.Errorf(errFmtServerTLSFileNotExistErr, opt, path, err))
|
||||
} else if !exist {
|
||||
validator.Push(fmt.Errorf(errFmtServerTLSFileNotExist, opt, path))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -296,7 +297,7 @@ func TestShouldRaiseErrorWhenTLSCertDoesNotExist(t *testing.T) {
|
|||
|
||||
ValidateServer(&config, validator)
|
||||
require.Len(t, validator.Errors(), 1)
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'certificate' the file '/tmp/unexisting_file' does not exist")
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'certificate' with path '/tmp/unexisting_file' refers to a file that doesn't exist")
|
||||
}
|
||||
|
||||
func TestShouldRaiseErrorWhenTLSKeyWithoutCertIsProvided(t *testing.T) {
|
||||
|
@ -329,7 +330,7 @@ func TestShouldRaiseErrorWhenTLSKeyDoesNotExist(t *testing.T) {
|
|||
|
||||
ValidateServer(&config, validator)
|
||||
require.Len(t, validator.Errors(), 1)
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'key' the file '/tmp/unexisting_file' does not exist")
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'key' with path '/tmp/unexisting_file' refers to a file that doesn't exist")
|
||||
}
|
||||
|
||||
func TestShouldNotRaiseErrorWhenBothTLSCertificateAndKeyAreProvided(t *testing.T) {
|
||||
|
@ -373,7 +374,7 @@ func TestShouldRaiseErrorWhenTLSClientCertificateDoesNotExist(t *testing.T) {
|
|||
|
||||
ValidateServer(&config, validator)
|
||||
require.Len(t, validator.Errors(), 1)
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'client_certificates' the file '/tmp/unexisting' does not exist")
|
||||
assert.EqualError(t, validator.Errors()[0], "server: tls: option 'client_certificates' with path '/tmp/unexisting' refers to a file that doesn't exist")
|
||||
}
|
||||
|
||||
func TestShouldRaiseErrorWhenTLSClientAuthIsDefinedButNotServerCertificate(t *testing.T) {
|
||||
|
@ -569,3 +570,25 @@ func TestServerAuthzEndpointLegacyAsImplementationLegacyWhenBlank(t *testing.T)
|
|||
|
||||
assert.Equal(t, authzImplementationLegacy, config.Server.Endpoints.Authz[legacy].Implementation)
|
||||
}
|
||||
|
||||
func TestValidateTLSPathStatInvalidArgument(t *testing.T) {
|
||||
val := schema.NewStructValidator()
|
||||
|
||||
validateServerTLSFileExists("key", string([]byte{0x0, 0x1}), val)
|
||||
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
||||
assert.EqualError(t, val.Errors()[0], "server: tls: option 'key' with path '\x00\x01' could not be verified due to a file system error: stat \x00\x01: invalid argument")
|
||||
}
|
||||
|
||||
func TestValidateTLSPathIsDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
|
||||
validateServerTLSFileExists("key", dir, val)
|
||||
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
||||
assert.EqualError(t, val.Errors()[0], fmt.Sprintf("server: tls: option 'key' with path '%s' refers to a directory but it should refer to a file", dir))
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ import (
|
|||
|
||||
// ValidateTLSConfig sets the default values and validates a schema.TLSConfig.
|
||||
func ValidateTLSConfig(config *schema.TLSConfig, configDefault *schema.TLSConfig) (err error) {
|
||||
if configDefault == nil {
|
||||
return errors.New("must provide configDefault")
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
return
|
||||
}
|
||||
|
@ -35,7 +39,7 @@ func ValidateTLSConfig(config *schema.TLSConfig, configDefault *schema.TLSConfig
|
|||
}
|
||||
|
||||
if (config.CertificateChain.HasCertificates() || config.PrivateKey != nil) && !config.CertificateChain.EqualKey(config.PrivateKey) {
|
||||
return errors.New("option 'certificates' is invalid: provided certificate is not the public key for the private key provided")
|
||||
return errors.New("option 'certificates' is invalid: provided certificate does not contain the public key for the private key provided")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
func TestValidateTLSConfig(t *testing.T) {
|
||||
var (
|
||||
config, configDefault *schema.TLSConfig
|
||||
)
|
||||
|
||||
assert.EqualError(t, ValidateTLSConfig(config, configDefault), "must provide configDefault")
|
||||
|
||||
configDefault = &schema.TLSConfig{}
|
||||
|
||||
assert.NoError(t, ValidateTLSConfig(config, configDefault))
|
||||
|
||||
config = &schema.TLSConfig{}
|
||||
|
||||
assert.NoError(t, ValidateTLSConfig(config, configDefault))
|
||||
|
||||
config.PrivateKey = keyRSA2048
|
||||
config.CertificateChain = certRSA4096
|
||||
|
||||
assert.EqualError(t, ValidateTLSConfig(config, configDefault), "option 'certificates' is invalid: provided certificate does not contain the public key for the private key provided")
|
||||
}
|
|
@ -125,12 +125,20 @@ type JWKProperties struct {
|
|||
func schemaJWKGetProperties(jwk schema.JWK) (properties *JWKProperties, err error) {
|
||||
switch key := jwk.Key.(type) {
|
||||
case nil:
|
||||
return nil, fmt.Errorf("private key is nil")
|
||||
return nil, nil
|
||||
case ed25519.PrivateKey, ed25519.PublicKey:
|
||||
return &JWKProperties{}, nil
|
||||
case *rsa.PrivateKey:
|
||||
if key.PublicKey.N == nil {
|
||||
return &JWKProperties{oidc.KeyUseSignature, oidc.SigningAlgRSAUsingSHA256, 0, nil}, nil
|
||||
}
|
||||
|
||||
return &JWKProperties{oidc.KeyUseSignature, oidc.SigningAlgRSAUsingSHA256, key.Size(), nil}, nil
|
||||
case *rsa.PublicKey:
|
||||
if key.N == nil {
|
||||
return &JWKProperties{oidc.KeyUseSignature, oidc.SigningAlgRSAUsingSHA256, 0, nil}, nil
|
||||
}
|
||||
|
||||
return &JWKProperties{oidc.KeyUseSignature, oidc.SigningAlgRSAUsingSHA256, key.Size(), nil}, nil
|
||||
case *ecdsa.PublicKey:
|
||||
switch key.Curve {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestIsCookieDomainValid(t *testing.T) {
|
||||
|
@ -38,3 +43,39 @@ func TestIsCookieDomainValid(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildStringFuncsMissingTests(t *testing.T) {
|
||||
assert.Equal(t, "", buildJoinedString(".", ":", "'", nil))
|
||||
assert.Equal(t, "'abc', '123'", strJoinComma("", []string{"abc", "123"}))
|
||||
}
|
||||
|
||||
func TestSchemaJWKGetPropertiesMissingTests(t *testing.T) {
|
||||
props, err := schemaJWKGetProperties(schema.JWK{Key: keyECDSAP224})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, oidc.KeyUseSignature, props.Use)
|
||||
assert.Equal(t, "", props.Algorithm)
|
||||
assert.Equal(t, elliptic.P224(), props.Curve)
|
||||
assert.Equal(t, -1, props.Bits)
|
||||
|
||||
props, err = schemaJWKGetProperties(schema.JWK{Key: keyECDSAP224.Public()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, oidc.KeyUseSignature, props.Use)
|
||||
assert.Equal(t, "", props.Algorithm)
|
||||
assert.Equal(t, elliptic.P224(), props.Curve)
|
||||
assert.Equal(t, -1, props.Bits)
|
||||
|
||||
rsa := &rsa.PrivateKey{}
|
||||
|
||||
*rsa = *keyRSA2048
|
||||
rsa.PublicKey.N = nil
|
||||
|
||||
props, err = schemaJWKGetProperties(schema.JWK{Key: rsa})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, oidc.KeyUseSignature, props.Use)
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, props.Algorithm)
|
||||
assert.Equal(t, nil, props.Curve)
|
||||
assert.Equal(t, 0, props.Bits)
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ func OpenIDConnectAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWr
|
|||
|
||||
ctx.Logger.Debugf("Authorization Request with id '%s' on client with id '%s' was successfully processed, proceeding to build Authorization Response", requester.GetID(), clientID)
|
||||
|
||||
session := oidc.NewSessionWithAuthorizeRequest(issuer, ctx.Providers.OpenIDConnect.KeyManager.GetKIDFromAlg(ctx, client.GetIDTokenSigningAlg()),
|
||||
session := oidc.NewSessionWithAuthorizeRequest(issuer, ctx.Providers.OpenIDConnect.KeyManager.GetKeyIDFromAlg(ctx, client.GetIDTokenSigningAlg()),
|
||||
userSession.Username, userSession.AuthenticationMethodRefs.MarshalRFC8176(), extraClaims, authTime, consent, requester)
|
||||
|
||||
ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with claims: %+v",
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
type testAMRWant struct {
|
||||
|
@ -17,13 +19,13 @@ type testAMRWant struct {
|
|||
func TestAuthenticationMethodsReferences(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
is AuthenticationMethodsReferences
|
||||
is oidc.AuthenticationMethodsReferences
|
||||
want testAMRWant
|
||||
}{
|
||||
{
|
||||
desc: "Username and Password",
|
||||
|
||||
is: AuthenticationMethodsReferences{UsernameAndPassword: true},
|
||||
is: oidc.AuthenticationMethodsReferences{UsernameAndPassword: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: true,
|
||||
FactorPossession: false,
|
||||
|
@ -37,7 +39,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "TOTP",
|
||||
|
||||
is: AuthenticationMethodsReferences{TOTP: true},
|
||||
is: oidc.AuthenticationMethodsReferences{TOTP: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -51,7 +53,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "WebAuthn",
|
||||
|
||||
is: AuthenticationMethodsReferences{WebAuthn: true},
|
||||
is: oidc.AuthenticationMethodsReferences{WebAuthn: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -65,7 +67,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "WebAuthn User Presence",
|
||||
|
||||
is: AuthenticationMethodsReferences{WebAuthnUserPresence: true},
|
||||
is: oidc.AuthenticationMethodsReferences{WebAuthnUserPresence: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: false,
|
||||
|
@ -79,7 +81,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "WebAuthn User Verified",
|
||||
|
||||
is: AuthenticationMethodsReferences{WebAuthnUserVerified: true},
|
||||
is: oidc.AuthenticationMethodsReferences{WebAuthnUserVerified: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: false,
|
||||
|
@ -93,7 +95,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "WebAuthn with User Presence and Verified",
|
||||
|
||||
is: AuthenticationMethodsReferences{WebAuthn: true, WebAuthnUserVerified: true, WebAuthnUserPresence: true},
|
||||
is: oidc.AuthenticationMethodsReferences{WebAuthn: true, WebAuthnUserVerified: true, WebAuthnUserPresence: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -107,7 +109,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "Duo",
|
||||
|
||||
is: AuthenticationMethodsReferences{Duo: true},
|
||||
is: oidc.AuthenticationMethodsReferences{Duo: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -121,7 +123,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "Duo WebAuthn TOTP",
|
||||
|
||||
is: AuthenticationMethodsReferences{Duo: true, WebAuthn: true, TOTP: true},
|
||||
is: oidc.AuthenticationMethodsReferences{Duo: true, WebAuthn: true, TOTP: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -135,7 +137,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "Duo TOTP",
|
||||
|
||||
is: AuthenticationMethodsReferences{Duo: true, TOTP: true},
|
||||
is: oidc.AuthenticationMethodsReferences{Duo: true, TOTP: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: false,
|
||||
FactorPossession: true,
|
||||
|
@ -149,7 +151,7 @@ func TestAuthenticationMethodsReferences(t *testing.T) {
|
|||
{
|
||||
desc: "Username and Password with Duo",
|
||||
|
||||
is: AuthenticationMethodsReferences{Duo: true, UsernameAndPassword: true},
|
||||
is: oidc.AuthenticationMethodsReferences{Duo: true, UsernameAndPassword: true},
|
||||
want: testAMRWant{
|
||||
FactorKnowledge: true,
|
||||
FactorPossession: true,
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"github.com/go-crypt/crypt/algorithm/plaintext"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/ory/fosite"
|
||||
|
@ -20,6 +22,46 @@ import (
|
|||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
// NewHasher returns a new Hasher.
|
||||
func NewHasher() (hasher *Hasher, err error) {
|
||||
hasher = &Hasher{}
|
||||
|
||||
if hasher.decoder, err = crypt.NewDefaultDecoder(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = plaintext.RegisterDecoderPlainText(hasher.decoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hasher, nil
|
||||
}
|
||||
|
||||
// Hasher implements the fosite.Hasher interface and adaptively compares hashes.
|
||||
type Hasher struct {
|
||||
decoder algorithm.DecoderRegister
|
||||
}
|
||||
|
||||
// Compare compares the hash with the data and returns an error if they don't match.
|
||||
func (h Hasher) Compare(_ context.Context, hash, data []byte) (err error) {
|
||||
var digest algorithm.Digest
|
||||
|
||||
if digest, err = h.decoder.Decode(string(hash)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if digest.MatchBytes(data) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errPasswordsDoNotMatch
|
||||
}
|
||||
|
||||
// Hash creates a new hash from data.
|
||||
func (h Hasher) Hash(_ context.Context, data []byte) (hash []byte, err error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// DefaultClientAuthenticationStrategy is a copy of fosite's with the addition of the client_secret_jwt method and some
|
||||
// minor superficial changes.
|
||||
//
|
|
@ -1,14 +1,10 @@
|
|||
package handlers
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -21,6 +17,8 @@ import (
|
|||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
|
@ -31,6 +29,58 @@ import (
|
|||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestShouldNotRaiseErrorOnEqualPasswordsPlainText(t *testing.T) {
|
||||
hasher, err := oidc.NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc")
|
||||
b := []byte("abc")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.NoError(t, hasher.Compare(ctx, a, b))
|
||||
}
|
||||
|
||||
func TestShouldNotRaiseErrorOnEqualPasswordsPlainTextWithSeparator(t *testing.T) {
|
||||
hasher, err := oidc.NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc$123")
|
||||
b := []byte("abc$123")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.NoError(t, hasher.Compare(ctx, a, b))
|
||||
}
|
||||
|
||||
func TestShouldRaiseErrorOnNonEqualPasswordsPlainText(t *testing.T) {
|
||||
hasher, err := oidc.NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc")
|
||||
b := []byte("abcd")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.EqualError(t, hasher.Compare(ctx, a, b), "The provided client secret did not match the registered client secret.")
|
||||
}
|
||||
|
||||
func TestShouldHashPassword(t *testing.T) {
|
||||
hasher := oidc.Hasher{}
|
||||
|
||||
data := []byte("abc")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
hash, err := hasher.Hash(ctx, data)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, hash)
|
||||
}
|
||||
|
||||
func TestClientAuthenticationStrategySuite(t *testing.T) {
|
||||
suite.Run(t, &ClientAuthenticationStrategySuite{})
|
||||
}
|
||||
|
@ -135,7 +185,9 @@ func (s *ClientAuthenticationStrategySuite) GetAssertionRequest(token string) (r
|
|||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) GetCtx() oidc.OpenIDConnectContext {
|
||||
return &oidc.MockOpenIDConnectContext{
|
||||
fmt.Println(s.GetIssuerURL())
|
||||
|
||||
return &MockOpenIDConnectContext{
|
||||
Context: context.Background(),
|
||||
MockIssuerURL: s.GetIssuerURL(),
|
||||
}
|
||||
|
@ -145,12 +197,12 @@ func (s *ClientAuthenticationStrategySuite) SetupTest() {
|
|||
s.ctrl = gomock.NewController(s.T())
|
||||
s.store = mocks.NewMockStorage(s.ctrl)
|
||||
|
||||
secret := MustDecodeSecret("$plaintext$client-secret")
|
||||
secret := tOpenIDConnectPlainTextClientSecret
|
||||
|
||||
s.provider = oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerJWKS: []schema.JWK{},
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: MustParseRSAPrivateKey(exampleRSAPrivateKey),
|
||||
IssuerPrivateKeys: []schema.JWK{
|
||||
{Key: keyRSA2048, CertificateChain: certRSA2048, Use: oidc.KeyUseSignature, Algorithm: oidc.SigningAlgRSAUsingSHA256},
|
||||
},
|
||||
HMACSecret: "abc123",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
|
@ -184,7 +236,7 @@ func (s *ClientAuthenticationStrategySuite) SetupTest() {
|
|||
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA512,
|
||||
},
|
||||
{
|
||||
ID: "rs256",
|
||||
ID: rs256,
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
|
@ -273,6 +325,142 @@ func (s *ClientAuthenticationStrategySuite) SetupTest() {
|
|||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP521AndSHA512,
|
||||
},
|
||||
|
||||
{
|
||||
ID: "rs256k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA256,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: rs256, Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAUsingSHA256, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "rs384k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA384,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "rs384", Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAUsingSHA384, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "rs512k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA512,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "rs512", Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAUsingSHA512, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "ps256k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA256,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "ps256", Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAPSSUsingSHA256, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "ps384k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA384,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "ps384", Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAPSSUsingSHA384, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "ps512k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA512,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "ps512", Key: keyRSA2048.PublicKey, Algorithm: oidc.SigningAlgRSAPSSUsingSHA512, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "es256k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP256AndSHA256,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "es256", Key: keyECDSAP256.PublicKey, Algorithm: oidc.SigningAlgECDSAUsingP256AndSHA256, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "es384k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP384AndSHA384,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "es384", Key: keyECDSAP384.PublicKey, Algorithm: oidc.SigningAlgECDSAUsingP384AndSHA384, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "es512k",
|
||||
Secret: secret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP521AndSHA512,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
Values: []schema.JWK{
|
||||
{KeyID: "es512", Key: keyECDSAP521.PublicKey, Algorithm: oidc.SigningAlgECDSAUsingP521AndSHA512, Use: oidc.KeyUseSignature},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "hs5122",
|
||||
Secret: secret,
|
||||
|
@ -471,7 +659,7 @@ func (s *ClientAuthenticationStrategySuite) TestShouldValidateAssertionHS512() {
|
|||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnMismatchedAlg() {
|
||||
assertion := NewAssertion("rs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
assertion := NewAssertion(rs256, s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
|
||||
|
||||
|
@ -507,11 +695,11 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnMismatchedAlgS
|
|||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS256() {
|
||||
assertion := NewAssertion("rs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
assertion := NewAssertion(rs256, s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS256, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -524,12 +712,100 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnBadAlgRS256() {
|
||||
assertion := NewAssertion("rs256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = rs256
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The 'client_assertion' uses signing algorithm 'PS256' but the requested OAuth 2.0 Client enforces signing algorithm 'RS256'.")
|
||||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnBadKidRS256() {
|
||||
assertion := NewAssertion("rs256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "nokey"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The JSON Web Token uses signing key with kid 'nokey', which could not be found.")
|
||||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnBadTypRS256() {
|
||||
assertion := NewAssertion("rs256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = rs256
|
||||
|
||||
token, err := assertionJWT.SignedString(keyECDSAP256)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The 'client_assertion' uses signing algorithm 'ES256' but the requested OAuth 2.0 Client enforces signing algorithm 'RS256'.")
|
||||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysRS256() {
|
||||
assertion := NewAssertion("rs256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = rs256
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("rs256k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS384() {
|
||||
assertion := NewAssertion("rs384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS384, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -542,12 +818,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysRS384() {
|
||||
assertion := NewAssertion("rs384k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS384, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "rs384"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("rs384k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS512() {
|
||||
assertion := NewAssertion("rs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS512, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -560,12 +870,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysRS512() {
|
||||
assertion := NewAssertion("rs512k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS512, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "rs512"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("rs512k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS256() {
|
||||
assertion := NewAssertion("ps256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS256, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -578,12 +922,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysPS256() {
|
||||
assertion := NewAssertion("ps256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "ps256"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("ps256k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS384() {
|
||||
assertion := NewAssertion("ps384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS384, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -596,12 +974,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysPS384() {
|
||||
assertion := NewAssertion("ps384k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS384, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "ps384"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("ps384k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS512() {
|
||||
assertion := NewAssertion("ps512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS512, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -614,12 +1026,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysPS512() {
|
||||
assertion := NewAssertion("ps512k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS512, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "ps512"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyRSA2048)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("ps512k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES256() {
|
||||
assertion := NewAssertion("es256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES256, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP256PrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyECDSAP256)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -632,12 +1078,47 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysES256() {
|
||||
assertion := NewAssertion("es256k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES256, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "es256"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyECDSAP256)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("es256k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES384() {
|
||||
assertion := NewAssertion("es384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES384, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP384PrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyECDSAP384)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -650,12 +1131,46 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysES384() {
|
||||
assertion := NewAssertion("es384k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES384, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "es384"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyECDSAP384)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("es384k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES512() {
|
||||
assertion := NewAssertion("es512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES512, assertion)
|
||||
|
||||
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP521PrivateKey))
|
||||
token, err := assertionJWT.SignedString(keyECDSAP521)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
@ -668,6 +1183,40 @@ func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKe
|
|||
s.Nil(client)
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldAuthKeysES512() {
|
||||
assertion := NewAssertion("es512k", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES512, assertion)
|
||||
assertionJWT.Header[oidc.JWTHeaderKeyIdentifier] = "es512"
|
||||
|
||||
token, err := assertionJWT.SignedString(keyECDSAP521)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual("", token)
|
||||
|
||||
r := s.GetAssertionRequest(token)
|
||||
|
||||
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
|
||||
|
||||
ctx := s.GetCtx()
|
||||
|
||||
gomock.InOrder(
|
||||
s.store.
|
||||
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
|
||||
Return(nil, sql.ErrNoRows),
|
||||
|
||||
s.store.
|
||||
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
|
||||
|
||||
s.NoError(err)
|
||||
s.Require().NotNil(client)
|
||||
|
||||
s.Equal("es512k", client.GetID())
|
||||
}
|
||||
|
||||
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnJTIKnown() {
|
||||
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
|
||||
|
||||
|
@ -1384,126 +1933,3 @@ func NewAssertion(clientID string, tokenURL *url.URL, iat, exp time.Time) Regist
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
type RFC6749ErrorTest struct {
|
||||
*fosite.RFC6749Error
|
||||
}
|
||||
|
||||
func (err *RFC6749ErrorTest) Error() string {
|
||||
return err.WithExposeDebug(true).GetDescription()
|
||||
}
|
||||
|
||||
func ErrorToRFC6749ErrorTest(err error) (rfc error) {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ferr := fosite.ErrorToRFC6749Error(err)
|
||||
|
||||
return &RFC6749ErrorTest{ferr}
|
||||
}
|
||||
|
||||
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
||||
if secret, err := schema.DecodePasswordDigest(value); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return secret
|
||||
}
|
||||
}
|
||||
|
||||
func MustParseRequestURI(input string) *url.URL {
|
||||
if requestURI, err := url.ParseRequestURI(input); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return requestURI
|
||||
}
|
||||
}
|
||||
|
||||
func MustParseRSAPrivateKey(data string) *rsa.PrivateKey {
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil || block.Bytes == nil || len(block.Bytes) == 0 {
|
||||
panic("not pem encoded")
|
||||
}
|
||||
|
||||
if block.Type != "RSA PRIVATE KEY" {
|
||||
panic("not private key")
|
||||
}
|
||||
|
||||
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
func MustParseECPrivateKey(data string) *ecdsa.PrivateKey {
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil || block.Bytes == nil || len(block.Bytes) == 0 {
|
||||
panic("not pem encoded")
|
||||
}
|
||||
|
||||
if block.Type != "EC PRIVATE KEY" {
|
||||
panic("not private key")
|
||||
}
|
||||
|
||||
key, err := x509.ParseECPrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
const exampleRSAPrivateKey = `
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA60Vuz1N1wUHiCDIlbz8gE0dWPCmHEWnXKchEEISqIJ6j5Eah
|
||||
Q/GwX3WK0UV5ATRvWhg6o7/WfrLYcAsi4w79TgMjJHLWIY/jzAS3quEtzOLlLSWZ
|
||||
9FR9SomQm3T/ETOS8IvSGrksIj0WgX35jB1NnbqSTRnYx7Cg/TBJjmiaqd0b9G/8
|
||||
LlReaihwGf8tvPgnteWIdon3EI2MKDBkaesRjpL98Cz7VvD7dajseAlUh9jQWVge
|
||||
sN8qnm8pNPFAYsgxf//Jf0RfsND6H70zKKybDmyct4T4o/8qjivw4ly0XkArDCUj
|
||||
Qx2KUF7nN+Bo9wwnNppjdnsOPUbus8o1a9vY1QIDAQABAoIBAQDl1SBY3PlN36SF
|
||||
yScUtCALdUbi4taVxkVxBbioQlFIKHGGkRD9JN/dgSApK6r36FdXNhAi40cQ4nnZ
|
||||
iqd8FKqTSTFNa/mPM9ee+ITMI8nwOz8SiYcKTndPF2/yzapXDYDgCFcpz/czQ2X2
|
||||
/i+IFyA5k4dUVomVGhFLBZ71xW5BvGUBMUH0XkeR5+c4gLvgR209BlpBHlkX4tUQ
|
||||
+RQoxbKpkntl0mjqf91zcOe4LJVsXZFyN+NVSzLEbGC3lVSSiyjVQH3s7ExnTaHi
|
||||
PpwSoXzu5QJj5xRit/1B3/LEGpIlPGFrkhMzBDTN+HYV/VLbCHJzjg5GVJawA82E
|
||||
h2BY6YWJAoGBAPmGaZL5ggnTVR2XVBLDKbwL/sesqiPZk45B+I5eObHl+v236JH9
|
||||
RPMjdE10jOR1TzfQdmE2/RboKhiVn+osS+2W6VXSo7sMsSM1bLBPYhnwrNIqzrX8
|
||||
Vgi2bCl2S8ZhVo2R8c5WUaD0Gpxs6hwPIMOQWWwxDlsbg/UoLrhD3X4XAoGBAPFg
|
||||
VSvaWQdDVAqjM42ObhZtWxeLfEAcxRQDMQq7btrTwBZSrtP3S3Egu66cp/4PT4VD
|
||||
Hc8tYyT2rNETiqT6b2Rm1MgeoJ8wRqte6ZXSQVVQUOd42VG04O3aaleAGhXjEkM2
|
||||
avctRdKHDhQdIt+riPgaNj4FdYpmQ5zIrcZtBr/zAoGBAOBXzBX7xMHmwxEe3NUd
|
||||
qSlMM579C9+9oF/3ymzeJMtgtcBmGHEhoFtmVgvJrV8+ZaIOCFExam2tASQnaqbV
|
||||
etK7q0ChaNok+CJqxzThupcN/6PaHw4aOJQOx8KjfE95dqNEQ367txqaPk7D0dy2
|
||||
cUPDRdLzbC/X1lWV8iNzyPGzAoGBAN4R2epRpYz4Fa7/vWNkAcaib6c2zmaR0YN6
|
||||
+Di+ftvW6yfehDhBkWgQTHv2ZtxoK6oYOKmuQUP1qsNkbi8gtTEzJlrDStWKbcom
|
||||
tVMAsNkT3otHdPEmL7bFNwcvtVAjrF6oBztHrLBnTr2UnMwZnhdczkC7dwuQ0G3D
|
||||
d5VSI16fAoGAY7eeVDkic73GbZmtZibuodvPJ/z85RIBOrzf3ColO4jGI6Ej/EnD
|
||||
rMEe/mRC27CJzS9L9Jc0Kt66mGSvodDGl0nBsXGNfPog0cGwweCVN0Eo2VJZbRTT
|
||||
UoU05/Pvu2h3/E8gGTBY0/WPSo06YUsICjVDWNuOIa/7IY7SyE6Xxn0=
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
const exampleECP256PrivateKey = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEID1fSsJ8qyEqj2DVkrshaNiXqaSDX7qViASRkyGGJFbEoAoGCCqGSM49
|
||||
AwEHoUQDQgAENnBG+bBJIaIa+bRlHaLiXD86RAy+Ef9CVdAfpPGoNRfkOTcrrIV7
|
||||
2wv3Y5e0he63Tn9iVAFYRFexK1mjFw7TfA==
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
const exampleECP384PrivateKey = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDBPoOfapxtgZ8XNE7Wwdlw+9oDc6x4m57MITZyWzN62jkFUAYsvPJDF
|
||||
9+g+e8CT5yqgBwYFK4EEACKhZANiAAQ2uZ0HIIxIavyjGyX13tIZVOaRB4+D64dF
|
||||
s3DXDrpXcuDTSohw9xBW5sLDqRVu2LkBsCUFXtEJUHgC+O7wToNw8nh+KdDrcu/J
|
||||
miNqbvEHuvlSlHWyx9HH8kAEuu1+SZg=
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
const exampleECP521PrivateKey = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIHcAgEBBEIBT07AnitDd1Z01bl5W5VW8/vTWyu7w3MSqEmCeKcM19p/TAJAeS8L
|
||||
6UOig2fTUeuMeA2PoOUjI2Bid927VsWcxE2gBwYFK4EEACOhgYkDgYYABAGnV9mu
|
||||
xY0E7/k8b+glOOMaN0+Qt70H9OmSz6tC8tU3EayRwFlNPch9TlvEpbCS3MsDE9dN
|
||||
78EpFx45MUqzzdZcOgAu+EUC9Zas1YVK+WMo0GFy+XtFq3kxubOclBb52M/63mcd
|
||||
zZnA8aAu9iTK9YPfcw1YWTJliNdKUoxmGVV5Ca1W4w==
|
||||
-----END EC PRIVATE KEY-----`
|
|
@ -46,12 +46,22 @@ func NewClient(config schema.OpenIDConnectClientConfiguration) (client Client) {
|
|||
base.ResponseModes = append(base.ResponseModes, fosite.ResponseModeType(mode))
|
||||
}
|
||||
|
||||
if config.TokenEndpointAuthMethod != "" && config.TokenEndpointAuthMethod != "auto" {
|
||||
client = &FullClient{
|
||||
if config.TokenEndpointAuthMethod != "" || config.TokenEndpointAuthSigningAlg != "" ||
|
||||
len(config.PublicKeys.Values) != 0 || config.PublicKeys.URI != nil || config.RequestObjectSigningAlg != "" {
|
||||
full := &FullClient{
|
||||
BaseClient: base,
|
||||
TokenEndpointAuthMethod: config.TokenEndpointAuthMethod,
|
||||
TokenEndpointAuthSigningAlgorithm: config.TokenEndpointAuthSigningAlg,
|
||||
RequestObjectSigningAlgorithm: config.RequestObjectSigningAlg,
|
||||
|
||||
JSONWebKeys: NewPublicJSONWebKeySetFromSchemaJWK(config.PublicKeys.Values),
|
||||
}
|
||||
|
||||
if config.PublicKeys.URI != nil {
|
||||
full.JSONWebKeysURI = config.PublicKeys.URI.String()
|
||||
}
|
||||
|
||||
client = full
|
||||
} else {
|
||||
client = base
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -14,30 +14,31 @@ import (
|
|||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/model"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
config := schema.OpenIDConnectClientConfiguration{}
|
||||
client := NewClient(config)
|
||||
client := oidc.NewClient(config)
|
||||
assert.Equal(t, "", client.GetID())
|
||||
assert.Equal(t, "", client.GetDescription())
|
||||
assert.Len(t, client.GetResponseModes(), 0)
|
||||
assert.Len(t, client.GetResponseTypes(), 1)
|
||||
assert.Equal(t, "", client.GetSectorIdentifier())
|
||||
|
||||
bclient, ok := client.(*BaseClient)
|
||||
bclient, ok := client.(*oidc.BaseClient)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "", bclient.UserinfoSigningAlg)
|
||||
assert.Equal(t, SigningAlgNone, client.GetUserinfoSigningAlg())
|
||||
assert.Equal(t, oidc.SigningAlgNone, client.GetUserinfoSigningAlg())
|
||||
|
||||
_, ok = client.(*FullClient)
|
||||
_, ok = client.(*oidc.FullClient)
|
||||
assert.False(t, ok)
|
||||
|
||||
config = schema.OpenIDConnectClientConfiguration{
|
||||
ID: myclient,
|
||||
Description: myclientdesc,
|
||||
Policy: twofactor,
|
||||
Secret: MustDecodeSecret(badsecret),
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
RedirectURIs: []string{examplecom},
|
||||
Scopes: schema.DefaultOpenIDConnectClientConfiguration.Scopes,
|
||||
ResponseTypes: schema.DefaultOpenIDConnectClientConfiguration.ResponseTypes,
|
||||
|
@ -45,44 +46,42 @@ func TestNewClient(t *testing.T) {
|
|||
ResponseModes: schema.DefaultOpenIDConnectClientConfiguration.ResponseModes,
|
||||
}
|
||||
|
||||
client = NewClient(config)
|
||||
client = oidc.NewClient(config)
|
||||
assert.Equal(t, myclient, client.GetID())
|
||||
require.Len(t, client.GetResponseModes(), 1)
|
||||
assert.Equal(t, fosite.ResponseModeFormPost, client.GetResponseModes()[0])
|
||||
assert.Equal(t, authorization.TwoFactor, client.GetAuthorizationPolicy())
|
||||
|
||||
config = schema.OpenIDConnectClientConfiguration{
|
||||
TokenEndpointAuthMethod: ClientAuthMethodClientSecretPost,
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
|
||||
}
|
||||
|
||||
client = NewClient(config)
|
||||
client = oidc.NewClient(config)
|
||||
|
||||
fclient, ok := client.(*FullClient)
|
||||
|
||||
var niljwks *jose.JSONWebKeySet
|
||||
fclient, ok := client.(*oidc.FullClient)
|
||||
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, "", fclient.UserinfoSigningAlg)
|
||||
assert.Equal(t, SigningAlgNone, client.GetUserinfoSigningAlg())
|
||||
assert.Equal(t, SigningAlgNone, fclient.UserinfoSigningAlg)
|
||||
assert.Equal(t, oidc.SigningAlgNone, client.GetUserinfoSigningAlg())
|
||||
assert.Equal(t, oidc.SigningAlgNone, fclient.UserinfoSigningAlg)
|
||||
|
||||
assert.Equal(t, "", fclient.IDTokenSigningAlg)
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, client.GetIDTokenSigningAlg())
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, fclient.IDTokenSigningAlg)
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, client.GetIDTokenSigningAlg())
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, fclient.IDTokenSigningAlg)
|
||||
|
||||
assert.Equal(t, ClientAuthMethodClientSecretPost, fclient.TokenEndpointAuthMethod)
|
||||
assert.Equal(t, ClientAuthMethodClientSecretPost, fclient.GetTokenEndpointAuthMethod())
|
||||
assert.Equal(t, oidc.ClientAuthMethodClientSecretPost, fclient.TokenEndpointAuthMethod)
|
||||
assert.Equal(t, oidc.ClientAuthMethodClientSecretPost, fclient.GetTokenEndpointAuthMethod())
|
||||
|
||||
assert.Equal(t, "", fclient.TokenEndpointAuthSigningAlgorithm)
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, fclient.GetTokenEndpointAuthSigningAlgorithm())
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, fclient.TokenEndpointAuthSigningAlgorithm)
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, fclient.GetTokenEndpointAuthSigningAlgorithm())
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, fclient.TokenEndpointAuthSigningAlgorithm)
|
||||
|
||||
assert.Equal(t, "", fclient.RequestObjectSigningAlgorithm)
|
||||
assert.Equal(t, "", fclient.GetRequestObjectSigningAlgorithm())
|
||||
|
||||
fclient.RequestObjectSigningAlgorithm = SigningAlgRSAUsingSHA256
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, fclient.GetRequestObjectSigningAlgorithm())
|
||||
fclient.RequestObjectSigningAlgorithm = oidc.SigningAlgRSAUsingSHA256
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, fclient.GetRequestObjectSigningAlgorithm())
|
||||
|
||||
assert.Equal(t, "", fclient.JSONWebKeysURI)
|
||||
assert.Equal(t, "", fclient.GetJSONWebKeysURI())
|
||||
|
@ -90,22 +89,24 @@ func TestNewClient(t *testing.T) {
|
|||
fclient.JSONWebKeysURI = "https://example.com"
|
||||
assert.Equal(t, "https://example.com", fclient.GetJSONWebKeysURI())
|
||||
|
||||
var niljwks *jose.JSONWebKeySet
|
||||
|
||||
assert.Equal(t, niljwks, fclient.JSONWebKeys)
|
||||
assert.Equal(t, niljwks, fclient.GetJSONWebKeys())
|
||||
|
||||
assert.Equal(t, ClientConsentMode(0), fclient.Consent.Mode)
|
||||
assert.Equal(t, oidc.ClientConsentMode(0), fclient.Consent.Mode)
|
||||
assert.Equal(t, time.Second*0, fclient.Consent.Duration)
|
||||
assert.Equal(t, ClientConsent{Mode: ClientConsentModeExplicit}, fclient.GetConsentPolicy())
|
||||
assert.Equal(t, oidc.ClientConsent{Mode: oidc.ClientConsentModeExplicit}, fclient.GetConsentPolicy())
|
||||
|
||||
fclient.TokenEndpointAuthMethod = ""
|
||||
fclient.Public = false
|
||||
assert.Equal(t, ClientAuthMethodClientSecretBasic, fclient.GetTokenEndpointAuthMethod())
|
||||
assert.Equal(t, ClientAuthMethodClientSecretBasic, fclient.TokenEndpointAuthMethod)
|
||||
assert.Equal(t, oidc.ClientAuthMethodClientSecretBasic, fclient.GetTokenEndpointAuthMethod())
|
||||
assert.Equal(t, oidc.ClientAuthMethodClientSecretBasic, fclient.TokenEndpointAuthMethod)
|
||||
|
||||
fclient.TokenEndpointAuthMethod = ""
|
||||
fclient.Public = true
|
||||
assert.Equal(t, ClientAuthMethodNone, fclient.GetTokenEndpointAuthMethod())
|
||||
assert.Equal(t, ClientAuthMethodNone, fclient.TokenEndpointAuthMethod)
|
||||
assert.Equal(t, oidc.ClientAuthMethodNone, fclient.GetTokenEndpointAuthMethod())
|
||||
assert.Equal(t, oidc.ClientAuthMethodNone, fclient.TokenEndpointAuthMethod)
|
||||
|
||||
assert.Equal(t, []string(nil), fclient.RequestURIs)
|
||||
assert.Equal(t, []string(nil), fclient.GetRequestURIs())
|
||||
|
@ -114,13 +115,13 @@ func TestNewClient(t *testing.T) {
|
|||
func TestBaseClient_ValidatePARPolicy(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
client *BaseClient
|
||||
client *oidc.BaseClient
|
||||
have *fosite.Request
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"ShouldNotEnforcePAR",
|
||||
&BaseClient{
|
||||
&oidc.BaseClient{
|
||||
EnforcePAR: false,
|
||||
},
|
||||
&fosite.Request{},
|
||||
|
@ -128,36 +129,36 @@ func TestBaseClient_ValidatePARPolicy(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"ShouldEnforcePARAndErrorWithoutCorrectRequestURI",
|
||||
&BaseClient{
|
||||
&oidc.BaseClient{
|
||||
EnforcePAR: true,
|
||||
},
|
||||
&fosite.Request{
|
||||
Form: map[string][]string{
|
||||
FormParameterRequestURI: {"https://google.com"},
|
||||
oidc.FormParameterRequestURI: {"https://google.com"},
|
||||
},
|
||||
},
|
||||
"invalid_request",
|
||||
},
|
||||
{
|
||||
"ShouldEnforcePARAndErrorWithEmptyRequestURI",
|
||||
&BaseClient{
|
||||
&oidc.BaseClient{
|
||||
EnforcePAR: true,
|
||||
},
|
||||
&fosite.Request{
|
||||
Form: map[string][]string{
|
||||
FormParameterRequestURI: {""},
|
||||
oidc.FormParameterRequestURI: {""},
|
||||
},
|
||||
},
|
||||
"invalid_request",
|
||||
},
|
||||
{
|
||||
"ShouldEnforcePARAndNotErrorWithCorrectRequestURI",
|
||||
&BaseClient{
|
||||
&oidc.BaseClient{
|
||||
EnforcePAR: true,
|
||||
},
|
||||
&fosite.Request{
|
||||
Form: map[string][]string{
|
||||
FormParameterRequestURI: {urnPARPrefix + "abc"},
|
||||
oidc.FormParameterRequestURI: {oidc.RedirectURIPrefixPushedAuthorizationRequestURN + "abc"},
|
||||
},
|
||||
},
|
||||
"",
|
||||
|
@ -166,7 +167,7 @@ func TestBaseClient_ValidatePARPolicy(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.client.ValidatePARPolicy(tc.have, urnPARPrefix)
|
||||
err := tc.client.ValidatePARPolicy(tc.have, oidc.RedirectURIPrefixPushedAuthorizationRequestURN)
|
||||
|
||||
switch tc.expected {
|
||||
case "":
|
||||
|
@ -179,7 +180,7 @@ func TestBaseClient_ValidatePARPolicy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsAuthenticationLevelSufficient(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
c.Policy = authorization.Bypass
|
||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
||||
|
@ -203,7 +204,7 @@ func TestIsAuthenticationLevelSufficient(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetConsentResponseBody(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
consentRequestBody := c.GetConsentResponseBody(nil)
|
||||
assert.Equal(t, "", consentRequestBody.ClientID)
|
||||
|
@ -216,10 +217,10 @@ func TestClient_GetConsentResponseBody(t *testing.T) {
|
|||
|
||||
consent := &model.OAuth2ConsentSession{
|
||||
RequestedAudience: []string{examplecom},
|
||||
RequestedScopes: []string{ScopeOpenID, ScopeGroups},
|
||||
RequestedScopes: []string{oidc.ScopeOpenID, oidc.ScopeGroups},
|
||||
}
|
||||
|
||||
expectedScopes := []string{ScopeOpenID, ScopeGroups}
|
||||
expectedScopes := []string{oidc.ScopeOpenID, oidc.ScopeGroups}
|
||||
expectedAudiences := []string{examplecom}
|
||||
|
||||
consentRequestBody = c.GetConsentResponseBody(consent)
|
||||
|
@ -230,7 +231,7 @@ func TestClient_GetConsentResponseBody(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetAudience(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
audience := c.GetAudience()
|
||||
assert.Len(t, audience, 0)
|
||||
|
@ -243,24 +244,24 @@ func TestClient_GetAudience(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetScopes(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
scopes := c.GetScopes()
|
||||
assert.Len(t, scopes, 0)
|
||||
|
||||
c.Scopes = []string{ScopeOpenID}
|
||||
c.Scopes = []string{oidc.ScopeOpenID}
|
||||
|
||||
scopes = c.GetScopes()
|
||||
require.Len(t, scopes, 1)
|
||||
assert.Equal(t, ScopeOpenID, scopes[0])
|
||||
assert.Equal(t, oidc.ScopeOpenID, scopes[0])
|
||||
}
|
||||
|
||||
func TestClient_GetGrantTypes(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
grantTypes := c.GetGrantTypes()
|
||||
require.Len(t, grantTypes, 1)
|
||||
assert.Equal(t, GrantTypeAuthorizationCode, grantTypes[0])
|
||||
assert.Equal(t, oidc.GrantTypeAuthorizationCode, grantTypes[0])
|
||||
|
||||
c.GrantTypes = []string{"device_code"}
|
||||
|
||||
|
@ -270,30 +271,30 @@ func TestClient_GetGrantTypes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_Hashing(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
hashedSecret := c.GetHashedSecret()
|
||||
assert.Equal(t, []byte(nil), hashedSecret)
|
||||
|
||||
c.Secret = MustDecodeSecret(badsecret)
|
||||
c.Secret = tOpenIDConnectPlainTextClientSecret
|
||||
|
||||
assert.True(t, c.Secret.MatchBytes([]byte("a_bad_secret")))
|
||||
assert.True(t, c.Secret.MatchBytes([]byte("client-secret")))
|
||||
}
|
||||
|
||||
func TestClient_GetHashedSecret(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
hashedSecret := c.GetHashedSecret()
|
||||
assert.Equal(t, []byte(nil), hashedSecret)
|
||||
|
||||
c.Secret = MustDecodeSecret(badsecret)
|
||||
c.Secret = tOpenIDConnectPlainTextClientSecret
|
||||
|
||||
hashedSecret = c.GetHashedSecret()
|
||||
assert.Equal(t, []byte(badsecret), hashedSecret)
|
||||
assert.Equal(t, []byte("$plaintext$client-secret"), hashedSecret)
|
||||
}
|
||||
|
||||
func TestClient_GetID(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
id := c.GetID()
|
||||
assert.Equal(t, "", id)
|
||||
|
@ -305,7 +306,7 @@ func TestClient_GetID(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetRedirectURIs(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
redirectURIs := c.GetRedirectURIs()
|
||||
require.Len(t, redirectURIs, 0)
|
||||
|
@ -318,7 +319,7 @@ func TestClient_GetRedirectURIs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetResponseModes(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
responseModes := c.GetResponseModes()
|
||||
require.Len(t, responseModes, 0)
|
||||
|
@ -337,18 +338,18 @@ func TestClient_GetResponseModes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_GetResponseTypes(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
responseTypes := c.GetResponseTypes()
|
||||
require.Len(t, responseTypes, 1)
|
||||
assert.Equal(t, ResponseTypeAuthorizationCodeFlow, responseTypes[0])
|
||||
assert.Equal(t, oidc.ResponseTypeAuthorizationCodeFlow, responseTypes[0])
|
||||
|
||||
c.ResponseTypes = []string{ResponseTypeAuthorizationCodeFlow, ResponseTypeImplicitFlowIDToken}
|
||||
c.ResponseTypes = []string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowIDToken}
|
||||
|
||||
responseTypes = c.GetResponseTypes()
|
||||
require.Len(t, responseTypes, 2)
|
||||
assert.Equal(t, ResponseTypeAuthorizationCodeFlow, responseTypes[0])
|
||||
assert.Equal(t, ResponseTypeImplicitFlowIDToken, responseTypes[1])
|
||||
assert.Equal(t, oidc.ResponseTypeAuthorizationCodeFlow, responseTypes[0])
|
||||
assert.Equal(t, oidc.ResponseTypeImplicitFlowIDToken, responseTypes[1])
|
||||
}
|
||||
|
||||
func TestNewClientPKCE(t *testing.T) {
|
||||
|
@ -423,7 +424,7 @@ func TestNewClientPKCE(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := NewClient(tc.have)
|
||||
client := oidc.NewClient(tc.have)
|
||||
|
||||
assert.Equal(t, tc.expectedEnforcePKCE, client.GetPKCEEnforcement())
|
||||
assert.Equal(t, tc.expectedEnforcePKCEChallengeMethod, client.GetPKCEChallengeMethodEnforcement())
|
||||
|
@ -473,14 +474,14 @@ func TestNewClientPAR(t *testing.T) {
|
|||
"ShouldEnforcePARAndErrorOnNonPARRequest",
|
||||
schema.OpenIDConnectClientConfiguration{EnforcePAR: true},
|
||||
true,
|
||||
&fosite.Request{Form: map[string][]string{FormParameterRequestURI: {"https://example.com"}}},
|
||||
&fosite.Request{Form: map[string][]string{oidc.FormParameterRequestURI: {"https://example.com"}}},
|
||||
"invalid_request",
|
||||
"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Pushed Authorization Requests are enforced for this client but no such request was sent. The request_uri parameter 'https://example.com' is malformed."},
|
||||
{
|
||||
"ShouldEnforcePARAndNotErrorOnPARRequest",
|
||||
schema.OpenIDConnectClientConfiguration{EnforcePAR: true},
|
||||
true,
|
||||
&fosite.Request{Form: map[string][]string{FormParameterRequestURI: {fmt.Sprintf("%sabc", urnPARPrefix)}}},
|
||||
&fosite.Request{Form: map[string][]string{oidc.FormParameterRequestURI: {fmt.Sprintf("%sabc", oidc.RedirectURIPrefixPushedAuthorizationRequestURN)}}},
|
||||
"",
|
||||
"",
|
||||
},
|
||||
|
@ -488,12 +489,12 @@ func TestNewClientPAR(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := NewClient(tc.have)
|
||||
client := oidc.NewClient(tc.have)
|
||||
|
||||
assert.Equal(t, tc.expected, client.GetPAREnforcement())
|
||||
|
||||
if tc.r != nil {
|
||||
err := client.ValidatePARPolicy(tc.r, urnPARPrefix)
|
||||
err := client.ValidatePARPolicy(tc.r, oidc.RedirectURIPrefixPushedAuthorizationRequestURN)
|
||||
|
||||
if tc.err != "" {
|
||||
require.NotNil(t, err)
|
||||
|
@ -518,25 +519,25 @@ func TestNewClientResponseModes(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
"ShouldEnforceResponseModePolicyAndAllowDefaultModeQuery",
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{ResponseModeQuery}},
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{oidc.ResponseModeQuery}},
|
||||
[]fosite.ResponseModeType{fosite.ResponseModeQuery},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{FormParameterResponseMode: nil}}},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{oidc.FormParameterResponseMode: nil}}},
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"ShouldEnforceResponseModePolicyAndFailOnDefaultMode",
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{ResponseModeFormPost}},
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{oidc.ResponseModeFormPost}},
|
||||
[]fosite.ResponseModeType{fosite.ResponseModeFormPost},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{FormParameterResponseMode: nil}}},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{oidc.FormParameterResponseMode: nil}}},
|
||||
"unsupported_response_mode",
|
||||
"The authorization server does not support obtaining a response using this response mode. The request omitted the response_mode making the default response_mode 'query' based on the other authorization request parameters but registered OAuth 2.0 client doesn't support this response_mode",
|
||||
},
|
||||
{
|
||||
"ShouldNotEnforceConfiguredResponseMode",
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{ResponseModeFormPost}},
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{oidc.ResponseModeFormPost}},
|
||||
[]fosite.ResponseModeType{fosite.ResponseModeFormPost},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeQuery, Request: fosite.Request{Form: map[string][]string{FormParameterResponseMode: {ResponseModeQuery}}}},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeQuery, Request: fosite.Request{Form: map[string][]string{oidc.FormParameterResponseMode: {oidc.ResponseModeQuery}}}},
|
||||
"",
|
||||
"",
|
||||
},
|
||||
|
@ -544,7 +545,7 @@ func TestNewClientResponseModes(t *testing.T) {
|
|||
"ShouldNotEnforceUnconfiguredResponseMode",
|
||||
schema.OpenIDConnectClientConfiguration{ResponseModes: []string{}},
|
||||
[]fosite.ResponseModeType{},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{FormParameterResponseMode: {ResponseModeQuery}}}},
|
||||
&fosite.AuthorizeRequest{DefaultResponseMode: fosite.ResponseModeQuery, ResponseMode: fosite.ResponseModeDefault, Request: fosite.Request{Form: map[string][]string{oidc.FormParameterResponseMode: {oidc.ResponseModeQuery}}}},
|
||||
"",
|
||||
"",
|
||||
},
|
||||
|
@ -552,7 +553,7 @@ func TestNewClientResponseModes(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := NewClient(tc.have)
|
||||
client := oidc.NewClient(tc.have)
|
||||
|
||||
assert.Equal(t, tc.expected, client.GetResponseModes())
|
||||
|
||||
|
@ -572,10 +573,48 @@ func TestNewClientResponseModes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClient_IsPublic(t *testing.T) {
|
||||
c := &FullClient{BaseClient: &BaseClient{}}
|
||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||
|
||||
assert.False(t, c.IsPublic())
|
||||
|
||||
c.Public = true
|
||||
assert.True(t, c.IsPublic())
|
||||
}
|
||||
|
||||
func TestNewClient_JSONWebKeySetURI(t *testing.T) {
|
||||
var (
|
||||
client oidc.Client
|
||||
clientf *oidc.FullClient
|
||||
ok bool
|
||||
)
|
||||
|
||||
client = oidc.NewClient(schema.OpenIDConnectClientConfiguration{
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
URI: MustParseRequestURI("https://google.com"),
|
||||
},
|
||||
})
|
||||
|
||||
require.NotNil(t, client)
|
||||
|
||||
clientf, ok = client.(*oidc.FullClient)
|
||||
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, "https://google.com", clientf.GetJSONWebKeysURI())
|
||||
|
||||
client = oidc.NewClient(schema.OpenIDConnectClientConfiguration{
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
|
||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||
URI: nil,
|
||||
},
|
||||
})
|
||||
|
||||
require.NotNil(t, client)
|
||||
|
||||
clientf, ok = client.(*oidc.FullClient)
|
||||
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, "", clientf.GetJSONWebKeysURI())
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"hash"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
|
@ -43,7 +42,7 @@ func NewConfig(config *schema.OpenIDConnectConfiguration, templates *templates.P
|
|||
PAR: PARConfig{
|
||||
Enforced: config.PAR.Enforce,
|
||||
ContextLifespan: config.PAR.ContextLifespan,
|
||||
URIPrefix: urnPARPrefix,
|
||||
URIPrefix: RedirectURIPrefixPushedAuthorizationRequestURN,
|
||||
},
|
||||
Templates: templates,
|
||||
}
|
||||
|
@ -91,7 +90,6 @@ type Config struct {
|
|||
RefreshTokenScopes []string
|
||||
|
||||
HTTPClient *retryablehttp.Client
|
||||
FormPostHTMLTemplate *template.Template
|
||||
MessageCatalog i18n.MessageCatalog
|
||||
|
||||
Templates *templates.Provider
|
||||
|
@ -386,8 +384,8 @@ func (c *Config) GetDisableRefreshTokenValidation(ctx context.Context) (disable
|
|||
|
||||
// GetAuthorizeCodeLifespan returns the authorization code lifespan.
|
||||
func (c *Config) GetAuthorizeCodeLifespan(ctx context.Context) (lifespan time.Duration) {
|
||||
if c.Lifespans.AuthorizeCode <= 0 {
|
||||
c.Lifespans.AccessToken = lifespanAuthorizeCodeDefault
|
||||
if c.Lifespans.AuthorizeCode.Seconds() <= 0 {
|
||||
c.Lifespans.AuthorizeCode = lifespanAuthorizeCodeDefault
|
||||
}
|
||||
|
||||
return c.Lifespans.AuthorizeCode
|
||||
|
@ -395,8 +393,8 @@ func (c *Config) GetAuthorizeCodeLifespan(ctx context.Context) (lifespan time.Du
|
|||
|
||||
// GetRefreshTokenLifespan returns the refresh token lifespan.
|
||||
func (c *Config) GetRefreshTokenLifespan(ctx context.Context) (lifespan time.Duration) {
|
||||
if c.Lifespans.RefreshToken <= 0 {
|
||||
c.Lifespans.AccessToken = lifespanRefreshTokenDefault
|
||||
if c.Lifespans.RefreshToken.Seconds() <= 0 {
|
||||
c.Lifespans.RefreshToken = lifespanRefreshTokenDefault
|
||||
}
|
||||
|
||||
return c.Lifespans.RefreshToken
|
||||
|
@ -404,8 +402,8 @@ func (c *Config) GetRefreshTokenLifespan(ctx context.Context) (lifespan time.Dur
|
|||
|
||||
// GetIDTokenLifespan returns the ID token lifespan.
|
||||
func (c *Config) GetIDTokenLifespan(ctx context.Context) (lifespan time.Duration) {
|
||||
if c.Lifespans.IDToken <= 0 {
|
||||
c.Lifespans.AccessToken = lifespanTokenDefault
|
||||
if c.Lifespans.IDToken.Seconds() <= 0 {
|
||||
c.Lifespans.IDToken = lifespanTokenDefault
|
||||
}
|
||||
|
||||
return c.Lifespans.IDToken
|
||||
|
@ -413,7 +411,7 @@ func (c *Config) GetIDTokenLifespan(ctx context.Context) (lifespan time.Duration
|
|||
|
||||
// GetAccessTokenLifespan returns the access token lifespan.
|
||||
func (c *Config) GetAccessTokenLifespan(ctx context.Context) (lifespan time.Duration) {
|
||||
if c.Lifespans.AccessToken <= 0 {
|
||||
if c.Lifespans.AccessToken.Seconds() <= 0 {
|
||||
c.Lifespans.AccessToken = lifespanTokenDefault
|
||||
}
|
||||
|
||||
|
@ -528,15 +526,13 @@ func (c *Config) GetFormPostHTMLTemplate(ctx context.Context) (tmpl *template.Te
|
|||
|
||||
// GetTokenURL returns the token URL.
|
||||
func (c *Config) GetTokenURL(ctx context.Context) (tokenURL string) {
|
||||
if ctx, ok := ctx.(OpenIDConnectContext); ok {
|
||||
tokenURI, err := ctx.IssuerURL()
|
||||
if err != nil {
|
||||
if octx, ok := ctx.(OpenIDConnectContext); ok {
|
||||
switch issuerURL, err := octx.IssuerURL(); err {
|
||||
case nil:
|
||||
return issuerURL.JoinPath(EndpointPathToken).String()
|
||||
default:
|
||||
return c.TokenURL
|
||||
}
|
||||
|
||||
tokenURI.Path = path.Join(tokenURI.Path, EndpointPathToken)
|
||||
|
||||
return tokenURI.String()
|
||||
}
|
||||
|
||||
return c.TokenURL
|
||||
|
@ -592,7 +588,7 @@ func (c *Config) GetResponseModeHandlerExtension(ctx context.Context) (handler f
|
|||
// usually 'urn:ietf:params:oauth:request_uri:'.
|
||||
func (c *Config) GetPushedAuthorizeRequestURIPrefix(ctx context.Context) string {
|
||||
if c.PAR.URIPrefix == "" {
|
||||
c.PAR.URIPrefix = urnPARPrefix
|
||||
c.PAR.URIPrefix = RedirectURIPrefixPushedAuthorizationRequestURN
|
||||
}
|
||||
|
||||
return c.PAR.URIPrefix
|
||||
|
@ -607,7 +603,7 @@ func (c *Config) EnforcePushedAuthorize(ctx context.Context) bool {
|
|||
|
||||
// GetPushedAuthorizeContextLifespan is the lifespan of the short-lived PAR context.
|
||||
func (c *Config) GetPushedAuthorizeContextLifespan(ctx context.Context) (lifespan time.Duration) {
|
||||
if c.PAR.ContextLifespan.Seconds() == 0 {
|
||||
if c.PAR.ContextLifespan.Seconds() <= 0 {
|
||||
c.PAR.ContextLifespan = lifespanPARContextDefault
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite/token/jwt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
"github.com/authelia/authelia/v4/internal/templates"
|
||||
)
|
||||
|
||||
func TestConfig_GetAllowedPrompts(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
|
||||
assert.Equal(t, []string(nil), config.AllowedPrompts)
|
||||
assert.Equal(t, []string{oidc.PromptNone, oidc.PromptLogin, oidc.PromptConsent}, config.GetAllowedPrompts(ctx))
|
||||
assert.Equal(t, []string{oidc.PromptNone, oidc.PromptLogin, oidc.PromptConsent}, config.AllowedPrompts)
|
||||
|
||||
config.AllowedPrompts = []string{oidc.PromptNone}
|
||||
assert.Equal(t, []string{oidc.PromptNone}, config.AllowedPrompts)
|
||||
}
|
||||
|
||||
func TestConfig_PKCE(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
|
||||
assert.False(t, config.GetEnforcePKCE(ctx))
|
||||
assert.False(t, config.GetEnforcePKCEForPublicClients(ctx))
|
||||
|
||||
config.ProofKeyCodeExchange.Enforce = true
|
||||
assert.True(t, config.GetEnforcePKCE(ctx))
|
||||
assert.True(t, config.GetEnforcePKCEForPublicClients(ctx))
|
||||
|
||||
config.ProofKeyCodeExchange.Enforce = false
|
||||
|
||||
assert.False(t, config.GetEnforcePKCEForPublicClients(ctx))
|
||||
|
||||
config.ProofKeyCodeExchange.EnforcePublicClients = true
|
||||
|
||||
assert.True(t, config.GetEnforcePKCEForPublicClients(ctx))
|
||||
|
||||
assert.False(t, config.GetEnablePKCEPlainChallengeMethod(ctx))
|
||||
config.ProofKeyCodeExchange.AllowPlainChallengeMethod = true
|
||||
|
||||
assert.True(t, config.GetEnablePKCEPlainChallengeMethod(ctx))
|
||||
}
|
||||
|
||||
func TestConfig_GrantTypeJWTBearer(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
assert.False(t, config.GetGrantTypeJWTBearerIDOptional(ctx))
|
||||
assert.False(t, config.GetGrantTypeJWTBearerCanSkipClientAuth(ctx))
|
||||
assert.False(t, config.GetGrantTypeJWTBearerIssuedDateOptional(ctx))
|
||||
|
||||
config.GrantTypeJWTBearer.OptionalJTIClaim = true
|
||||
assert.True(t, config.GetGrantTypeJWTBearerIDOptional(ctx))
|
||||
assert.False(t, config.GetGrantTypeJWTBearerCanSkipClientAuth(ctx))
|
||||
assert.False(t, config.GetGrantTypeJWTBearerIssuedDateOptional(ctx))
|
||||
|
||||
config.GrantTypeJWTBearer.OptionalClientAuth = true
|
||||
assert.True(t, config.GetGrantTypeJWTBearerIDOptional(ctx))
|
||||
assert.True(t, config.GetGrantTypeJWTBearerCanSkipClientAuth(ctx))
|
||||
assert.False(t, config.GetGrantTypeJWTBearerIssuedDateOptional(ctx))
|
||||
|
||||
config.GrantTypeJWTBearer.OptionalIssuedDate = true
|
||||
assert.True(t, config.GetGrantTypeJWTBearerIDOptional(ctx))
|
||||
assert.True(t, config.GetGrantTypeJWTBearerCanSkipClientAuth(ctx))
|
||||
assert.True(t, config.GetGrantTypeJWTBearerIssuedDateOptional(ctx))
|
||||
}
|
||||
|
||||
func TestConfig_Durations(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
assert.Equal(t, time.Duration(0), config.JWTMaxDuration)
|
||||
assert.Equal(t, time.Hour*24, config.GetJWTMaxDuration(ctx))
|
||||
assert.Equal(t, time.Hour*24, config.JWTMaxDuration)
|
||||
|
||||
assert.Equal(t, time.Duration(0), config.Lifespans.IDToken)
|
||||
assert.Equal(t, time.Hour, config.GetIDTokenLifespan(ctx))
|
||||
assert.Equal(t, time.Hour, config.Lifespans.IDToken)
|
||||
|
||||
assert.Equal(t, time.Duration(0), config.Lifespans.AccessToken)
|
||||
assert.Equal(t, time.Hour, config.GetAccessTokenLifespan(ctx))
|
||||
assert.Equal(t, time.Hour, config.Lifespans.AccessToken)
|
||||
|
||||
assert.Equal(t, time.Duration(0), config.Lifespans.RefreshToken)
|
||||
assert.Equal(t, time.Hour*24*30, config.GetRefreshTokenLifespan(ctx))
|
||||
assert.Equal(t, time.Hour*24*30, config.Lifespans.RefreshToken)
|
||||
|
||||
assert.Equal(t, time.Duration(0), config.Lifespans.AuthorizeCode)
|
||||
assert.Equal(t, time.Minute*15, config.GetAuthorizeCodeLifespan(ctx))
|
||||
assert.Equal(t, time.Minute*15, config.Lifespans.AuthorizeCode)
|
||||
}
|
||||
|
||||
func TestConfig_GetTokenEntropy(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
|
||||
assert.Equal(t, 0, config.TokenEntropy)
|
||||
assert.Equal(t, 32, config.GetTokenEntropy(ctx))
|
||||
assert.Equal(t, 32, config.TokenEntropy)
|
||||
}
|
||||
|
||||
func TestConfig_Misc(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
|
||||
assert.False(t, config.DisableRefreshTokenValidation)
|
||||
assert.False(t, config.GetDisableRefreshTokenValidation(ctx))
|
||||
|
||||
assert.Equal(t, "", config.Issuers.AccessToken)
|
||||
assert.Equal(t, "", config.GetAccessTokenIssuer(ctx))
|
||||
|
||||
assert.Equal(t, "", config.Issuers.IDToken)
|
||||
assert.Equal(t, "", config.GetIDTokenIssuer(ctx))
|
||||
|
||||
assert.Equal(t, jwt.JWTScopeFieldUnset, config.JWTScopeField)
|
||||
assert.Equal(t, jwt.JWTScopeFieldList, config.GetJWTScopeField(ctx))
|
||||
assert.Equal(t, jwt.JWTScopeFieldList, config.JWTScopeField)
|
||||
|
||||
assert.Equal(t, []string(nil), config.SanitationWhiteList)
|
||||
assert.Equal(t, []string(nil), config.GetSanitationWhiteList(ctx))
|
||||
assert.Equal(t, []string(nil), config.SanitationWhiteList)
|
||||
|
||||
assert.False(t, config.OmitRedirectScopeParameter)
|
||||
assert.False(t, config.GetOmitRedirectScopeParam(ctx))
|
||||
|
||||
assert.NotNil(t, config.GetRedirectSecureChecker(ctx))
|
||||
assert.NotNil(t, config.GetHTTPClient(ctx))
|
||||
|
||||
assert.Nil(t, config.Strategy.Scope)
|
||||
assert.NotNil(t, config.GetScopeStrategy(ctx))
|
||||
assert.NotNil(t, config.Strategy.Scope)
|
||||
|
||||
assert.Nil(t, config.Strategy.Audience)
|
||||
assert.NotNil(t, config.GetAudienceStrategy(ctx))
|
||||
assert.NotNil(t, config.Strategy.Audience)
|
||||
|
||||
assert.Equal(t, []string(nil), config.RefreshTokenScopes)
|
||||
assert.Equal(t, []string{oidc.ScopeOffline, oidc.ScopeOfflineAccess}, config.GetRefreshTokenScopes(ctx))
|
||||
assert.Equal(t, []string{oidc.ScopeOffline, oidc.ScopeOfflineAccess}, config.RefreshTokenScopes)
|
||||
|
||||
assert.Equal(t, 0, config.MinParameterEntropy)
|
||||
assert.Equal(t, 8, config.GetMinParameterEntropy(ctx))
|
||||
assert.Equal(t, 8, config.MinParameterEntropy)
|
||||
|
||||
assert.False(t, config.SendDebugMessagesToClients)
|
||||
assert.False(t, config.GetSendDebugMessagesToClients(ctx))
|
||||
|
||||
config.SendDebugMessagesToClients = true
|
||||
|
||||
assert.True(t, config.GetSendDebugMessagesToClients(ctx))
|
||||
|
||||
assert.Nil(t, config.Strategy.JWKSFetcher)
|
||||
assert.NotNil(t, config.GetJWKSFetcherStrategy(ctx))
|
||||
assert.NotNil(t, config.Strategy.JWKSFetcher)
|
||||
|
||||
assert.Nil(t, config.Strategy.ClientAuthentication)
|
||||
assert.Nil(t, config.GetClientAuthenticationStrategy(ctx))
|
||||
|
||||
assert.Nil(t, config.MessageCatalog)
|
||||
assert.Nil(t, config.GetMessageCatalog(ctx))
|
||||
|
||||
assert.Nil(t, config.Templates)
|
||||
assert.Nil(t, config.GetFormPostHTMLTemplate(ctx))
|
||||
|
||||
var err error
|
||||
|
||||
config.Templates, err = templates.New(templates.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, config.GetFormPostHTMLTemplate(ctx))
|
||||
assert.NotNil(t, config.Templates)
|
||||
|
||||
assert.False(t, config.GetUseLegacyErrorFormat(ctx))
|
||||
|
||||
assert.Nil(t, config.GetAuthorizeEndpointHandlers(ctx))
|
||||
assert.Nil(t, config.GetTokenEndpointHandlers(ctx))
|
||||
assert.Nil(t, config.GetTokenIntrospectionHandlers(ctx))
|
||||
assert.Nil(t, config.GetRevocationHandlers(ctx))
|
||||
assert.Nil(t, config.GetPushedAuthorizeEndpointHandlers(ctx))
|
||||
assert.Nil(t, config.GetResponseModeHandlerExtension(ctx))
|
||||
|
||||
assert.Equal(t, "", config.GetTokenURL(ctx))
|
||||
|
||||
octx := &MockOpenIDConnectContext{
|
||||
Context: ctx,
|
||||
IssuerURLFunc: func() (issuerURL *url.URL, err error) {
|
||||
return nil, fmt.Errorf("test error")
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, "", config.GetTokenURL(octx))
|
||||
}
|
||||
|
||||
func TestConfig_PAR(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config := &oidc.Config{}
|
||||
|
||||
assert.Equal(t, "", config.PAR.URIPrefix)
|
||||
assert.Equal(t, "urn:ietf:params:oauth:request_uri:", config.GetPushedAuthorizeRequestURIPrefix(ctx))
|
||||
assert.Equal(t, "urn:ietf:params:oauth:request_uri:", config.PAR.URIPrefix)
|
||||
|
||||
assert.False(t, config.PAR.Enforced)
|
||||
assert.False(t, config.EnforcePushedAuthorize(ctx))
|
||||
assert.False(t, config.PAR.Enforced)
|
||||
|
||||
config.PAR.Enforced = true
|
||||
|
||||
assert.True(t, config.EnforcePushedAuthorize(ctx))
|
||||
|
||||
assert.Equal(t, time.Duration(0), config.PAR.ContextLifespan)
|
||||
assert.Equal(t, time.Minute*5, config.GetPushedAuthorizeContextLifespan(ctx))
|
||||
assert.Equal(t, time.Minute*5, config.PAR.ContextLifespan)
|
||||
}
|
|
@ -53,7 +53,7 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
urnPARPrefix = "urn:ietf:params:oauth:request_uri:"
|
||||
RedirectURIPrefixPushedAuthorizationRequestURN = "urn:ietf:params:oauth:request_uri:"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -175,9 +175,9 @@ const (
|
|||
tokenPrefixOrgAutheliaFmt = "authelia_%s_" //nolint:gosec
|
||||
tokenPrefixOrgOryFmt = "ory_%s_" //nolint:gosec
|
||||
|
||||
tokenPrefixPartAccessToken = "at"
|
||||
tokenPrefixPartRefreshToken = "rt"
|
||||
tokenPrefixPartAuthorizeCode = "ac"
|
||||
TokenPrefixPartAccessToken = "at"
|
||||
TokenPrefixPartRefreshToken = "rt"
|
||||
TokenPrefixPartAuthorizeCode = "ac"
|
||||
)
|
||||
|
||||
// Paths.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
@ -10,6 +9,8 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/utils"
|
||||
)
|
||||
|
@ -22,8 +23,12 @@ const (
|
|||
twofactor = "two_factor"
|
||||
examplecom = "https://example.com"
|
||||
examplecomsid = "example.com"
|
||||
badsecret = "$plaintext$a_bad_secret"
|
||||
badhmac = "asbdhaaskmdlkamdklasmdlkams"
|
||||
badTokenString = "badTokenString"
|
||||
)
|
||||
|
||||
const (
|
||||
rs256 = "rs256"
|
||||
)
|
||||
|
||||
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
||||
|
@ -78,28 +83,6 @@ func MustLoadCertificateChain(alg, op string) schema.X509CertificateChain {
|
|||
}
|
||||
}
|
||||
|
||||
func MustLoadCertificate(alg, op string) *x509.Certificate {
|
||||
decoded := MustLoadCrypto(alg, op, "crt")
|
||||
|
||||
cert, ok := decoded.(*x509.Certificate)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("the key was not a *x509.Certificate, it's a %T", cert))
|
||||
}
|
||||
|
||||
return cert
|
||||
}
|
||||
|
||||
func MustLoadEd15519PrivateKey(curve string, extra ...string) ed25519.PrivateKey {
|
||||
decoded := MustLoadCrypto("ED25519", curve, "pem", extra...)
|
||||
|
||||
key, ok := decoded.(ed25519.PrivateKey)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("the key was not a ed25519.PrivateKey, it's a %T", key))
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
func MustLoadECDSAPrivateKey(curve string, extra ...string) *ecdsa.PrivateKey {
|
||||
decoded := MustLoadCrypto("ECDSA", curve, "pem", extra...)
|
||||
|
||||
|
@ -133,6 +116,24 @@ func MustLoadRSAPrivateKey(bits string, extra ...string) *rsa.PrivateKey {
|
|||
return key
|
||||
}
|
||||
|
||||
type RFC6749ErrorTest struct {
|
||||
*fosite.RFC6749Error
|
||||
}
|
||||
|
||||
func (err *RFC6749ErrorTest) Error() string {
|
||||
return err.WithExposeDebug(true).GetDescription()
|
||||
}
|
||||
|
||||
func ErrorToRFC6749ErrorTest(err error) (rfc error) {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ferr := fosite.ErrorToRFC6749Error(err)
|
||||
|
||||
return &RFC6749ErrorTest{ferr}
|
||||
}
|
||||
|
||||
var (
|
||||
tOpenIDConnectPBKDF2ClientSecret, tOpenIDConnectPlainTextClientSecret *schema.PasswordDigest
|
||||
|
||||
|
@ -146,8 +147,8 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
tOpenIDConnectPBKDF2ClientSecret = MustDecodeSecret("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng")
|
||||
tOpenIDConnectPlainTextClientSecret = MustDecodeSecret("$plaintext$example")
|
||||
tOpenIDConnectPBKDF2ClientSecret = MustDecodeSecret("$pbkdf2-sha512$100000$cfNEo93VkIUIvaXHqetFoQ$O6qFLAlwCMz6.hv9XqUEPnMtrFxODw70T7bmnfTzfNPi3iXbgUEmGiyA6msybOfmj7m3QJS6lLy4DglgJifkKw")
|
||||
tOpenIDConnectPlainTextClientSecret = MustDecodeSecret("$plaintext$client-secret")
|
||||
|
||||
keyRSA1024 = MustLoadRSAPrivateKey("1024")
|
||||
keyRSA2048 = MustLoadRSAPrivateKey("2048")
|
||||
|
|
|
@ -22,22 +22,21 @@ type HMACCoreStrategy struct {
|
|||
}
|
||||
|
||||
// AccessTokenSignature implements oauth2.AccessTokenStrategy.
|
||||
func (h *HMACCoreStrategy) AccessTokenSignature(ctx context.Context, token string) string {
|
||||
return h.Enigma.Signature(token)
|
||||
func (h *HMACCoreStrategy) AccessTokenSignature(ctx context.Context, tokenString string) string {
|
||||
return h.Enigma.Signature(tokenString)
|
||||
}
|
||||
|
||||
// GenerateAccessToken implements oauth2.AccessTokenStrategy.
|
||||
func (h *HMACCoreStrategy) GenerateAccessToken(ctx context.Context, _ fosite.Requester) (token string, signature string, err error) {
|
||||
token, sig, err := h.Enigma.Generate(ctx)
|
||||
if err != nil {
|
||||
func (h *HMACCoreStrategy) GenerateAccessToken(ctx context.Context, _ fosite.Requester) (tokenString string, sig string, err error) {
|
||||
if tokenString, sig, err = h.Enigma.Generate(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return h.setPrefix(token, tokenPrefixPartAccessToken), sig, nil
|
||||
return h.setPrefix(tokenString, TokenPrefixPartAccessToken), sig, nil
|
||||
}
|
||||
|
||||
// ValidateAccessToken implements oauth2.AccessTokenStrategy.
|
||||
func (h *HMACCoreStrategy) ValidateAccessToken(ctx context.Context, r fosite.Requester, token string) (err error) {
|
||||
func (h *HMACCoreStrategy) ValidateAccessToken(ctx context.Context, r fosite.Requester, tokenString string) (err error) {
|
||||
var exp = r.GetSession().GetExpiresAt(fosite.AccessToken)
|
||||
if exp.IsZero() && r.GetRequestedAt().Add(h.Config.GetAccessTokenLifespan(ctx)).Before(time.Now().UTC()) {
|
||||
return errorsx.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at '%s'.", r.GetRequestedAt().Add(h.Config.GetAccessTokenLifespan(ctx))))
|
||||
|
@ -47,37 +46,36 @@ func (h *HMACCoreStrategy) ValidateAccessToken(ctx context.Context, r fosite.Req
|
|||
return errorsx.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at '%s'.", exp))
|
||||
}
|
||||
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(token, tokenPrefixPartAccessToken))
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(tokenString, TokenPrefixPartAccessToken))
|
||||
}
|
||||
|
||||
// RefreshTokenSignature implements oauth2.RefreshTokenStrategy.
|
||||
func (h *HMACCoreStrategy) RefreshTokenSignature(ctx context.Context, token string) string {
|
||||
return h.Enigma.Signature(token)
|
||||
func (h *HMACCoreStrategy) RefreshTokenSignature(ctx context.Context, tokenString string) string {
|
||||
return h.Enigma.Signature(tokenString)
|
||||
}
|
||||
|
||||
// GenerateRefreshToken implements oauth2.RefreshTokenStrategy.
|
||||
func (h *HMACCoreStrategy) GenerateRefreshToken(ctx context.Context, _ fosite.Requester) (token string, signature string, err error) {
|
||||
token, sig, err := h.Enigma.Generate(ctx)
|
||||
if err != nil {
|
||||
func (h *HMACCoreStrategy) GenerateRefreshToken(ctx context.Context, _ fosite.Requester) (tokenString string, sig string, err error) {
|
||||
if tokenString, sig, err = h.Enigma.Generate(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return h.setPrefix(token, tokenPrefixPartRefreshToken), sig, nil
|
||||
return h.setPrefix(tokenString, TokenPrefixPartRefreshToken), sig, nil
|
||||
}
|
||||
|
||||
// ValidateRefreshToken implements oauth2.RefreshTokenStrategy.
|
||||
func (h *HMACCoreStrategy) ValidateRefreshToken(ctx context.Context, r fosite.Requester, token string) (err error) {
|
||||
func (h *HMACCoreStrategy) ValidateRefreshToken(ctx context.Context, r fosite.Requester, tokenString string) (err error) {
|
||||
var exp = r.GetSession().GetExpiresAt(fosite.RefreshToken)
|
||||
|
||||
if exp.IsZero() {
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(token, tokenPrefixPartRefreshToken))
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(tokenString, TokenPrefixPartRefreshToken))
|
||||
}
|
||||
|
||||
if exp.Before(time.Now().UTC()) {
|
||||
return errorsx.WithStack(fosite.ErrTokenExpired.WithHintf("Refresh token expired at '%s'.", exp))
|
||||
}
|
||||
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(token, tokenPrefixPartRefreshToken))
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(tokenString, TokenPrefixPartRefreshToken))
|
||||
}
|
||||
|
||||
// AuthorizeCodeSignature implements oauth2.AuthorizeCodeStrategy.
|
||||
|
@ -86,17 +84,16 @@ func (h *HMACCoreStrategy) AuthorizeCodeSignature(ctx context.Context, token str
|
|||
}
|
||||
|
||||
// GenerateAuthorizeCode implements oauth2.AuthorizeCodeStrategy.
|
||||
func (h *HMACCoreStrategy) GenerateAuthorizeCode(ctx context.Context, _ fosite.Requester) (token string, signature string, err error) {
|
||||
token, sig, err := h.Enigma.Generate(ctx)
|
||||
if err != nil {
|
||||
func (h *HMACCoreStrategy) GenerateAuthorizeCode(ctx context.Context, _ fosite.Requester) (tokenString string, sig string, err error) {
|
||||
if tokenString, sig, err = h.Enigma.Generate(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return h.setPrefix(token, tokenPrefixPartAuthorizeCode), sig, nil
|
||||
return h.setPrefix(tokenString, TokenPrefixPartAuthorizeCode), sig, nil
|
||||
}
|
||||
|
||||
// ValidateAuthorizeCode implements oauth2.AuthorizeCodeStrategy.
|
||||
func (h *HMACCoreStrategy) ValidateAuthorizeCode(ctx context.Context, r fosite.Requester, token string) (err error) {
|
||||
func (h *HMACCoreStrategy) ValidateAuthorizeCode(ctx context.Context, r fosite.Requester, tokenString string) (err error) {
|
||||
var exp = r.GetSession().GetExpiresAt(fosite.AuthorizeCode)
|
||||
|
||||
if exp.IsZero() && r.GetRequestedAt().Add(h.Config.GetAuthorizeCodeLifespan(ctx)).Before(time.Now().UTC()) {
|
||||
|
@ -107,7 +104,7 @@ func (h *HMACCoreStrategy) ValidateAuthorizeCode(ctx context.Context, r fosite.R
|
|||
return errorsx.WithStack(fosite.ErrTokenExpired.WithHintf("Authorize code expired at '%s'.", exp))
|
||||
}
|
||||
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(token, tokenPrefixPartAuthorizeCode))
|
||||
return h.Enigma.Validate(ctx, h.trimPrefix(tokenString, TokenPrefixPartAuthorizeCode))
|
||||
}
|
||||
|
||||
func (h *HMACCoreStrategy) getPrefix(part string) string {
|
||||
|
@ -118,14 +115,14 @@ func (h *HMACCoreStrategy) getCustomPrefix(tokenPrefixFmt, part string) string {
|
|||
return fmt.Sprintf(tokenPrefixFmt, part)
|
||||
}
|
||||
|
||||
func (h *HMACCoreStrategy) setPrefix(token, part string) string {
|
||||
return h.getPrefix(part) + token
|
||||
func (h *HMACCoreStrategy) setPrefix(tokenString, part string) string {
|
||||
return h.getPrefix(part) + tokenString
|
||||
}
|
||||
|
||||
func (h *HMACCoreStrategy) trimPrefix(token, part string) string {
|
||||
if strings.HasPrefix(token, h.getCustomPrefix(tokenPrefixOrgOryFmt, part)) {
|
||||
return strings.TrimPrefix(token, h.getCustomPrefix(tokenPrefixOrgOryFmt, part))
|
||||
func (h *HMACCoreStrategy) trimPrefix(tokenString, part string) string {
|
||||
if strings.HasPrefix(tokenString, h.getCustomPrefix(tokenPrefixOrgOryFmt, part)) {
|
||||
return strings.TrimPrefix(tokenString, h.getCustomPrefix(tokenPrefixOrgOryFmt, part))
|
||||
}
|
||||
|
||||
return strings.TrimPrefix(token, h.getPrefix(part))
|
||||
return strings.TrimPrefix(tokenString, h.getPrefix(part))
|
||||
}
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/token/hmac"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestHMACStrategy(t *testing.T) {
|
||||
goodsecret := []byte("R7VCSUfnKc7Y5zE84q6GstYqfMGjL4wM")
|
||||
secreta := []byte("a")
|
||||
|
||||
config := &Config{
|
||||
config := &oidc.Config{
|
||||
TokenEntropy: 10,
|
||||
GlobalSecret: secreta,
|
||||
Lifespans: LifespanConfig{
|
||||
Lifespans: oidc.LifespanConfig{
|
||||
AccessToken: time.Hour,
|
||||
RefreshToken: time.Hour,
|
||||
AuthorizeCode: time.Minute,
|
||||
},
|
||||
}
|
||||
|
||||
strategy := &HMACCoreStrategy{
|
||||
strategy := &oidc.HMACCoreStrategy{
|
||||
Enigma: &hmac.HMACStrategy{Config: config},
|
||||
Config: config,
|
||||
}
|
||||
|
@ -87,50 +87,3 @@ func TestHMACStrategy(t *testing.T) {
|
|||
assert.NoError(t, strategy.ValidateAccessToken(ctx, &fosite.Request{RequestedAt: time.Now().Add(time.Hour * -2400), Session: &fosite.DefaultSession{ExpiresAt: map[fosite.TokenType]time.Time{fosite.AccessToken: time.Now().Add(100 * time.Hour)}}}, token))
|
||||
assert.EqualError(t, strategy.ValidateAccessToken(ctx, &fosite.Request{RequestedAt: time.Now(), Session: &fosite.DefaultSession{ExpiresAt: map[fosite.TokenType]time.Time{fosite.AccessToken: time.Now().Add(-100 * time.Second)}}}, token), "invalid_token")
|
||||
}
|
||||
|
||||
func TestHMACCoreStrategy_TrimPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have string
|
||||
part string
|
||||
expected string
|
||||
}{
|
||||
{"ShouldTrimAutheliaPrefix", "authelia_at_example", tokenPrefixPartAccessToken, "example"},
|
||||
{"ShouldTrimOryPrefix", "ory_at_example", tokenPrefixPartAccessToken, "example"},
|
||||
{"ShouldTrimOnlyAutheliaPrefix", "authelia_at_ory_at_example", tokenPrefixPartAccessToken, "ory_at_example"},
|
||||
{"ShouldTrimOnlyOryPrefix", "ory_at_authelia_at_example", tokenPrefixPartAccessToken, "authelia_at_example"},
|
||||
{"ShouldNotTrimGitHubPrefix", "gh_at_example", tokenPrefixPartAccessToken, "gh_at_example"},
|
||||
}
|
||||
|
||||
strategy := &HMACCoreStrategy{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expected, strategy.trimPrefix(tc.have, tc.part))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHMACCoreStrategy_GetSetPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have string
|
||||
expectedSet string
|
||||
expectedGet string
|
||||
}{
|
||||
{"ShouldAddPrefix", "example", "authelia_%s_example", "authelia_%s_"},
|
||||
}
|
||||
|
||||
strategy := &HMACCoreStrategy{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, part := range []string{tokenPrefixPartAccessToken, tokenPrefixPartAuthorizeCode, tokenPrefixPartRefreshToken} {
|
||||
t.Run(strings.ToUpper(part), func(t *testing.T) {
|
||||
assert.Equal(t, fmt.Sprintf(tc.expectedSet, part), strategy.setPrefix(tc.have, part))
|
||||
assert.Equal(t, fmt.Sprintf(tc.expectedGet, part), strategy.getPrefix(part))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHMACCoreStrategy_TrimPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have string
|
||||
part string
|
||||
expected string
|
||||
}{
|
||||
{"ShouldTrimAutheliaPrefix", "authelia_at_example", TokenPrefixPartAccessToken, "example"},
|
||||
{"ShouldTrimOryPrefix", "ory_at_example", TokenPrefixPartAccessToken, "example"},
|
||||
{"ShouldTrimOnlyAutheliaPrefix", "authelia_at_ory_at_example", TokenPrefixPartAccessToken, "ory_at_example"},
|
||||
{"ShouldTrimOnlyOryPrefix", "ory_at_authelia_at_example", TokenPrefixPartAccessToken, "authelia_at_example"},
|
||||
{"ShouldNotTrimGitHubPrefix", "gh_at_example", TokenPrefixPartAccessToken, "gh_at_example"},
|
||||
}
|
||||
|
||||
strategy := &HMACCoreStrategy{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expected, strategy.trimPrefix(tc.have, tc.part))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHMACCoreStrategy_GetSetPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have string
|
||||
expectedSet string
|
||||
expectedGet string
|
||||
}{
|
||||
{"ShouldAddPrefix", "example", "authelia_%s_example", "authelia_%s_"},
|
||||
}
|
||||
|
||||
strategy := &HMACCoreStrategy{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, part := range []string{TokenPrefixPartAccessToken, TokenPrefixPartAuthorizeCode, TokenPrefixPartRefreshToken} {
|
||||
t.Run(strings.ToUpper(part), func(t *testing.T) {
|
||||
assert.Equal(t, fmt.Sprintf(tc.expectedSet, part), strategy.setPrefix(tc.have, part))
|
||||
assert.Equal(t, fmt.Sprintf(tc.expectedGet, part), strategy.getPrefix(part))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -66,6 +66,7 @@ func NewOpenIDConnectWellKnownConfiguration(c *schema.OpenIDConnectConfiguration
|
|||
ClientAuthMethodClientSecretBasic,
|
||||
ClientAuthMethodClientSecretPost,
|
||||
ClientAuthMethodClientSecretJWT,
|
||||
ClientAuthMethodPrivateKeyJWT,
|
||||
ClientAuthMethodNone,
|
||||
},
|
||||
TokenEndpointAuthSigningAlgValuesSupported: []string{
|
||||
|
@ -82,6 +83,7 @@ func NewOpenIDConnectWellKnownConfiguration(c *schema.OpenIDConnectConfiguration
|
|||
ClientAuthMethodClientSecretBasic,
|
||||
ClientAuthMethodClientSecretPost,
|
||||
ClientAuthMethodClientSecretJWT,
|
||||
ClientAuthMethodPrivateKeyJWT,
|
||||
ClientAuthMethodNone,
|
||||
},
|
||||
RevocationEndpointAuthSigningAlgValuesSupported: []string{
|
||||
|
@ -104,12 +106,12 @@ func NewOpenIDConnectWellKnownConfiguration(c *schema.OpenIDConnectConfiguration
|
|||
SigningAlgRSAUsingSHA256,
|
||||
},
|
||||
UserinfoSigningAlgValuesSupported: []string{
|
||||
SigningAlgNone,
|
||||
SigningAlgRSAUsingSHA256,
|
||||
SigningAlgNone,
|
||||
},
|
||||
RequestObjectSigningAlgValuesSupported: []string{
|
||||
SigningAlgNone,
|
||||
SigningAlgRSAUsingSHA256,
|
||||
SigningAlgNone,
|
||||
},
|
||||
},
|
||||
OpenIDConnectFrontChannelLogoutDiscoveryOptions: &OpenIDConnectFrontChannelLogoutDiscoveryOptions{},
|
||||
|
@ -122,11 +124,7 @@ func NewOpenIDConnectWellKnownConfiguration(c *schema.OpenIDConnectConfiguration
|
|||
},
|
||||
}
|
||||
|
||||
algs := make([]string, len(c.Discovery.RegisteredJWKSigningAlgs))
|
||||
|
||||
copy(algs, c.Discovery.RegisteredJWKSigningAlgs)
|
||||
|
||||
for _, alg := range algs {
|
||||
for _, alg := range c.Discovery.ResponseObjectSigningAlgs {
|
||||
if !utils.IsStringInSlice(alg, config.IDTokenSigningAlgValuesSupported) {
|
||||
config.IDTokenSigningAlgValuesSupported = append(config.IDTokenSigningAlgValuesSupported, alg)
|
||||
}
|
||||
|
@ -136,6 +134,20 @@ func NewOpenIDConnectWellKnownConfiguration(c *schema.OpenIDConnectConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
for _, alg := range c.Discovery.RequestObjectSigningAlgs {
|
||||
if !utils.IsStringInSlice(alg, config.RequestObjectSigningAlgValuesSupported) {
|
||||
config.RequestObjectSigningAlgValuesSupported = append(config.RequestObjectSigningAlgValuesSupported, alg)
|
||||
}
|
||||
|
||||
if !utils.IsStringInSlice(alg, config.RevocationEndpointAuthSigningAlgValuesSupported) {
|
||||
config.RevocationEndpointAuthSigningAlgValuesSupported = append(config.RevocationEndpointAuthSigningAlgValuesSupported, alg)
|
||||
}
|
||||
|
||||
if !utils.IsStringInSlice(alg, config.TokenEndpointAuthSigningAlgValuesSupported) {
|
||||
config.TokenEndpointAuthSigningAlgValuesSupported = append(config.TokenEndpointAuthSigningAlgValuesSupported, alg)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(SortedSigningAlgs(config.IDTokenSigningAlgValuesSupported))
|
||||
sort.Sort(SortedSigningAlgs(config.UserinfoSigningAlgValuesSupported))
|
||||
sort.Sort(SortedSigningAlgs(config.RequestObjectSigningAlgValuesSupported))
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestNewOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
||||
|
@ -13,91 +16,119 @@ func TestNewOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
|||
desc string
|
||||
pkcePlainChallenge bool
|
||||
enforcePAR bool
|
||||
clients map[string]Client
|
||||
clients map[string]oidc.Client
|
||||
discovery schema.OpenIDConnectDiscovery
|
||||
|
||||
expectCodeChallengeMethodsSupported, expectSubjectTypesSupported, expectedIDTokenSigAlgsSupported, expectedUserInfoSigAlgsSupported []string
|
||||
expectCodeChallengeMethodsSupported, expectSubjectTypesSupported []string
|
||||
expectedIDTokenSigAlgsSupported, expectedUserInfoSigAlgsSupported []string
|
||||
|
||||
expectedRequestObjectSigAlgsSupported, expectedRevocationSigAlgsSupported, expectedTokenAuthSigAlgsSupported []string
|
||||
}{
|
||||
{
|
||||
desc: "ShouldHaveChallengeMethodsS256ANDSubjectTypesSupportedPublic",
|
||||
pkcePlainChallenge: false,
|
||||
clients: map[string]Client{"a": &BaseClient{}},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{}},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldIncludDiscoveryInfo",
|
||||
desc: "ShouldIncludeDiscoveryInfo",
|
||||
pkcePlainChallenge: false,
|
||||
clients: map[string]Client{"a": &BaseClient{}},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{}},
|
||||
discovery: schema.OpenIDConnectDiscovery{
|
||||
RegisteredJWKSigningAlgs: []string{SigningAlgECDSAUsingP521AndSHA512},
|
||||
ResponseObjectSigningAlgs: []string{oidc.SigningAlgECDSAUsingP521AndSHA512},
|
||||
RequestObjectSigningAlgs: []string{oidc.SigningAlgECDSAUsingP256AndSHA256},
|
||||
},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgECDSAUsingP521AndSHA512},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgECDSAUsingP521AndSHA512, SigningAlgNone},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgECDSAUsingP521AndSHA512},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgECDSAUsingP521AndSHA512, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgECDSAUsingP256AndSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512, oidc.SigningAlgECDSAUsingP256AndSHA256},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512, oidc.SigningAlgECDSAUsingP256AndSHA256},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveChallengeMethodsS256PlainANDSubjectTypesSupportedPublic",
|
||||
pkcePlainChallenge: true,
|
||||
clients: map[string]Client{"a": &BaseClient{}},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256, PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{}},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256, oidc.PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveChallengeMethodsS256ANDSubjectTypesSupportedPublicPairwise",
|
||||
pkcePlainChallenge: false,
|
||||
clients: map[string]Client{"a": &BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveChallengeMethodsS256PlainANDSubjectTypesSupportedPublicPairwise",
|
||||
pkcePlainChallenge: true,
|
||||
clients: map[string]Client{"a": &BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256, PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256, oidc.PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveTokenAuthMethodsNone",
|
||||
pkcePlainChallenge: true,
|
||||
clients: map[string]Client{"a": &BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256, PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
clients: map[string]oidc.Client{"a": &oidc.BaseClient{SectorIdentifier: "yes"}},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256, oidc.PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveTokenAuthMethodsNone",
|
||||
pkcePlainChallenge: true,
|
||||
clients: map[string]Client{
|
||||
"a": &BaseClient{SectorIdentifier: "yes"},
|
||||
"b": &BaseClient{SectorIdentifier: "yes"},
|
||||
clients: map[string]oidc.Client{
|
||||
"a": &oidc.BaseClient{SectorIdentifier: "yes"},
|
||||
"b": &oidc.BaseClient{SectorIdentifier: "yes"},
|
||||
},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256, PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256, oidc.PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
{
|
||||
desc: "ShouldHaveTokenAuthMethodsNone",
|
||||
pkcePlainChallenge: true,
|
||||
clients: map[string]Client{
|
||||
"a": &BaseClient{SectorIdentifier: "yes"},
|
||||
"b": &BaseClient{SectorIdentifier: "yes"},
|
||||
clients: map[string]oidc.Client{
|
||||
"a": &oidc.BaseClient{SectorIdentifier: "yes"},
|
||||
"b": &oidc.BaseClient{SectorIdentifier: "yes"},
|
||||
},
|
||||
expectCodeChallengeMethodsSupported: []string{PKCEChallengeMethodSHA256, PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{SubjectTypePublic, SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{SigningAlgRSAUsingSHA256, SigningAlgNone},
|
||||
expectCodeChallengeMethodsSupported: []string{oidc.PKCEChallengeMethodSHA256, oidc.PKCEChallengeMethodPlain},
|
||||
expectSubjectTypesSupported: []string{oidc.SubjectTypePublic, oidc.SubjectTypePairwise},
|
||||
expectedIDTokenSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256},
|
||||
expectedUserInfoSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRequestObjectSigAlgsSupported: []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgNone},
|
||||
expectedRevocationSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
expectedTokenAuthSigAlgsSupported: []string{oidc.SigningAlgHMACUsingSHA256, oidc.SigningAlgHMACUsingSHA384, oidc.SigningAlgHMACUsingSHA512},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -111,7 +142,7 @@ func TestNewOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
|||
Discovery: tc.discovery,
|
||||
}
|
||||
|
||||
actual := NewOpenIDConnectWellKnownConfiguration(&c)
|
||||
actual := oidc.NewOpenIDConnectWellKnownConfiguration(&c)
|
||||
for _, codeChallengeMethod := range tc.expectCodeChallengeMethodsSupported {
|
||||
assert.Contains(t, actual.CodeChallengeMethodsSupported, codeChallengeMethod)
|
||||
}
|
||||
|
@ -130,6 +161,425 @@ func TestNewOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
|||
|
||||
assert.Equal(t, tc.expectedUserInfoSigAlgsSupported, actual.UserinfoSigningAlgValuesSupported)
|
||||
assert.Equal(t, tc.expectedIDTokenSigAlgsSupported, actual.IDTokenSigningAlgValuesSupported)
|
||||
assert.Equal(t, tc.expectedRequestObjectSigAlgsSupported, actual.RequestObjectSigningAlgValuesSupported)
|
||||
assert.Equal(t, tc.expectedRevocationSigAlgsSupported, actual.RevocationEndpointAuthSigningAlgValuesSupported)
|
||||
assert.Equal(t, tc.expectedTokenAuthSigAlgsSupported, actual.TokenEndpointAuthSigningAlgValuesSupported)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProviderDiscovery(t *testing.T) {
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
EnablePKCEPlainChallenge: true,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
a := provider.GetOpenIDConnectWellKnownConfiguration("https://auth.example.com")
|
||||
|
||||
data, err := json.Marshal(&a)
|
||||
assert.NoError(t, err)
|
||||
|
||||
b := oidc.OpenIDConnectWellKnownConfiguration{}
|
||||
|
||||
assert.NoError(t, json.Unmarshal(data, &b))
|
||||
|
||||
assert.Equal(t, a, b)
|
||||
|
||||
y := provider.GetOAuth2WellKnownConfiguration("https://auth.example.com")
|
||||
|
||||
data, err = json.Marshal(&y)
|
||||
assert.NoError(t, err)
|
||||
|
||||
z := oidc.OAuth2WellKnownConfiguration{}
|
||||
|
||||
assert.NoError(t, json.Unmarshal(data, &z))
|
||||
|
||||
assert.Equal(t, y, z)
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOpenIDConnectWellKnownConfiguration(examplecom)
|
||||
|
||||
assert.Equal(t, examplecom, disco.Issuer)
|
||||
assert.Equal(t, "https://example.com/jwks.json", disco.JWKSURI)
|
||||
assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/userinfo", disco.UserinfoEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint)
|
||||
assert.Equal(t, "", disco.RegistrationEndpoint)
|
||||
|
||||
assert.Len(t, disco.CodeChallengeMethodsSupported, 1)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, oidc.PKCEChallengeMethodSHA256)
|
||||
|
||||
assert.Len(t, disco.ScopesSupported, 5)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeOpenID)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeOfflineAccess)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeProfile)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeGroups)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeEmail)
|
||||
|
||||
assert.Len(t, disco.ResponseModesSupported, 3)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeFormPost)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeQuery)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeFragment)
|
||||
|
||||
assert.Len(t, disco.SubjectTypesSupported, 2)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePairwise)
|
||||
|
||||
assert.Len(t, disco.ResponseTypesSupported, 7)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeAuthorizationCodeFlow)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowBoth)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowBoth)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthMethodsSupported, 5)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodPrivateKeyJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.RevocationEndpointAuthMethodsSupported, 5)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, oidc.ClientAuthMethodPrivateKeyJWT)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, oidc.ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.IntrospectionEndpointAuthMethodsSupported, 2)
|
||||
assert.Contains(t, disco.IntrospectionEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.IntrospectionEndpointAuthMethodsSupported, oidc.ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.GrantTypesSupported, 3)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeAuthorizationCode)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeRefreshToken)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeImplicit)
|
||||
|
||||
assert.Len(t, disco.RevocationEndpointAuthSigningAlgValuesSupported, 3)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[0], oidc.SigningAlgHMACUsingSHA256)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[1], oidc.SigningAlgHMACUsingSHA384)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[2], oidc.SigningAlgHMACUsingSHA512)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthSigningAlgValuesSupported, 3)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[0], oidc.SigningAlgHMACUsingSHA256)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[1], oidc.SigningAlgHMACUsingSHA384)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[2], oidc.SigningAlgHMACUsingSHA512)
|
||||
|
||||
assert.Len(t, disco.IDTokenSigningAlgValuesSupported, 1)
|
||||
assert.Contains(t, disco.IDTokenSigningAlgValuesSupported, oidc.SigningAlgRSAUsingSHA256)
|
||||
|
||||
assert.Len(t, disco.UserinfoSigningAlgValuesSupported, 2)
|
||||
assert.Equal(t, disco.UserinfoSigningAlgValuesSupported[0], oidc.SigningAlgRSAUsingSHA256)
|
||||
assert.Equal(t, disco.UserinfoSigningAlgValuesSupported[1], oidc.SigningAlgNone)
|
||||
|
||||
require.Len(t, disco.RequestObjectSigningAlgValuesSupported, 2)
|
||||
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, disco.RequestObjectSigningAlgValuesSupported[0])
|
||||
assert.Equal(t, oidc.SigningAlgNone, disco.RequestObjectSigningAlgValuesSupported[1])
|
||||
|
||||
assert.Len(t, disco.ClaimsSupported, 18)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthenticationMethodsReference)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAudience)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthorizedParty)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimClientIdentifier)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimExpirationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimIssuedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimIssuer)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimJWTID)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimRequestedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimSubject)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthenticationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimNonce)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimPreferredEmail)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimEmailVerified)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimEmailAlts)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimGroups)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimPreferredUsername)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimFullName)
|
||||
|
||||
assert.Len(t, disco.PromptValuesSupported, 2)
|
||||
assert.Contains(t, disco.PromptValuesSupported, oidc.PromptConsent)
|
||||
assert.Contains(t, disco.PromptValuesSupported, oidc.PromptNone)
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProvider_GetOAuth2WellKnownConfiguration(t *testing.T) {
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOAuth2WellKnownConfiguration(examplecom)
|
||||
|
||||
assert.Equal(t, examplecom, disco.Issuer)
|
||||
assert.Equal(t, "https://example.com/jwks.json", disco.JWKSURI)
|
||||
assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint)
|
||||
assert.Equal(t, "", disco.RegistrationEndpoint)
|
||||
|
||||
require.Len(t, disco.CodeChallengeMethodsSupported, 1)
|
||||
assert.Equal(t, "S256", disco.CodeChallengeMethodsSupported[0])
|
||||
|
||||
assert.Len(t, disco.ScopesSupported, 5)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeOpenID)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeOfflineAccess)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeProfile)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeGroups)
|
||||
assert.Contains(t, disco.ScopesSupported, oidc.ScopeEmail)
|
||||
|
||||
assert.Len(t, disco.ResponseModesSupported, 3)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeFormPost)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeQuery)
|
||||
assert.Contains(t, disco.ResponseModesSupported, oidc.ResponseModeFragment)
|
||||
|
||||
assert.Len(t, disco.SubjectTypesSupported, 2)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePairwise)
|
||||
|
||||
assert.Len(t, disco.ResponseTypesSupported, 7)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeAuthorizationCodeFlow)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeImplicitFlowBoth)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, oidc.ResponseTypeHybridFlowBoth)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthMethodsSupported, 5)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodPrivateKeyJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, oidc.ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.GrantTypesSupported, 3)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeAuthorizationCode)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeRefreshToken)
|
||||
assert.Contains(t, disco.GrantTypesSupported, oidc.GrantTypeImplicit)
|
||||
|
||||
assert.Len(t, disco.ClaimsSupported, 18)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthenticationMethodsReference)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAudience)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthorizedParty)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimClientIdentifier)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimExpirationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimIssuedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimIssuer)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimJWTID)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimRequestedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimSubject)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimAuthenticationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimNonce)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimPreferredEmail)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimEmailVerified)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimEmailAlts)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimGroups)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimPreferredUsername)
|
||||
assert.Contains(t, disco.ClaimsSupported, oidc.ClaimFullName)
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfigurationWithPlainPKCE(t *testing.T) {
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
EnablePKCEPlainChallenge: true,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOpenIDConnectWellKnownConfiguration(examplecom)
|
||||
|
||||
require.Len(t, disco.CodeChallengeMethodsSupported, 2)
|
||||
assert.Equal(t, oidc.PKCEChallengeMethodSHA256, disco.CodeChallengeMethodsSupported[0])
|
||||
assert.Equal(t, oidc.PKCEChallengeMethodPlain, disco.CodeChallengeMethodsSupported[1])
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectWellKnownConfiguration_Copy(t *testing.T) {
|
||||
config := &oidc.OpenIDConnectWellKnownConfiguration{
|
||||
OAuth2WellKnownConfiguration: oidc.OAuth2WellKnownConfiguration{
|
||||
CommonDiscoveryOptions: oidc.CommonDiscoveryOptions{
|
||||
Issuer: "https://example.com",
|
||||
JWKSURI: "https://example.com/jwks.json",
|
||||
AuthorizationEndpoint: "",
|
||||
TokenEndpoint: "",
|
||||
SubjectTypesSupported: nil,
|
||||
ResponseTypesSupported: nil,
|
||||
GrantTypesSupported: nil,
|
||||
ResponseModesSupported: nil,
|
||||
ScopesSupported: nil,
|
||||
ClaimsSupported: nil,
|
||||
UILocalesSupported: nil,
|
||||
TokenEndpointAuthMethodsSupported: nil,
|
||||
TokenEndpointAuthSigningAlgValuesSupported: nil,
|
||||
ServiceDocumentation: "",
|
||||
OPPolicyURI: "",
|
||||
OPTOSURI: "",
|
||||
SignedMetadata: "",
|
||||
},
|
||||
OAuth2DiscoveryOptions: oidc.OAuth2DiscoveryOptions{
|
||||
IntrospectionEndpoint: "",
|
||||
RevocationEndpoint: "",
|
||||
RegistrationEndpoint: "",
|
||||
IntrospectionEndpointAuthMethodsSupported: nil,
|
||||
RevocationEndpointAuthMethodsSupported: nil,
|
||||
RevocationEndpointAuthSigningAlgValuesSupported: nil,
|
||||
IntrospectionEndpointAuthSigningAlgValuesSupported: nil,
|
||||
CodeChallengeMethodsSupported: nil,
|
||||
},
|
||||
OAuth2DeviceAuthorizationGrantDiscoveryOptions: &oidc.OAuth2DeviceAuthorizationGrantDiscoveryOptions{
|
||||
DeviceAuthorizationEndpoint: "",
|
||||
},
|
||||
OAuth2MutualTLSClientAuthenticationDiscoveryOptions: &oidc.OAuth2MutualTLSClientAuthenticationDiscoveryOptions{
|
||||
TLSClientCertificateBoundAccessTokens: false,
|
||||
MutualTLSEndpointAliases: oidc.OAuth2MutualTLSClientAuthenticationAliasesDiscoveryOptions{
|
||||
AuthorizationEndpoint: "",
|
||||
TokenEndpoint: "",
|
||||
IntrospectionEndpoint: "",
|
||||
RevocationEndpoint: "",
|
||||
EndSessionEndpoint: "",
|
||||
UserinfoEndpoint: "",
|
||||
BackChannelAuthenticationEndpoint: "",
|
||||
FederationRegistrationEndpoint: "",
|
||||
PushedAuthorizationRequestEndpoint: "",
|
||||
RegistrationEndpoint: "",
|
||||
},
|
||||
},
|
||||
OAuth2IssuerIdentificationDiscoveryOptions: &oidc.OAuth2IssuerIdentificationDiscoveryOptions{
|
||||
AuthorizationResponseIssuerParameterSupported: false,
|
||||
},
|
||||
OAuth2JWTIntrospectionResponseDiscoveryOptions: &oidc.OAuth2JWTIntrospectionResponseDiscoveryOptions{
|
||||
IntrospectionSigningAlgValuesSupported: nil,
|
||||
IntrospectionEncryptionAlgValuesSupported: nil,
|
||||
IntrospectionEncryptionEncValuesSupported: nil,
|
||||
},
|
||||
OAuth2JWTSecuredAuthorizationRequestDiscoveryOptions: &oidc.OAuth2JWTSecuredAuthorizationRequestDiscoveryOptions{
|
||||
RequireSignedRequestObject: false,
|
||||
},
|
||||
OAuth2PushedAuthorizationDiscoveryOptions: &oidc.OAuth2PushedAuthorizationDiscoveryOptions{
|
||||
PushedAuthorizationRequestEndpoint: "",
|
||||
RequirePushedAuthorizationRequests: false,
|
||||
},
|
||||
},
|
||||
OpenIDConnectDiscoveryOptions: oidc.OpenIDConnectDiscoveryOptions{
|
||||
UserinfoEndpoint: "",
|
||||
IDTokenSigningAlgValuesSupported: nil,
|
||||
UserinfoSigningAlgValuesSupported: nil,
|
||||
RequestObjectSigningAlgValuesSupported: nil,
|
||||
IDTokenEncryptionAlgValuesSupported: nil,
|
||||
UserinfoEncryptionAlgValuesSupported: nil,
|
||||
RequestObjectEncryptionAlgValuesSupported: nil,
|
||||
IDTokenEncryptionEncValuesSupported: nil,
|
||||
UserinfoEncryptionEncValuesSupported: nil,
|
||||
RequestObjectEncryptionEncValuesSupported: nil,
|
||||
ACRValuesSupported: nil,
|
||||
DisplayValuesSupported: nil,
|
||||
ClaimTypesSupported: nil,
|
||||
ClaimLocalesSupported: nil,
|
||||
RequestParameterSupported: false,
|
||||
RequestURIParameterSupported: false,
|
||||
RequireRequestURIRegistration: false,
|
||||
ClaimsParameterSupported: false,
|
||||
},
|
||||
OpenIDConnectFrontChannelLogoutDiscoveryOptions: &oidc.OpenIDConnectFrontChannelLogoutDiscoveryOptions{
|
||||
FrontChannelLogoutSupported: false,
|
||||
FrontChannelLogoutSessionSupported: false,
|
||||
},
|
||||
OpenIDConnectBackChannelLogoutDiscoveryOptions: &oidc.OpenIDConnectBackChannelLogoutDiscoveryOptions{
|
||||
BackChannelLogoutSupported: false,
|
||||
BackChannelLogoutSessionSupported: false,
|
||||
},
|
||||
OpenIDConnectSessionManagementDiscoveryOptions: &oidc.OpenIDConnectSessionManagementDiscoveryOptions{
|
||||
CheckSessionIFrame: "",
|
||||
},
|
||||
OpenIDConnectRPInitiatedLogoutDiscoveryOptions: &oidc.OpenIDConnectRPInitiatedLogoutDiscoveryOptions{
|
||||
EndSessionEndpoint: "",
|
||||
},
|
||||
OpenIDConnectPromptCreateDiscoveryOptions: &oidc.OpenIDConnectPromptCreateDiscoveryOptions{
|
||||
PromptValuesSupported: nil,
|
||||
},
|
||||
OpenIDConnectClientInitiatedBackChannelAuthFlowDiscoveryOptions: &oidc.OpenIDConnectClientInitiatedBackChannelAuthFlowDiscoveryOptions{
|
||||
BackChannelAuthenticationEndpoint: "",
|
||||
BackChannelTokenDeliveryModesSupported: nil,
|
||||
BackChannelAuthRequestSigningAlgValuesSupported: nil,
|
||||
BackChannelUserCodeParameterSupported: false,
|
||||
},
|
||||
OpenIDConnectJWTSecuredAuthorizationResponseModeDiscoveryOptions: &oidc.OpenIDConnectJWTSecuredAuthorizationResponseModeDiscoveryOptions{
|
||||
AuthorizationSigningAlgValuesSupported: nil,
|
||||
AuthorizationEncryptionAlgValuesSupported: nil,
|
||||
AuthorizationEncryptionEncValuesSupported: nil,
|
||||
},
|
||||
OpenIDFederationDiscoveryOptions: &oidc.OpenIDFederationDiscoveryOptions{
|
||||
FederationRegistrationEndpoint: "",
|
||||
ClientRegistrationTypesSupported: nil,
|
||||
RequestAuthenticationMethodsSupported: nil,
|
||||
RequestAuthenticationSigningAlgValuesSupproted: nil,
|
||||
},
|
||||
}
|
||||
|
||||
x := config.Copy()
|
||||
|
||||
assert.Equal(t, config, &x)
|
||||
|
||||
y := config.OAuth2WellKnownConfiguration.Copy()
|
||||
|
||||
assert.Equal(t, config.OAuth2WellKnownConfiguration, y)
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"github.com/go-crypt/crypt/algorithm/plaintext"
|
||||
)
|
||||
|
||||
// NewHasher returns a new Hasher.
|
||||
func NewHasher() (hasher *Hasher, err error) {
|
||||
hasher = &Hasher{}
|
||||
|
||||
if hasher.decoder, err = crypt.NewDefaultDecoder(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = plaintext.RegisterDecoderPlainText(hasher.decoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hasher, nil
|
||||
}
|
||||
|
||||
// Hasher implements the fosite.Hasher interface and adaptively compares hashes.
|
||||
type Hasher struct {
|
||||
decoder algorithm.DecoderRegister
|
||||
}
|
||||
|
||||
// Compare compares the hash with the data and returns an error if they don't match.
|
||||
func (h Hasher) Compare(_ context.Context, hash, data []byte) (err error) {
|
||||
var digest algorithm.Digest
|
||||
|
||||
if digest, err = h.decoder.Decode(string(hash)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if digest.MatchBytes(data) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errPasswordsDoNotMatch
|
||||
}
|
||||
|
||||
// Hash creates a new hash from data.
|
||||
func (h Hasher) Hash(_ context.Context, data []byte) (hash []byte, err error) {
|
||||
return data, nil
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestShouldNotRaiseErrorOnEqualPasswordsPlainText(t *testing.T) {
|
||||
hasher, err := NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc")
|
||||
b := []byte("abc")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.NoError(t, hasher.Compare(ctx, a, b))
|
||||
}
|
||||
|
||||
func TestShouldNotRaiseErrorOnEqualPasswordsPlainTextWithSeparator(t *testing.T) {
|
||||
hasher, err := NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc$123")
|
||||
b := []byte("abc$123")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.NoError(t, hasher.Compare(ctx, a, b))
|
||||
}
|
||||
|
||||
func TestShouldRaiseErrorOnNonEqualPasswordsPlainText(t *testing.T) {
|
||||
hasher, err := NewHasher()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
a := []byte("$plaintext$abc")
|
||||
b := []byte("abcd")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.Equal(t, errPasswordsDoNotMatch, hasher.Compare(ctx, a, b))
|
||||
}
|
||||
|
||||
func TestShouldHashPassword(t *testing.T) {
|
||||
hasher := Hasher{}
|
||||
|
||||
data := []byte("abc")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
hash, err := hasher.Hash(ctx, data)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, hash)
|
||||
}
|
|
@ -26,7 +26,7 @@ func NewKeyManager(config *schema.OpenIDConnectConfiguration) (manager *KeyManag
|
|||
algs: map[string]*JWK{},
|
||||
}
|
||||
|
||||
for _, sjwk := range config.IssuerJWKS {
|
||||
for _, sjwk := range config.IssuerPrivateKeys {
|
||||
jwk := NewJWK(sjwk)
|
||||
|
||||
manager.kids[sjwk.KeyID] = jwk
|
||||
|
@ -47,7 +47,13 @@ type KeyManager struct {
|
|||
algs map[string]*JWK
|
||||
}
|
||||
|
||||
func (m *KeyManager) GetKIDFromAlgStrict(ctx context.Context, alg string) (kid string, err error) {
|
||||
// GetKeyID returns the default key id.
|
||||
func (m *KeyManager) GetKeyID(ctx context.Context) string {
|
||||
return m.kid
|
||||
}
|
||||
|
||||
// GetKeyIDFromAlgStrict returns the key id given an alg or an error if it doesn't exist.
|
||||
func (m *KeyManager) GetKeyIDFromAlgStrict(ctx context.Context, alg string) (kid string, err error) {
|
||||
if jwks, ok := m.algs[alg]; ok {
|
||||
return jwks.kid, nil
|
||||
}
|
||||
|
@ -55,7 +61,8 @@ func (m *KeyManager) GetKIDFromAlgStrict(ctx context.Context, alg string) (kid s
|
|||
return "", fmt.Errorf("alg not found")
|
||||
}
|
||||
|
||||
func (m *KeyManager) GetKIDFromAlg(ctx context.Context, alg string) string {
|
||||
// GetKeyIDFromAlg returns the key id given an alg or the default if it doesn't exist.
|
||||
func (m *KeyManager) GetKeyIDFromAlg(ctx context.Context, alg string) string {
|
||||
if jwks, ok := m.algs[alg]; ok {
|
||||
return jwks.kid
|
||||
}
|
||||
|
@ -63,6 +70,7 @@ func (m *KeyManager) GetKIDFromAlg(ctx context.Context, alg string) string {
|
|||
return m.kid
|
||||
}
|
||||
|
||||
// GetByAlg returns the JWK given an alg or nil if it doesn't exist.
|
||||
func (m *KeyManager) GetByAlg(ctx context.Context, alg string) *JWK {
|
||||
if jwk, ok := m.algs[alg]; ok {
|
||||
return jwk
|
||||
|
@ -71,6 +79,7 @@ func (m *KeyManager) GetByAlg(ctx context.Context, alg string) *JWK {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetByKID returns the JWK given an key id or nil if it doesn't exist. If given a blank string it returns the default.
|
||||
func (m *KeyManager) GetByKID(ctx context.Context, kid string) *JWK {
|
||||
if kid == "" {
|
||||
return m.kids[m.kid]
|
||||
|
@ -83,6 +92,7 @@ func (m *KeyManager) GetByKID(ctx context.Context, kid string) *JWK {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetByHeader returns the JWK a JWT header with the appropriate kid value or returns an error.
|
||||
func (m *KeyManager) GetByHeader(ctx context.Context, header fjwt.Mapper) (jwk *JWK, err error) {
|
||||
var (
|
||||
kid string
|
||||
|
@ -104,6 +114,7 @@ func (m *KeyManager) GetByHeader(ctx context.Context, header fjwt.Mapper) (jwk *
|
|||
return jwk, nil
|
||||
}
|
||||
|
||||
// GetByTokenString does an invalidated decode of a token to get the header, then calls GetByHeader.
|
||||
func (m *KeyManager) GetByTokenString(ctx context.Context, tokenString string) (jwk *JWK, err error) {
|
||||
var (
|
||||
token *jwt.Token
|
||||
|
@ -116,6 +127,7 @@ func (m *KeyManager) GetByTokenString(ctx context.Context, tokenString string) (
|
|||
return m.GetByHeader(ctx, &fjwt.Headers{Extra: token.Header})
|
||||
}
|
||||
|
||||
// Set returns the *jose.JSONWebKeySet.
|
||||
func (m *KeyManager) Set(ctx context.Context) *jose.JSONWebKeySet {
|
||||
keys := make([]jose.JSONWebKey, 0, len(m.kids))
|
||||
|
||||
|
@ -130,6 +142,7 @@ func (m *KeyManager) Set(ctx context.Context) *jose.JSONWebKeySet {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate implements the fosite jwt.Signer interface and automatically maps the underlying keys based on the JWK Header kid.
|
||||
func (m *KeyManager) Generate(ctx context.Context, claims fjwt.MapClaims, header fjwt.Mapper) (tokenString string, sig string, err error) {
|
||||
var jwk *JWK
|
||||
|
||||
|
@ -140,6 +153,7 @@ func (m *KeyManager) Generate(ctx context.Context, claims fjwt.MapClaims, header
|
|||
return jwk.Strategy().Generate(ctx, claims, header)
|
||||
}
|
||||
|
||||
// Validate implements the fosite jwt.Signer interface and automatically maps the underlying keys based on the JWK Header kid.
|
||||
func (m *KeyManager) Validate(ctx context.Context, tokenString string) (sig string, err error) {
|
||||
var jwk *JWK
|
||||
|
||||
|
@ -150,10 +164,12 @@ func (m *KeyManager) Validate(ctx context.Context, tokenString string) (sig stri
|
|||
return jwk.Strategy().Validate(ctx, tokenString)
|
||||
}
|
||||
|
||||
// Hash implements the fosite jwt.Signer interface.
|
||||
func (m *KeyManager) Hash(ctx context.Context, in []byte) (sum []byte, err error) {
|
||||
return m.GetByKID(ctx, "").Strategy().Hash(ctx, in)
|
||||
}
|
||||
|
||||
// Decode implements the fosite jwt.Signer interface and automatically maps the underlying keys based on the JWK Header kid.
|
||||
func (m *KeyManager) Decode(ctx context.Context, tokenString string) (token *fjwt.Token, err error) {
|
||||
var jwk *JWK
|
||||
|
||||
|
@ -164,14 +180,58 @@ func (m *KeyManager) Decode(ctx context.Context, tokenString string) (token *fjw
|
|||
return jwk.Strategy().Decode(ctx, tokenString)
|
||||
}
|
||||
|
||||
// GetSignature implements the fosite jwt.Signer interface.
|
||||
func (m *KeyManager) GetSignature(ctx context.Context, tokenString string) (sig string, err error) {
|
||||
return getTokenSignature(tokenString)
|
||||
}
|
||||
|
||||
// GetSigningMethodLength implements the fosite jwt.Signer interface.
|
||||
func (m *KeyManager) GetSigningMethodLength(ctx context.Context) (size int) {
|
||||
return m.GetByKID(ctx, "").Strategy().GetSigningMethodLength(ctx)
|
||||
}
|
||||
|
||||
// NewPublicJSONWebKeySetFromSchemaJWK creates a *jose.JSONWebKeySet from a slice of schema.JWK.
|
||||
func NewPublicJSONWebKeySetFromSchemaJWK(sjwks []schema.JWK) (jwks *jose.JSONWebKeySet) {
|
||||
n := len(sjwks)
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := make([]jose.JSONWebKey, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
jwk := jose.JSONWebKey{
|
||||
KeyID: sjwks[i].KeyID,
|
||||
Algorithm: sjwks[i].Algorithm,
|
||||
Use: sjwks[i].Use,
|
||||
Certificates: sjwks[i].CertificateChain.Certificates(),
|
||||
}
|
||||
|
||||
switch key := sjwks[i].Key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
jwk.Key = key
|
||||
case rsa.PublicKey:
|
||||
jwk.Key = &key
|
||||
case *rsa.PrivateKey:
|
||||
jwk.Key = key.PublicKey
|
||||
case *ecdsa.PublicKey:
|
||||
jwk.Key = key
|
||||
case ecdsa.PublicKey:
|
||||
jwk.Key = &key
|
||||
case *ecdsa.PrivateKey:
|
||||
jwk.Key = key.PublicKey
|
||||
}
|
||||
|
||||
keys[i] = jwk
|
||||
}
|
||||
|
||||
return &jose.JSONWebKeySet{
|
||||
Keys: keys,
|
||||
}
|
||||
}
|
||||
|
||||
// NewJWK creates a *JWK f rom a schema.JWK.
|
||||
func NewJWK(s schema.JWK) (jwk *JWK) {
|
||||
jwk = &JWK{
|
||||
kid: s.KeyID,
|
||||
|
@ -198,6 +258,7 @@ func NewJWK(s schema.JWK) (jwk *JWK) {
|
|||
return jwk
|
||||
}
|
||||
|
||||
// JWK is a representation layer over the *jose.JSONWebKey for convenience.
|
||||
type JWK struct {
|
||||
kid string
|
||||
use string
|
||||
|
@ -210,16 +271,24 @@ type JWK struct {
|
|||
thumbprint []byte
|
||||
}
|
||||
|
||||
// GetSigningMethod returns the jwt.SigningMethod for this *JWK.
|
||||
func (j *JWK) GetSigningMethod() jwt.SigningMethod {
|
||||
return j.alg
|
||||
}
|
||||
|
||||
// GetPrivateKey returns the Private Key for this *JWK.
|
||||
func (j *JWK) GetPrivateKey(ctx context.Context) (any, error) {
|
||||
return j.PrivateJWK(), nil
|
||||
}
|
||||
|
||||
// KeyID returns the Key ID for this *JWK.
|
||||
func (j *JWK) KeyID() string {
|
||||
return j.kid
|
||||
}
|
||||
|
||||
func (j *JWK) PrivateJWK() (jwk *jose.JSONWebKey) {
|
||||
return &jose.JSONWebKey{
|
||||
// DirectJWK directly returns the *JWK as a jose.JSONWebKey with the private key if appropriate.
|
||||
func (j *JWK) DirectJWK() (jwk jose.JSONWebKey) {
|
||||
return jose.JSONWebKey{
|
||||
Key: j.key,
|
||||
KeyID: j.kid,
|
||||
Algorithm: j.alg.Alg(),
|
||||
|
@ -230,10 +299,23 @@ func (j *JWK) PrivateJWK() (jwk *jose.JSONWebKey) {
|
|||
}
|
||||
}
|
||||
|
||||
func (j *JWK) JWK() (jwk jose.JSONWebKey) {
|
||||
return j.PrivateJWK().Public()
|
||||
// PrivateJWK directly returns the *JWK as a *jose.JSONWebKey with the private key if appropriate.
|
||||
func (j *JWK) PrivateJWK() (jwk *jose.JSONWebKey) {
|
||||
value := j.DirectJWK()
|
||||
|
||||
return &value
|
||||
}
|
||||
|
||||
// JWK directly returns the *JWK as a jose.JSONWebKey specifically without the private key.
|
||||
func (j *JWK) JWK() (jwk jose.JSONWebKey) {
|
||||
if jwk = j.DirectJWK(); jwk.IsPublic() {
|
||||
return jwk
|
||||
}
|
||||
|
||||
return jwk.Public()
|
||||
}
|
||||
|
||||
// Strategy returns the fosite jwt.Signer.
|
||||
func (j *JWK) Strategy() (strategy fjwt.Signer) {
|
||||
return &Signer{
|
||||
hash: j.hash,
|
||||
|
@ -250,6 +332,7 @@ type Signer struct {
|
|||
GetPrivateKey fjwt.GetPrivateKeyFunc
|
||||
}
|
||||
|
||||
// GetPublicKey returns the PublicKey for this Signer.
|
||||
func (j *Signer) GetPublicKey(ctx context.Context) (key crypto.PublicKey, err error) {
|
||||
var k any
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestKeyManager(t *testing.T) {
|
||||
|
@ -19,81 +21,81 @@ func TestKeyManager(t *testing.T) {
|
|||
Discovery: schema.OpenIDConnectDiscovery{
|
||||
DefaultKeyID: "kid-RS256-sig",
|
||||
},
|
||||
IssuerJWKS: []schema.JWK{
|
||||
IssuerPrivateKeys: []schema.JWK{
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA256,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA384,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA512,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA256,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA384,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA512,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP256AndSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP256AndSHA256,
|
||||
Key: keyECDSAP256,
|
||||
CertificateChain: certECDSAP256,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP384AndSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP384AndSHA384,
|
||||
Key: keyECDSAP384,
|
||||
CertificateChain: certECDSAP384,
|
||||
},
|
||||
{
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP521AndSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP521AndSHA512,
|
||||
Key: keyECDSAP521,
|
||||
CertificateChain: certECDSAP521,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, key := range config.IssuerJWKS {
|
||||
config.IssuerJWKS[i].KeyID = fmt.Sprintf("kid-%s-%s", key.Algorithm, key.Use)
|
||||
for i, key := range config.IssuerPrivateKeys {
|
||||
config.IssuerPrivateKeys[i].KeyID = fmt.Sprintf("kid-%s-%s", key.Algorithm, key.Use)
|
||||
}
|
||||
|
||||
manager := NewKeyManager(config)
|
||||
manager := oidc.NewKeyManager(config)
|
||||
|
||||
assert.NotNil(t, manager)
|
||||
|
||||
assert.Len(t, manager.kids, len(config.IssuerJWKS))
|
||||
assert.Len(t, manager.algs, len(config.IssuerJWKS))
|
||||
|
||||
assert.Equal(t, "kid-RS256-sig", manager.kid)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
assert.Equal(t, "kid-RS256-sig", manager.GetKeyID(ctx))
|
||||
|
||||
var (
|
||||
jwk *JWK
|
||||
jwk *oidc.JWK
|
||||
tokenString, sig string
|
||||
sum []byte
|
||||
token *fjwt.Token
|
||||
err error
|
||||
)
|
||||
|
||||
|
@ -107,7 +109,7 @@ func TestKeyManager(t *testing.T) {
|
|||
assert.NotNil(t, jwk)
|
||||
assert.Equal(t, config.Discovery.DefaultKeyID, jwk.KeyID())
|
||||
|
||||
jwk, err = manager.GetByHeader(ctx, &fjwt.Headers{Extra: map[string]any{JWTHeaderKeyIdentifier: "notalg"}})
|
||||
jwk, err = manager.GetByHeader(ctx, &fjwt.Headers{Extra: map[string]any{oidc.JWTHeaderKeyIdentifier: "notalg"}})
|
||||
assert.EqualError(t, err, "jwt header 'kid' with value 'notalg' does not match a managed jwk")
|
||||
assert.Nil(t, jwk)
|
||||
|
||||
|
@ -119,17 +121,17 @@ func TestKeyManager(t *testing.T) {
|
|||
assert.EqualError(t, err, "jwt header was nil")
|
||||
assert.Nil(t, jwk)
|
||||
|
||||
kid, err := manager.GetKIDFromAlgStrict(ctx, "notalg")
|
||||
kid, err := manager.GetKeyIDFromAlgStrict(ctx, "notalg")
|
||||
assert.EqualError(t, err, "alg not found")
|
||||
assert.Equal(t, "", kid)
|
||||
|
||||
kid = manager.GetKIDFromAlg(ctx, "notalg")
|
||||
kid = manager.GetKeyIDFromAlg(ctx, "notalg")
|
||||
assert.Equal(t, config.Discovery.DefaultKeyID, kid)
|
||||
|
||||
set := manager.Set(ctx)
|
||||
|
||||
assert.NotNil(t, set)
|
||||
assert.Len(t, set.Keys, len(config.IssuerJWKS))
|
||||
assert.Len(t, set.Keys, len(config.IssuerPrivateKeys))
|
||||
|
||||
data, err := json.Marshal(&set)
|
||||
assert.NoError(t, err)
|
||||
|
@ -139,9 +141,32 @@ func TestKeyManager(t *testing.T) {
|
|||
assert.NoError(t, json.Unmarshal(data, &out))
|
||||
assert.Equal(t, *set, out)
|
||||
|
||||
for _, alg := range []string{SigningAlgRSAUsingSHA256, SigningAlgRSAUsingSHA384, SigningAlgRSAPSSUsingSHA512, SigningAlgRSAPSSUsingSHA256, SigningAlgRSAPSSUsingSHA384, SigningAlgRSAPSSUsingSHA512, SigningAlgECDSAUsingP256AndSHA256, SigningAlgECDSAUsingP384AndSHA384, SigningAlgECDSAUsingP521AndSHA512} {
|
||||
jwk, err = manager.GetByTokenString(ctx, badTokenString)
|
||||
assert.EqualError(t, err, "token contains an invalid number of segments")
|
||||
assert.Nil(t, jwk)
|
||||
|
||||
tokenString, sig, err = manager.Generate(ctx, nil, nil)
|
||||
assert.EqualError(t, err, "error getting jwk from header: jwt header was nil")
|
||||
assert.Equal(t, "", tokenString)
|
||||
assert.Equal(t, "", sig)
|
||||
|
||||
sig, err = manager.Validate(ctx, badTokenString)
|
||||
assert.EqualError(t, err, "error getting jwk from token string: token contains an invalid number of segments")
|
||||
assert.Equal(t, "", sig)
|
||||
|
||||
token, err = manager.Decode(ctx, badTokenString)
|
||||
assert.EqualError(t, err, "error getting jwk from token string: token contains an invalid number of segments")
|
||||
assert.Nil(t, token)
|
||||
|
||||
sum, err = manager.Hash(ctx, []byte("abc"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", fmt.Sprintf("%x", sum))
|
||||
|
||||
assert.Equal(t, crypto.SHA256.Size(), manager.GetSigningMethodLength(ctx))
|
||||
|
||||
for _, alg := range []string{oidc.SigningAlgRSAUsingSHA256, oidc.SigningAlgRSAUsingSHA384, oidc.SigningAlgRSAPSSUsingSHA512, oidc.SigningAlgRSAPSSUsingSHA256, oidc.SigningAlgRSAPSSUsingSHA384, oidc.SigningAlgRSAPSSUsingSHA512, oidc.SigningAlgECDSAUsingP256AndSHA256, oidc.SigningAlgECDSAUsingP384AndSHA384, oidc.SigningAlgECDSAUsingP521AndSHA512} {
|
||||
t.Run(alg, func(t *testing.T) {
|
||||
expectedKID := fmt.Sprintf("kid-%s-%s", alg, KeyUseSignature)
|
||||
expectedKID := fmt.Sprintf("kid-%s-%s", alg, oidc.KeyUseSignature)
|
||||
|
||||
t.Run("ShouldGetCorrectKey", func(t *testing.T) {
|
||||
jwk = manager.GetByKID(ctx, expectedKID)
|
||||
|
@ -151,17 +176,17 @@ func TestKeyManager(t *testing.T) {
|
|||
jwk = manager.GetByAlg(ctx, alg)
|
||||
assert.NotNil(t, jwk)
|
||||
|
||||
assert.Equal(t, alg, jwk.alg.Alg())
|
||||
assert.Equal(t, alg, jwk.GetSigningMethod().Alg())
|
||||
assert.Equal(t, expectedKID, jwk.KeyID())
|
||||
|
||||
kid, err = manager.GetKIDFromAlgStrict(ctx, alg)
|
||||
kid, err = manager.GetKeyIDFromAlgStrict(ctx, alg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedKID, kid)
|
||||
|
||||
kid = manager.GetKIDFromAlg(ctx, alg)
|
||||
kid = manager.GetKeyIDFromAlg(ctx, alg)
|
||||
assert.Equal(t, expectedKID, kid)
|
||||
|
||||
jwk, err = manager.GetByHeader(ctx, &fjwt.Headers{Extra: map[string]any{JWTHeaderKeyIdentifier: expectedKID}})
|
||||
jwk, err = manager.GetByHeader(ctx, &fjwt.Headers{Extra: map[string]any{oidc.JWTHeaderKeyIdentifier: expectedKID}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, jwk)
|
||||
|
||||
|
@ -169,10 +194,9 @@ func TestKeyManager(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("ShouldUseCorrectSigner", func(t *testing.T) {
|
||||
var tokenString, sig, sigb string
|
||||
var token *fjwt.Token
|
||||
var sigb string
|
||||
|
||||
tokenString, sig, err = manager.Generate(ctx, fjwt.MapClaims{}, &fjwt.Headers{Extra: map[string]any{JWTHeaderKeyIdentifier: expectedKID}})
|
||||
tokenString, sig, err = manager.Generate(ctx, fjwt.MapClaims{}, &fjwt.Headers{Extra: map[string]any{oidc.JWTHeaderKeyIdentifier: expectedKID}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
sigb, err = manager.GetSignature(ctx, tokenString)
|
||||
|
@ -185,10 +209,9 @@ func TestKeyManager(t *testing.T) {
|
|||
|
||||
token, err = manager.Decode(ctx, tokenString)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedKID, token.Header[JWTHeaderKeyIdentifier])
|
||||
assert.Equal(t, expectedKID, token.Header[oidc.JWTHeaderKeyIdentifier])
|
||||
|
||||
jwk, err = manager.GetByTokenString(ctx, tokenString)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
sigb, err = jwk.Strategy().Validate(ctx, tokenString)
|
||||
|
@ -206,8 +229,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-rs256",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA256,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -215,8 +238,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-rs384",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA384,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -224,8 +247,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-rs512",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA512,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -233,8 +256,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-rs256",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA256,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -242,8 +265,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-rs384",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA384,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -251,8 +274,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-rs512",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAUsingSHA512,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -260,8 +283,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-rs256",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA256,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -269,8 +292,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-ps384",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA384,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -278,8 +301,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa2048-ps512",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA512,
|
||||
Key: keyRSA2048,
|
||||
CertificateChain: certRSA2048,
|
||||
},
|
||||
|
@ -287,8 +310,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-ps256",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA256,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -296,8 +319,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-ps384",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA384,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -305,8 +328,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "rsa4096-ps512",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgRSAPSSUsingSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgRSAPSSUsingSHA512,
|
||||
Key: keyRSA4096,
|
||||
CertificateChain: certRSA4096,
|
||||
},
|
||||
|
@ -314,8 +337,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "ecdsaP256",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP256AndSHA256,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP256AndSHA256,
|
||||
Key: keyECDSAP256,
|
||||
CertificateChain: certECDSAP256,
|
||||
},
|
||||
|
@ -323,8 +346,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "ecdsaP384",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP384AndSHA384,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP384AndSHA384,
|
||||
Key: keyECDSAP384,
|
||||
CertificateChain: certECDSAP384,
|
||||
},
|
||||
|
@ -332,8 +355,8 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
{
|
||||
schema.JWK{
|
||||
KeyID: "ecdsaP521",
|
||||
Use: KeyUseSignature,
|
||||
Algorithm: SigningAlgECDSAUsingP521AndSHA512,
|
||||
Use: oidc.KeyUseSignature,
|
||||
Algorithm: oidc.SigningAlgECDSAUsingP521AndSHA512,
|
||||
Key: keyECDSAP521,
|
||||
CertificateChain: certECDSAP521,
|
||||
},
|
||||
|
@ -344,24 +367,28 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
t.Run(tc.have.KeyID, func(t *testing.T) {
|
||||
t.Run("Generating", func(t *testing.T) {
|
||||
var (
|
||||
jwk *JWK
|
||||
jwk *oidc.JWK
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
jwk = NewJWK(tc.have)
|
||||
jwk = oidc.NewJWK(tc.have)
|
||||
|
||||
signer := jwk.Strategy()
|
||||
|
||||
claims := fjwt.MapClaims{}
|
||||
header := &fjwt.Headers{
|
||||
Extra: map[string]any{
|
||||
"kid": jwk.kid,
|
||||
oidc.JWTHeaderKeyIdentifier: jwk.KeyID(),
|
||||
},
|
||||
}
|
||||
|
||||
tokenString, sig, err := signer.Generate(ctx, claims, header)
|
||||
tokenString, sig, err := signer.Generate(ctx, nil, nil)
|
||||
assert.EqualError(t, err, "either claims or header is nil")
|
||||
assert.Equal(t, "", tokenString)
|
||||
assert.Equal(t, "", sig)
|
||||
|
||||
tokenString, sig, err = signer.Generate(ctx, claims, header)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "", tokenString)
|
||||
assert.NotEqual(t, "", sig)
|
||||
|
@ -376,7 +403,7 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
fmt.Println(tokenString)
|
||||
|
||||
assert.True(t, token.Valid())
|
||||
assert.Equal(t, jwk.alg.Alg(), string(token.Method))
|
||||
assert.Equal(t, jwk.GetSigningMethod().Alg(), string(token.Method))
|
||||
|
||||
sigv, err := signer.Validate(ctx, tokenString)
|
||||
assert.NoError(t, err)
|
||||
|
@ -385,19 +412,19 @@ func TestJWKFunctionality(t *testing.T) {
|
|||
|
||||
t.Run("Marshalling", func(t *testing.T) {
|
||||
var (
|
||||
jwk *JWK
|
||||
jwk *oidc.JWK
|
||||
out jose.JSONWebKey
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
jwk = NewJWK(tc.have)
|
||||
jwk = oidc.NewJWK(tc.have)
|
||||
|
||||
strategy := jwk.Strategy()
|
||||
|
||||
assert.NotNil(t, strategy)
|
||||
|
||||
signer, ok := strategy.(*Signer)
|
||||
signer, ok := strategy.(*oidc.Signer)
|
||||
|
||||
require.True(t, ok)
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateToken(t *testing.T) {
|
||||
sig, err := validateToken("none", nil)
|
||||
assert.Equal(t, "", sig)
|
||||
assert.EqualError(t, err, "square/go-jose: compact JWS format must have three parts")
|
||||
}
|
||||
|
||||
func TestGetTokenSignature(t *testing.T) {
|
||||
sig, err := getTokenSignature("abc.123")
|
||||
assert.Equal(t, "", sig)
|
||||
assert.EqualError(t, err, "header, body and signature must all be set")
|
||||
}
|
||||
|
||||
func TestAssign(t *testing.T) {
|
||||
a := map[string]any{
|
||||
"a": "valuea",
|
||||
"c": "valuea",
|
||||
}
|
||||
|
||||
b := map[string]any{
|
||||
"b": "valueb",
|
||||
"c": "valueb",
|
||||
}
|
||||
|
||||
c := assign(a, b)
|
||||
|
||||
assert.Equal(t, "valuea", c["a"])
|
||||
assert.Equal(t, "valueb", c["b"])
|
||||
assert.Equal(t, "valuea", c["c"])
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
|
@ -9,16 +8,17 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_NotConfigured(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(nil, nil, nil)
|
||||
provider := oidc.NewOpenIDConnectProvider(nil, nil, nil)
|
||||
|
||||
assert.Nil(t, provider)
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProvider_ShouldEnableOptionalDiscoveryValues(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
EnablePKCEPlainChallenge: true,
|
||||
|
@ -26,7 +26,7 @@ func TestNewOpenIDConnectProvider_ShouldEnableOptionalDiscoveryValues(t *testing
|
|||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: myclient,
|
||||
Secret: MustDecodeSecret(badsecret),
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
SectorIdentifier: url.URL{Host: examplecomsid},
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
|
@ -41,23 +41,23 @@ func TestNewOpenIDConnectProvider_ShouldEnableOptionalDiscoveryValues(t *testing
|
|||
disco := provider.GetOpenIDConnectWellKnownConfiguration(examplecom)
|
||||
|
||||
assert.Len(t, disco.SubjectTypesSupported, 2)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePairwise)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, oidc.SubjectTypePairwise)
|
||||
|
||||
assert.Len(t, disco.CodeChallengeMethodsSupported, 2)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, PKCEChallengeMethodSHA256)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, PKCEChallengeMethodSHA256)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, oidc.PKCEChallengeMethodSHA256)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, oidc.PKCEChallengeMethodSHA256)
|
||||
}
|
||||
|
||||
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
provider := oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: badhmac,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
|
@ -66,16 +66,16 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *tes
|
|||
{
|
||||
ID: "b-client",
|
||||
Description: "Normal Description",
|
||||
Secret: MustDecodeSecret("$plaintext$b-client-secret"),
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
Policy: twofactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
Scopes: []string{
|
||||
ScopeGroups,
|
||||
oidc.ScopeGroups,
|
||||
},
|
||||
GrantTypes: []string{
|
||||
GrantTypeRefreshToken,
|
||||
oidc.GrantTypeRefreshToken,
|
||||
},
|
||||
ResponseTypes: []string{
|
||||
"token",
|
||||
|
@ -87,285 +87,3 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *tes
|
|||
|
||||
assert.NotNil(t, provider)
|
||||
}
|
||||
|
||||
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfiguration(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOpenIDConnectWellKnownConfiguration(examplecom)
|
||||
|
||||
assert.Equal(t, examplecom, disco.Issuer)
|
||||
assert.Equal(t, "https://example.com/jwks.json", disco.JWKSURI)
|
||||
assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/userinfo", disco.UserinfoEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint)
|
||||
assert.Equal(t, "", disco.RegistrationEndpoint)
|
||||
|
||||
assert.Len(t, disco.CodeChallengeMethodsSupported, 1)
|
||||
assert.Contains(t, disco.CodeChallengeMethodsSupported, PKCEChallengeMethodSHA256)
|
||||
|
||||
assert.Len(t, disco.ScopesSupported, 5)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeOpenID)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeOfflineAccess)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeProfile)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeGroups)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeEmail)
|
||||
|
||||
assert.Len(t, disco.ResponseModesSupported, 3)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeFormPost)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeQuery)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeFragment)
|
||||
|
||||
assert.Len(t, disco.SubjectTypesSupported, 2)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePairwise)
|
||||
|
||||
assert.Len(t, disco.ResponseTypesSupported, 7)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeAuthorizationCodeFlow)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowBoth)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowBoth)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthMethodsSupported, 4)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.RevocationEndpointAuthMethodsSupported, 4)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.RevocationEndpointAuthMethodsSupported, ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.IntrospectionEndpointAuthMethodsSupported, 2)
|
||||
assert.Contains(t, disco.IntrospectionEndpointAuthMethodsSupported, ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.IntrospectionEndpointAuthMethodsSupported, ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.GrantTypesSupported, 3)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeAuthorizationCode)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeRefreshToken)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeImplicit)
|
||||
|
||||
assert.Len(t, disco.RevocationEndpointAuthSigningAlgValuesSupported, 3)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[0], SigningAlgHMACUsingSHA256)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[1], SigningAlgHMACUsingSHA384)
|
||||
assert.Equal(t, disco.RevocationEndpointAuthSigningAlgValuesSupported[2], SigningAlgHMACUsingSHA512)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthSigningAlgValuesSupported, 3)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[0], SigningAlgHMACUsingSHA256)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[1], SigningAlgHMACUsingSHA384)
|
||||
assert.Equal(t, disco.TokenEndpointAuthSigningAlgValuesSupported[2], SigningAlgHMACUsingSHA512)
|
||||
|
||||
assert.Len(t, disco.IDTokenSigningAlgValuesSupported, 1)
|
||||
assert.Contains(t, disco.IDTokenSigningAlgValuesSupported, SigningAlgRSAUsingSHA256)
|
||||
|
||||
assert.Len(t, disco.UserinfoSigningAlgValuesSupported, 2)
|
||||
assert.Equal(t, disco.UserinfoSigningAlgValuesSupported[0], SigningAlgRSAUsingSHA256)
|
||||
assert.Equal(t, disco.UserinfoSigningAlgValuesSupported[1], SigningAlgNone)
|
||||
|
||||
require.Len(t, disco.RequestObjectSigningAlgValuesSupported, 2)
|
||||
assert.Equal(t, SigningAlgRSAUsingSHA256, disco.RequestObjectSigningAlgValuesSupported[0])
|
||||
assert.Equal(t, SigningAlgNone, disco.RequestObjectSigningAlgValuesSupported[1])
|
||||
|
||||
assert.Len(t, disco.ClaimsSupported, 18)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthenticationMethodsReference)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAudience)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthorizedParty)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimClientIdentifier)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimExpirationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimIssuedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimIssuer)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimJWTID)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimRequestedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimSubject)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthenticationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimNonce)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimPreferredEmail)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimEmailVerified)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimEmailAlts)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimGroups)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimPreferredUsername)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimFullName)
|
||||
|
||||
assert.Len(t, disco.PromptValuesSupported, 2)
|
||||
assert.Contains(t, disco.PromptValuesSupported, PromptConsent)
|
||||
assert.Contains(t, disco.PromptValuesSupported, PromptNone)
|
||||
}
|
||||
|
||||
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOAuth2WellKnownConfiguration(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOAuth2WellKnownConfiguration(examplecom)
|
||||
|
||||
assert.Equal(t, examplecom, disco.Issuer)
|
||||
assert.Equal(t, "https://example.com/jwks.json", disco.JWKSURI)
|
||||
assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint)
|
||||
assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint)
|
||||
assert.Equal(t, "", disco.RegistrationEndpoint)
|
||||
|
||||
require.Len(t, disco.CodeChallengeMethodsSupported, 1)
|
||||
assert.Equal(t, "S256", disco.CodeChallengeMethodsSupported[0])
|
||||
|
||||
assert.Len(t, disco.ScopesSupported, 5)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeOpenID)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeOfflineAccess)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeProfile)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeGroups)
|
||||
assert.Contains(t, disco.ScopesSupported, ScopeEmail)
|
||||
|
||||
assert.Len(t, disco.ResponseModesSupported, 3)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeFormPost)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeQuery)
|
||||
assert.Contains(t, disco.ResponseModesSupported, ResponseModeFragment)
|
||||
|
||||
assert.Len(t, disco.SubjectTypesSupported, 2)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePublic)
|
||||
assert.Contains(t, disco.SubjectTypesSupported, SubjectTypePairwise)
|
||||
|
||||
assert.Len(t, disco.ResponseTypesSupported, 7)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeAuthorizationCodeFlow)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeImplicitFlowBoth)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowIDToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowToken)
|
||||
assert.Contains(t, disco.ResponseTypesSupported, ResponseTypeHybridFlowBoth)
|
||||
|
||||
assert.Len(t, disco.TokenEndpointAuthMethodsSupported, 4)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretBasic)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretPost)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodClientSecretJWT)
|
||||
assert.Contains(t, disco.TokenEndpointAuthMethodsSupported, ClientAuthMethodNone)
|
||||
|
||||
assert.Len(t, disco.GrantTypesSupported, 3)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeAuthorizationCode)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeRefreshToken)
|
||||
assert.Contains(t, disco.GrantTypesSupported, GrantTypeImplicit)
|
||||
|
||||
assert.Len(t, disco.ClaimsSupported, 18)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthenticationMethodsReference)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAudience)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthorizedParty)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimClientIdentifier)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimExpirationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimIssuedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimIssuer)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimJWTID)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimRequestedAt)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimSubject)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimAuthenticationTime)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimNonce)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimPreferredEmail)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimEmailVerified)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimEmailAlts)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimGroups)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimPreferredUsername)
|
||||
assert.Contains(t, disco.ClaimsSupported, ClaimFullName)
|
||||
}
|
||||
|
||||
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfigurationWithPlainPKCE(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
EnablePKCEPlainChallenge: true,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
require.NotNil(t, provider)
|
||||
|
||||
disco := provider.GetOpenIDConnectWellKnownConfiguration(examplecom)
|
||||
|
||||
require.Len(t, disco.CodeChallengeMethodsSupported, 2)
|
||||
assert.Equal(t, PKCEChallengeMethodSHA256, disco.CodeChallengeMethodsSupported[0])
|
||||
assert.Equal(t, PKCEChallengeMethodPlain, disco.CodeChallengeMethodsSupported[1])
|
||||
}
|
||||
|
||||
func TestNewOpenIDConnectProviderDiscovery(t *testing.T) {
|
||||
provider := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
HMACSecret: "asbdhaaskmdlkamdklasmdlkams",
|
||||
EnablePKCEPlainChallenge: true,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "a-client",
|
||||
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
|
||||
Policy: onefactor,
|
||||
RedirectURIs: []string{
|
||||
"https://google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
|
||||
a := provider.GetOpenIDConnectWellKnownConfiguration("https://auth.example.com")
|
||||
|
||||
data, err := json.Marshal(&a)
|
||||
assert.NoError(t, err)
|
||||
|
||||
b := OpenIDConnectWellKnownConfiguration{}
|
||||
|
||||
assert.NoError(t, json.Unmarshal(data, &b))
|
||||
|
||||
assert.Equal(t, a, b)
|
||||
|
||||
y := provider.GetOAuth2WellKnownConfiguration("https://auth.example.com")
|
||||
|
||||
data, err = json.Marshal(&y)
|
||||
assert.NoError(t, err)
|
||||
|
||||
z := OAuth2WellKnownConfiguration{}
|
||||
|
||||
assert.NoError(t, json.Unmarshal(data, &z))
|
||||
|
||||
assert.Equal(t, y, z)
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ func (s *Store) CreatePKCERequestSession(ctx context.Context, signature string,
|
|||
// DeletePKCERequestSession marks the authorization request for a given PKCE request as deleted.
|
||||
// This implements a portion of pkce.PKCERequestStorage.
|
||||
func (s *Store) DeletePKCERequestSession(ctx context.Context, signature string) (err error) {
|
||||
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypeAccessToken, signature)
|
||||
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypePKCEChallenge, signature)
|
||||
}
|
||||
|
||||
// GetPKCERequestSession gets the authorization request for a given PKCE request.
|
||||
|
@ -254,7 +254,7 @@ func (s *Store) CreateOpenIDConnectSession(ctx context.Context, authorizeCode st
|
|||
// DeleteOpenIDConnectSession just implements the method required by fosite even though it's unused.
|
||||
// This implements a portion of openid.OpenIDConnectRequestStorage.
|
||||
func (s *Store) DeleteOpenIDConnectSession(ctx context.Context, authorizeCode string) (err error) {
|
||||
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypeAccessToken, authorizeCode)
|
||||
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypeOpenIDConnect, authorizeCode)
|
||||
}
|
||||
|
||||
// GetOpenIDConnectSession returns error:
|
||||
|
|
|
@ -1,19 +1,30 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/mocks"
|
||||
"github.com/authelia/authelia/v4/internal/model"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
"github.com/authelia/authelia/v4/internal/storage"
|
||||
)
|
||||
|
||||
func TestOpenIDConnectStore_GetClientPolicy(t *testing.T) {
|
||||
s := NewStore(&schema.OpenIDConnectConfiguration{
|
||||
s := oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
|
@ -21,15 +32,15 @@ func TestOpenIDConnectStore_GetClientPolicy(t *testing.T) {
|
|||
ID: myclient,
|
||||
Description: myclientdesc,
|
||||
Policy: onefactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
},
|
||||
{
|
||||
ID: "myotherclient",
|
||||
Description: myclientdesc,
|
||||
Policy: twofactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
|
@ -45,7 +56,7 @@ func TestOpenIDConnectStore_GetClientPolicy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOpenIDConnectStore_GetInternalClient(t *testing.T) {
|
||||
s := NewStore(&schema.OpenIDConnectConfiguration{
|
||||
s := oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
|
@ -53,8 +64,8 @@ func TestOpenIDConnectStore_GetInternalClient(t *testing.T) {
|
|||
ID: myclient,
|
||||
Description: myclientdesc,
|
||||
Policy: onefactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
|
@ -76,11 +87,11 @@ func TestOpenIDConnectStore_GetInternalClient_ValidClient(t *testing.T) {
|
|||
ID: id,
|
||||
Description: myclientdesc,
|
||||
Policy: onefactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
}
|
||||
|
||||
s := NewStore(&schema.OpenIDConnectConfiguration{
|
||||
s := oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{c1},
|
||||
|
@ -92,11 +103,11 @@ func TestOpenIDConnectStore_GetInternalClient_ValidClient(t *testing.T) {
|
|||
assert.Equal(t, id, client.GetID())
|
||||
assert.Equal(t, myclientdesc, client.GetDescription())
|
||||
assert.Equal(t, fosite.Arguments(c1.Scopes), client.GetScopes())
|
||||
assert.Equal(t, fosite.Arguments([]string{GrantTypeAuthorizationCode}), client.GetGrantTypes())
|
||||
assert.Equal(t, fosite.Arguments([]string{ResponseTypeAuthorizationCodeFlow}), client.GetResponseTypes())
|
||||
assert.Equal(t, fosite.Arguments([]string{oidc.GrantTypeAuthorizationCode}), client.GetGrantTypes())
|
||||
assert.Equal(t, fosite.Arguments([]string{oidc.ResponseTypeAuthorizationCodeFlow}), client.GetResponseTypes())
|
||||
assert.Equal(t, []string(nil), client.GetRedirectURIs())
|
||||
assert.Equal(t, authorization.OneFactor, client.GetAuthorizationPolicy())
|
||||
assert.Equal(t, "$plaintext$mysecret", client.GetSecret().Encode())
|
||||
assert.Equal(t, "$plaintext$client-secret", client.GetSecret().Encode())
|
||||
}
|
||||
|
||||
func TestOpenIDConnectStore_GetInternalClient_InvalidClient(t *testing.T) {
|
||||
|
@ -104,11 +115,11 @@ func TestOpenIDConnectStore_GetInternalClient_InvalidClient(t *testing.T) {
|
|||
ID: myclient,
|
||||
Description: myclientdesc,
|
||||
Policy: onefactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
}
|
||||
|
||||
s := NewStore(&schema.OpenIDConnectConfiguration{
|
||||
s := oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{c1},
|
||||
|
@ -120,7 +131,7 @@ func TestOpenIDConnectStore_GetInternalClient_InvalidClient(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOpenIDConnectStore_IsValidClientID(t *testing.T) {
|
||||
s := NewStore(&schema.OpenIDConnectConfiguration{
|
||||
s := oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||
IssuerPrivateKey: keyRSA2048,
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
|
@ -128,8 +139,8 @@ func TestOpenIDConnectStore_IsValidClientID(t *testing.T) {
|
|||
ID: myclient,
|
||||
Description: myclientdesc,
|
||||
Policy: onefactor,
|
||||
Scopes: []string{ScopeOpenID, ScopeProfile},
|
||||
Secret: MustDecodeSecret("$plaintext$mysecret"),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
|
@ -140,3 +151,516 @@ func TestOpenIDConnectStore_IsValidClientID(t *testing.T) {
|
|||
assert.True(t, validClient)
|
||||
assert.False(t, invalidClient)
|
||||
}
|
||||
|
||||
func TestStoreSuite(t *testing.T) {
|
||||
suite.Run(t, &StoreSuite{})
|
||||
}
|
||||
|
||||
type StoreSuite struct {
|
||||
suite.Suite
|
||||
|
||||
ctx context.Context
|
||||
ctrl *gomock.Controller
|
||||
mock *mocks.MockStorage
|
||||
store *oidc.Store
|
||||
}
|
||||
|
||||
func (s *StoreSuite) SetupTest() {
|
||||
s.ctx = context.Background()
|
||||
s.ctrl = gomock.NewController(s.T())
|
||||
s.mock = mocks.NewMockStorage(s.ctrl)
|
||||
s.store = oidc.NewStore(&schema.OpenIDConnectConfiguration{
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "hs256",
|
||||
Secret: tOpenIDConnectPBKDF2ClientSecret,
|
||||
Policy: authorization.OneFactor.String(),
|
||||
RedirectURIs: []string{
|
||||
"https://client.example.com",
|
||||
},
|
||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
|
||||
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA256,
|
||||
},
|
||||
}}, s.mock)
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestGetSubject() {
|
||||
s.T().Run("GenerateNew", func(t *testing.T) {
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john").
|
||||
Return(nil, nil)
|
||||
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveUserOpaqueIdentifier(s.ctx, gomock.Any()).
|
||||
Return(nil)
|
||||
|
||||
opaqueID, err := s.store.GetSubject(s.ctx, "", "john")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, uint32(0), opaqueID)
|
||||
})
|
||||
|
||||
s.T().Run("ReturnDatabaseErrorOnLoad", func(t *testing.T) {
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john").
|
||||
Return(nil, fmt.Errorf("failed to load"))
|
||||
|
||||
opaqueID, err := s.store.GetSubject(s.ctx, "", "john")
|
||||
|
||||
assert.EqualError(t, err, "failed to load")
|
||||
assert.Equal(t, uint32(0), opaqueID.ID())
|
||||
})
|
||||
|
||||
s.T().Run("ReturnDatabaseErrorOnSave", func(t *testing.T) {
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john").
|
||||
Return(nil, nil)
|
||||
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveUserOpaqueIdentifier(s.ctx, gomock.Any()).
|
||||
Return(fmt.Errorf("failed to save"))
|
||||
|
||||
opaqueID, err := s.store.GetSubject(s.ctx, "", "john")
|
||||
|
||||
assert.EqualError(t, err, "failed to save")
|
||||
assert.Equal(t, uint32(0), opaqueID.ID())
|
||||
})
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestTx() {
|
||||
gomock.InOrder(
|
||||
s.mock.EXPECT().BeginTX(s.ctx).Return(s.ctx, nil),
|
||||
s.mock.EXPECT().Commit(s.ctx).Return(nil),
|
||||
s.mock.EXPECT().Rollback(s.ctx).Return(nil),
|
||||
s.mock.EXPECT().BeginTX(s.ctx).Return(nil, fmt.Errorf("failed to begin")),
|
||||
s.mock.EXPECT().Commit(s.ctx).Return(fmt.Errorf("failed to commit")),
|
||||
s.mock.EXPECT().Rollback(s.ctx).Return(fmt.Errorf("failed to rollback")),
|
||||
)
|
||||
|
||||
x, err := s.store.BeginTX(s.ctx)
|
||||
s.Equal(s.ctx, x)
|
||||
s.NoError(err)
|
||||
s.NoError(s.store.Commit(s.ctx))
|
||||
s.NoError(s.store.Rollback(s.ctx))
|
||||
|
||||
x, err = s.store.BeginTX(s.ctx)
|
||||
s.Equal(nil, x)
|
||||
s.EqualError(err, "failed to begin")
|
||||
s.EqualError(s.store.Commit(s.ctx), "failed to commit")
|
||||
s.EqualError(s.store.Rollback(s.ctx), "failed to rollback")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestClientAssertionJWTValid() {
|
||||
gomock.InOrder(
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63").
|
||||
Return(&model.OAuth2BlacklistedJTI{
|
||||
ID: 1,
|
||||
Signature: "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63",
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068").
|
||||
Return(&model.OAuth2BlacklistedJTI{
|
||||
ID: 1,
|
||||
Signature: "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068",
|
||||
ExpiresAt: time.Now().Add(-time.Hour),
|
||||
}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6").
|
||||
Return(nil, fmt.Errorf("failed to load")),
|
||||
)
|
||||
|
||||
s.EqualError(s.store.ClientAssertionJWTValid(s.ctx, "066ee771-e156-4886-b99f-ee09b0d3edf4"), "jti_known")
|
||||
s.NoError(s.store.ClientAssertionJWTValid(s.ctx, "5dad3ff7-e4f2-41b6-98a3-b73d872076ce"))
|
||||
s.EqualError(s.store.ClientAssertionJWTValid(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "failed to load")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestCreateSessions() {
|
||||
challenge := uuid.Must(uuid.NewRandom())
|
||||
session := &model.OpenIDSession{
|
||||
ChallengeID: challenge,
|
||||
}
|
||||
sessionData, _ := json.Marshal(session)
|
||||
|
||||
gomock.InOrder(
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(fmt.Errorf("duplicate key")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}).
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
SaveOAuth2PARContext(s.ctx, model.OAuth2PARContext{Signature: "abc", RequestID: "abc", ClientID: "example", Session: sessionData}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
s.NoError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}))
|
||||
|
||||
s.EqualError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}), "duplicate key")
|
||||
|
||||
s.EqualError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: nil,
|
||||
}), "can't convert type '<nil>' to an *OAuth2Session")
|
||||
|
||||
s.NoError(s.store.CreateAccessTokenSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}))
|
||||
|
||||
s.NoError(s.store.CreateRefreshTokenSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}))
|
||||
|
||||
s.NoError(s.store.CreateOpenIDConnectSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}))
|
||||
|
||||
s.NoError(s.store.CreatePKCERequestSession(s.ctx, "abc", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}))
|
||||
|
||||
s.NoError(s.store.CreatePARSession(s.ctx, "abc", &fosite.AuthorizeRequest{
|
||||
Request: fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
}}))
|
||||
|
||||
s.EqualError(s.store.CreatePARSession(s.ctx, "abc", &fosite.AuthorizeRequest{
|
||||
Request: fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: nil,
|
||||
}}), "can't convert type '<nil>' to an *OAuth2Session")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestRevokeSessions() {
|
||||
gomock.InOrder(
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "abc1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "abc2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at_example1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at_example2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202").
|
||||
Return(sql.ErrNoRows),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt_example1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt_example2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202").
|
||||
Return(sql.ErrNoRows),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202").
|
||||
Return(sql.ErrNoRows),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ac_1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ac_2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2PARContext(s.ctx, "urn:par1").
|
||||
Return(nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
RevokeOAuth2PARContext(s.ctx, "urn:par2").
|
||||
Return(fmt.Errorf("not found")),
|
||||
)
|
||||
|
||||
s.NoError(s.store.InvalidateAuthorizeCodeSession(s.ctx, "abc1"))
|
||||
s.EqualError(s.store.InvalidateAuthorizeCodeSession(s.ctx, "abc2"), "not found")
|
||||
|
||||
s.NoError(s.store.DeleteAccessTokenSession(s.ctx, "at_example1"))
|
||||
s.EqualError(s.store.DeleteAccessTokenSession(s.ctx, "at_example2"), "not found")
|
||||
|
||||
s.NoError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200"))
|
||||
s.EqualError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201"), "not found")
|
||||
s.EqualError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "not_found")
|
||||
|
||||
s.NoError(s.store.DeleteRefreshTokenSession(s.ctx, "rt_example1"))
|
||||
s.EqualError(s.store.DeleteRefreshTokenSession(s.ctx, "rt_example2"), "not found")
|
||||
|
||||
s.NoError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200"))
|
||||
s.EqualError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201"), "not found")
|
||||
s.EqualError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "sql: no rows in result set")
|
||||
|
||||
s.NoError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200", "1"))
|
||||
s.EqualError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201", "2"), "not found")
|
||||
s.EqualError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202", "3"), "sql: no rows in result set")
|
||||
|
||||
s.NoError(s.store.DeletePKCERequestSession(s.ctx, "pkce1"))
|
||||
s.EqualError(s.store.DeletePKCERequestSession(s.ctx, "pkce2"), "not found")
|
||||
|
||||
s.NoError(s.store.DeleteOpenIDConnectSession(s.ctx, "ac_1"))
|
||||
s.EqualError(s.store.DeleteOpenIDConnectSession(s.ctx, "ac_2"), "not found")
|
||||
|
||||
s.NoError(s.store.DeletePARSession(s.ctx, "urn:par1"))
|
||||
s.EqualError(s.store.DeletePARSession(s.ctx, "urn:par2"), "not found")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestGetSessions() {
|
||||
challenge := uuid.Must(uuid.NewRandom())
|
||||
session := &model.OpenIDSession{
|
||||
ChallengeID: challenge,
|
||||
ClientID: "hs256",
|
||||
}
|
||||
sessionData, _ := json.Marshal(session)
|
||||
|
||||
sessionb := &model.OpenIDSession{
|
||||
ChallengeID: challenge,
|
||||
ClientID: "hs256",
|
||||
}
|
||||
sessionDatab, _ := json.Marshal(sessionb)
|
||||
|
||||
gomock.InOrder(
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_123").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_456").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: false}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_aaa").
|
||||
Return(nil, sql.ErrNoRows),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_130").
|
||||
Return(nil, fmt.Errorf("timeout")),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_badclient").
|
||||
Return(&model.OAuth2Session{ClientID: "no-client", Session: sessionDatab, Active: true}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil),
|
||||
s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ot").
|
||||
Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2PARContext(s.ctx, "urn:par").
|
||||
Return(&model.OAuth2PARContext{Signature: "abc", RequestID: "abc", ClientID: "hs256", Session: sessionData}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2PARContext(s.ctx, "urn:par").
|
||||
Return(nil, sql.ErrNoRows),
|
||||
)
|
||||
|
||||
var (
|
||||
r fosite.Requester
|
||||
err error
|
||||
)
|
||||
|
||||
r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_123", &model.OpenIDSession{})
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_456", &model.OpenIDSession{})
|
||||
s.NotNil(r)
|
||||
s.EqualError(err, "Authorization code has ben invalidated")
|
||||
|
||||
r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_aaa", &model.OpenIDSession{})
|
||||
s.Nil(r)
|
||||
s.EqualError(err, "not_found")
|
||||
|
||||
r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_130", &model.OpenIDSession{})
|
||||
s.Nil(r)
|
||||
s.EqualError(err, "timeout")
|
||||
|
||||
r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_badclient", &model.OpenIDSession{})
|
||||
s.Nil(r)
|
||||
s.EqualError(err, "invalid_client")
|
||||
|
||||
r, err = s.store.GetAccessTokenSession(s.ctx, "at", &model.OpenIDSession{})
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetRefreshTokenSession(s.ctx, "rt", &model.OpenIDSession{})
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetPKCERequestSession(s.ctx, "pkce", &model.OpenIDSession{})
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetOpenIDConnectSession(s.ctx, "ot", &fosite.Request{
|
||||
ID: "abc",
|
||||
Client: &oidc.BaseClient{
|
||||
ID: "example",
|
||||
},
|
||||
Session: session,
|
||||
})
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetPARSession(s.ctx, "urn:par")
|
||||
s.NotNil(r)
|
||||
s.NoError(err)
|
||||
|
||||
r, err = s.store.GetPARSession(s.ctx, "urn:par")
|
||||
s.Nil(r)
|
||||
s.EqualError(err, "sql: no rows in result set")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestIsJWTUsed() {
|
||||
gomock.InOrder(
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63").
|
||||
Return(&model.OAuth2BlacklistedJTI{
|
||||
ID: 1,
|
||||
Signature: "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63",
|
||||
ExpiresAt: time.Now().Add(time.Hour),
|
||||
}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068").
|
||||
Return(&model.OAuth2BlacklistedJTI{
|
||||
ID: 1,
|
||||
Signature: "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068",
|
||||
ExpiresAt: time.Now().Add(-time.Hour),
|
||||
}, nil),
|
||||
s.mock.
|
||||
EXPECT().
|
||||
LoadOAuth2BlacklistedJTI(s.ctx, "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6").
|
||||
Return(nil, fmt.Errorf("failed to load")),
|
||||
)
|
||||
|
||||
used, err := s.store.IsJWTUsed(s.ctx, "066ee771-e156-4886-b99f-ee09b0d3edf4")
|
||||
s.True(used)
|
||||
s.EqualError(err, "jti_known")
|
||||
|
||||
used, err = s.store.IsJWTUsed(s.ctx, "5dad3ff7-e4f2-41b6-98a3-b73d872076ce")
|
||||
s.False(used)
|
||||
s.NoError(err)
|
||||
|
||||
used, err = s.store.IsJWTUsed(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202")
|
||||
s.True(used)
|
||||
s.EqualError(err, "failed to load")
|
||||
}
|
||||
|
||||
func (s *StoreSuite) TestMarkJWTUsedForTime() {
|
||||
gomock.InOrder(
|
||||
s.mock.EXPECT().
|
||||
SaveOAuth2BlacklistedJTI(s.ctx, model.OAuth2BlacklistedJTI{Signature: "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6", ExpiresAt: time.Unix(160000000, 0)}).
|
||||
Return(nil),
|
||||
s.mock.EXPECT().SaveOAuth2BlacklistedJTI(s.ctx, model.OAuth2BlacklistedJTI{Signature: "0dab0de97ed4e05da82763497448daf4f6b555c99218100e3ef5a81f36232940", ExpiresAt: time.Unix(160000000, 0)}).
|
||||
Return(fmt.Errorf("already marked")),
|
||||
)
|
||||
|
||||
s.NoError(s.store.MarkJWTUsedForTime(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202", time.Unix(160000000, 0)))
|
||||
s.EqualError(s.store.MarkJWTUsedForTime(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201", time.Unix(160000000, 0)), "already marked")
|
||||
}
|
||||
|
|
|
@ -515,7 +515,10 @@ type OAuth2MutualTLSClientAuthenticationDiscoveryOptions struct {
|
|||
within mtls_endpoint_aliases that do not define endpoints to which an OAuth client makes a direct request have
|
||||
no meaning and SHOULD be ignored.
|
||||
*/
|
||||
MutualTLSEndpointAliases struct {
|
||||
MutualTLSEndpointAliases OAuth2MutualTLSClientAuthenticationAliasesDiscoveryOptions `json:"mtls_endpoint_aliases"`
|
||||
}
|
||||
|
||||
type OAuth2MutualTLSClientAuthenticationAliasesDiscoveryOptions struct {
|
||||
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
|
||||
TokenEndpoint string `json:"token_endpoint,omitempty"`
|
||||
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
|
||||
|
@ -526,7 +529,6 @@ type OAuth2MutualTLSClientAuthenticationDiscoveryOptions struct {
|
|||
FederationRegistrationEndpoint string `json:"federation_registration_endpoint,omitempty"`
|
||||
PushedAuthorizationRequestEndpoint string `json:"pushed_authorization_request_endpoint,omitempty"`
|
||||
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
|
||||
} `json:"mtls_endpoint_aliases"`
|
||||
}
|
||||
|
||||
type OAuth2JWTSecuredAuthorizationRequestDiscoveryOptions struct {
|
||||
|
@ -954,15 +956,3 @@ type OpenIDConnectContext interface {
|
|||
|
||||
IssuerURL() (issuerURL *url.URL, err error)
|
||||
}
|
||||
|
||||
// MockOpenIDConnectContext is a minimal implementation of OpenIDConnectContext for the purpose of testing.
|
||||
type MockOpenIDConnectContext struct {
|
||||
context.Context
|
||||
|
||||
MockIssuerURL *url.URL
|
||||
}
|
||||
|
||||
// IssuerURL returns the MockIssuerURL.
|
||||
func (m *MockOpenIDConnectContext) IssuerURL() (issuerURL *url.URL, err error) {
|
||||
return m.MockIssuerURL, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package oidc
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -11,10 +12,11 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/model"
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
func TestNewSession(t *testing.T) {
|
||||
session := NewSession()
|
||||
session := oidc.NewSession()
|
||||
|
||||
require.NotNil(t, session)
|
||||
|
||||
|
@ -34,24 +36,24 @@ func TestNewSessionWithAuthorizeRequest(t *testing.T) {
|
|||
|
||||
formValues := url.Values{}
|
||||
|
||||
formValues.Set(ClaimNonce, "abc123xyzauthelia")
|
||||
formValues.Set(oidc.ClaimNonce, "abc123xyzauthelia")
|
||||
|
||||
request := &fosite.AuthorizeRequest{
|
||||
Request: fosite.Request{
|
||||
ID: requestID.String(),
|
||||
Form: formValues,
|
||||
Client: &BaseClient{ID: "example"},
|
||||
Client: &oidc.BaseClient{ID: "example"},
|
||||
},
|
||||
}
|
||||
|
||||
extra := map[string]any{
|
||||
ClaimPreferredUsername: "john",
|
||||
oidc.ClaimPreferredUsername: "john",
|
||||
}
|
||||
|
||||
requested := time.Unix(1647332518, 0)
|
||||
authAt := time.Unix(1647332500, 0)
|
||||
issuer := examplecom
|
||||
amr := []string{AMRPasswordBasedAuthentication}
|
||||
amr := []string{oidc.AMRPasswordBasedAuthentication}
|
||||
|
||||
consent := &model.OAuth2ConsentSession{
|
||||
ChallengeID: uuid.New(),
|
||||
|
@ -59,7 +61,7 @@ func TestNewSessionWithAuthorizeRequest(t *testing.T) {
|
|||
Subject: uuid.NullUUID{UUID: subject, Valid: true},
|
||||
}
|
||||
|
||||
session := NewSessionWithAuthorizeRequest(MustParseRequestURI(issuer), "primary", "john", amr, extra, authAt, consent, request)
|
||||
session := oidc.NewSessionWithAuthorizeRequest(MustParseRequestURI(issuer), "primary", "john", amr, extra, authAt, consent, request)
|
||||
|
||||
require.NotNil(t, session)
|
||||
require.NotNil(t, session.Extra)
|
||||
|
@ -80,19 +82,36 @@ func TestNewSessionWithAuthorizeRequest(t *testing.T) {
|
|||
assert.Equal(t, authAt, session.Claims.AuthTime)
|
||||
assert.Equal(t, requested, session.Claims.RequestedAt)
|
||||
assert.Equal(t, issuer, session.Claims.Issuer)
|
||||
assert.Equal(t, "john", session.Claims.Extra[ClaimPreferredUsername])
|
||||
assert.Equal(t, "john", session.Claims.Extra[oidc.ClaimPreferredUsername])
|
||||
|
||||
assert.Equal(t, "primary", session.Headers.Get(JWTHeaderKeyIdentifier))
|
||||
assert.Equal(t, "primary", session.Headers.Get(oidc.JWTHeaderKeyIdentifier))
|
||||
|
||||
consent = &model.OAuth2ConsentSession{
|
||||
ChallengeID: uuid.New(),
|
||||
RequestedAt: requested,
|
||||
}
|
||||
|
||||
session = NewSessionWithAuthorizeRequest(MustParseRequestURI(issuer), "primary", "john", nil, nil, authAt, consent, request)
|
||||
session = oidc.NewSessionWithAuthorizeRequest(MustParseRequestURI(issuer), "primary", "john", nil, nil, authAt, consent, request)
|
||||
|
||||
require.NotNil(t, session)
|
||||
require.NotNil(t, session.Claims)
|
||||
assert.NotNil(t, session.Claims.Extra)
|
||||
assert.Nil(t, session.Claims.AuthenticationMethodsReferences)
|
||||
}
|
||||
|
||||
// MockOpenIDConnectContext is a minimal implementation of OpenIDConnectContext for the purpose of testing.
|
||||
type MockOpenIDConnectContext struct {
|
||||
context.Context
|
||||
|
||||
MockIssuerURL *url.URL
|
||||
IssuerURLFunc func() (issuerURL *url.URL, err error)
|
||||
}
|
||||
|
||||
// IssuerURL returns the MockIssuerURL.
|
||||
func (m *MockOpenIDConnectContext) IssuerURL() (issuerURL *url.URL, err error) {
|
||||
if m.IssuerURLFunc != nil {
|
||||
return m.IssuerURLFunc()
|
||||
}
|
||||
|
||||
return m.MockIssuerURL, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBytesJoin(t *testing.T) {
|
||||
a := []byte("a")
|
||||
b := []byte("b")
|
||||
|
||||
assert.Equal(t, "ab", string(BytesJoin(a, b)))
|
||||
assert.Equal(t, "a", string(BytesJoin(a)))
|
||||
assert.Equal(t, "", string(BytesJoin()))
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTestingClock(t *testing.T) {
|
||||
c := &TestingClock{
|
||||
now: time.Unix(0, 0),
|
||||
}
|
||||
|
||||
assert.Equal(t, int64(0), c.Now().Unix())
|
||||
c.now = time.Unix(20, 0)
|
||||
|
||||
assert.Equal(t, int64(20), c.Now().Unix())
|
||||
assert.Equal(t, int64(20000000000), c.Now().UnixNano())
|
||||
|
||||
c.Set(time.Unix(16000000, 0))
|
||||
|
||||
assert.Equal(t, int64(16000000), c.Now().Unix())
|
||||
|
||||
before := c.Now()
|
||||
|
||||
<-c.After(time.Millisecond * 100)
|
||||
|
||||
assert.Equal(t, before, c.Now())
|
||||
}
|
||||
|
||||
func TestRealClock(t *testing.T) {
|
||||
c := &RealClock{}
|
||||
|
||||
assert.WithinDuration(t, time.Now(), c.Now(), time.Second)
|
||||
|
||||
before := c.Now()
|
||||
|
||||
<-c.After(time.Millisecond * 100)
|
||||
|
||||
after := c.Now()
|
||||
|
||||
assert.WithinDuration(t, before, after, time.Millisecond*120)
|
||||
|
||||
diff := after.Sub(before)
|
||||
|
||||
assert.GreaterOrEqual(t, diff, time.Millisecond*100)
|
||||
}
|
Loading…
Reference in New Issue