mirror of https://github.com/jumpserver/jumpserver
Merge pull request #9201 from jumpserver/pr@v3@perf_support_openid_pkce
perf: OpenID支持PKCE方式对接pull/9205/head
commit
b6d6c54d8f
|
@ -88,7 +88,7 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
|
|||
"""
|
||||
|
||||
@ssl_verification
|
||||
def authenticate(self, request, nonce=None, **kwargs):
|
||||
def authenticate(self, request, nonce=None, code_verifier=None, **kwargs):
|
||||
""" Authenticates users in case of the OpenID Connect Authorization code flow. """
|
||||
log_prompt = "Process authenticate [OIDCAuthCodeBackend]: {}"
|
||||
logger.debug(log_prompt.format('start'))
|
||||
|
@ -134,6 +134,8 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
|
|||
request, path=reverse(settings.AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME)
|
||||
)
|
||||
}
|
||||
if settings.AUTH_OPENID_PKCE and code_verifier:
|
||||
token_payload['code_verifier'] = code_verifier
|
||||
if settings.AUTH_OPENID_CLIENT_AUTH_METHOD == 'client_secret_post':
|
||||
token_payload.update({
|
||||
'client_id': settings.AUTH_OPENID_CLIENT_ID,
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
|
||||
"""
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import time
|
||||
import secrets
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
|
@ -38,6 +41,19 @@ class OIDCAuthRequestView(View):
|
|||
|
||||
http_method_names = ['get', ]
|
||||
|
||||
@staticmethod
|
||||
def gen_code_verifier(length=128):
|
||||
# length range 43 ~ 128
|
||||
return secrets.token_urlsafe(length - 32)
|
||||
|
||||
@staticmethod
|
||||
def gen_code_challenge(code_verifier, code_challenge_method):
|
||||
if code_challenge_method == 'plain':
|
||||
return code_verifier
|
||||
h = hashlib.sha256(code_verifier.encode('ascii')).digest()
|
||||
b = base64.urlsafe_b64encode(h)
|
||||
return b.decode('ascii')[:-1]
|
||||
|
||||
def get(self, request):
|
||||
""" Processes GET requests. """
|
||||
|
||||
|
@ -56,6 +72,16 @@ class OIDCAuthRequestView(View):
|
|||
)
|
||||
})
|
||||
|
||||
if settings.AUTH_OPENID_PKCE:
|
||||
code_verifier = self.gen_code_verifier()
|
||||
code_challenge_method = settings.AUTH_OPENID_CODE_CHALLENGE_METHOD or 'S256'
|
||||
code_challenge = self.gen_code_challenge(code_verifier, code_challenge_method)
|
||||
authentication_request_params.update({
|
||||
'code_challenge_method': code_challenge_method,
|
||||
'code_challenge': code_challenge
|
||||
})
|
||||
request.session['oidc_auth_code_verifier'] = code_verifier
|
||||
|
||||
# States should be used! They are recommended in order to maintain state between the
|
||||
# authentication request and the callback.
|
||||
if settings.AUTH_OPENID_USE_STATE:
|
||||
|
@ -138,8 +164,9 @@ class OIDCAuthCallbackView(View):
|
|||
|
||||
# Authenticates the end-user.
|
||||
next_url = request.session.get('oidc_auth_next_url', None)
|
||||
code_verifier = request.session.get('oidc_auth_code_verifier', None)
|
||||
logger.debug(log_prompt.format('Process authenticate'))
|
||||
user = auth.authenticate(nonce=nonce, request=request)
|
||||
user = auth.authenticate(nonce=nonce, request=request, code_verifier=code_verifier)
|
||||
if user and user.is_valid:
|
||||
logger.debug(log_prompt.format('Login: {}'.format(user)))
|
||||
auth.login(self.request, user)
|
||||
|
|
|
@ -270,6 +270,8 @@ class Config(dict):
|
|||
'AUTH_OPENID_USER_ATTR_MAP': {
|
||||
'name': 'name', 'username': 'preferred_username', 'email': 'email'
|
||||
},
|
||||
'AUTH_OPENID_PKCE': False,
|
||||
'AUTH_OPENID_CODE_CHALLENGE_METHOD': 'S256',
|
||||
|
||||
# OpenID 新配置参数 (version >= 1.5.9)
|
||||
'AUTH_OPENID_PROVIDER_ENDPOINT': 'https://oidc.example.com/',
|
||||
|
|
|
@ -77,6 +77,8 @@ AUTH_OPENID_USE_NONCE = CONFIG.AUTH_OPENID_USE_NONCE
|
|||
AUTH_OPENID_SHARE_SESSION = CONFIG.AUTH_OPENID_SHARE_SESSION
|
||||
AUTH_OPENID_IGNORE_SSL_VERIFICATION = CONFIG.AUTH_OPENID_IGNORE_SSL_VERIFICATION
|
||||
AUTH_OPENID_ALWAYS_UPDATE_USER = CONFIG.AUTH_OPENID_ALWAYS_UPDATE_USER
|
||||
AUTH_OPENID_PKCE = CONFIG.AUTH_OPENID_PKCE
|
||||
AUTH_OPENID_CODE_CHALLENGE_METHOD = CONFIG.AUTH_OPENID_CODE_CHALLENGE_METHOD
|
||||
AUTH_OPENID_USER_ATTR_MAP = CONFIG.AUTH_OPENID_USER_ATTR_MAP
|
||||
AUTH_OPENID_AUTH_LOGIN_URL_NAME = 'authentication:openid:login'
|
||||
AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME = 'authentication:openid:login-callback'
|
||||
|
|
|
@ -38,6 +38,11 @@ class CommonSettingSerializer(serializers.Serializer):
|
|||
help_text=_('User attr map present how to map OpenID user attr to '
|
||||
'jumpserver, username,name,email is jumpserver attr')
|
||||
)
|
||||
AUTH_OPENID_PKCE = serializers.BooleanField(required=False, label=_('Enable PKCE'))
|
||||
AUTH_OPENID_CODE_CHALLENGE_METHOD = serializers.ChoiceField(
|
||||
default='S256', label=_('Code challenge method'),
|
||||
choices=(('S256', 'HS256'), ('plain', 'Plain'))
|
||||
)
|
||||
|
||||
|
||||
class KeycloakSettingSerializer(CommonSettingSerializer):
|
||||
|
|
Loading…
Reference in New Issue