åæ
- Open ID Connectã®Relying Partyå´(以éRP)ã®ããã¼ããã£ã¦ã¿ãææã¯Authå±ããã®æ¬ãªã©ãããããRPå´ã®æåããã£ã¦ã¿ãã ãã§ã¯ã¾ã ã¾ã OIDCã®ç解ãæ·±ã¾ã£ã¦ããªãã¨æããã
- ããã§å¹´æ«å¹´å§ã¨ãããã¨ããããDjangoã§OIDCã®IdPå´ãããã°ãæ¸ããªããå®è£ ãã¦ã¿ããã¨ã«ãã
â» Djangoã使ãã®ã¯ä»¥ä¸ã®çç±ããã§ãæ·±ãæå³ã¯ãªã
- ä¸çªé¦´æã¿ããã
- IdPå´ã®å®è£ ã§ã¯DBãå¿ è¦ã ãã Djangoã¯SQLiteãå èµããã¦ããã®ã§æ¥½
Configurationã¨ã³ããã¤ã³ã
ã¾ãã¯ãã£ã¹ã«ããªã¨ããIdPã®ã¨ã³ããã¤ã³ãä¸è¦§ãå®ç¾©ããURLãå®è£ ããã
https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
.well-known/openid-configuration
ã¨ãããã¹ããã使ãããå°è±¡ãªã®ã§ãæ¬å®è£
ã§ããã®ããã«ããã
Viewãå®è£ ãã
ã¾ã IdPã®ã¨ã³ããã¤ã³ããä½ãå®è£ ãã¦ããªãã®ã§ã空ã®JSONãè¿ãViewãå®è£ ããã
views.py
from django.http import JsonResponse from django.views import View class DiscoveryView(View): def get(self, request): return JsonResponse({})
url.pyã«/.well-known/openid-configuration
ãå®ç¾©ãã
urls.py
from django.urls import path from . import views app_name = "sampleapp" urlpatterns = [ path("`.well-known/openid-configuration/`", views.DiscoveryView.as_view(), name="discovery"), ]
ããã§.well-known/openid-configuration
ã«ã¢ã¯ã»ã¹ããã¨ç©ºã®JSONãè¿ã£ã¦ããããã«ãªã£ãã
$ curl -X GET "http://localhost:8000/sample/.well-known/openid-configuration/" {}
èªå¯ã¨ã³ããã¤ã³ã
èªå¯ã¨ã³ããã¤ã³ããå®è£ ãã¦ãã
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
ã¨ã³ããã¤ã³ãã®è¿½å
ã¾ãã¯å ã»ã©ã®ãã£ã¹ã«ããªã«èªå¯ã¨ã³ããã¤ã³ãã®URLãå®ç¾©ããã
views.py
class DiscoveryView(View): def get(self, request): return JsonResponse({ "authorization_endpoint": "http://localhost:8000/sample/authorize/", })
ããã§ãã£ã¹ã«ããªããã¨ã³ããã¤ã³ãã調ã¹ãããããã«ãªãã
$ curl -X GET "http://localhost:8000/sample/.well-known/openid-configuration/" {"authorization_endpoint": "http://localhost:8000/sample/authorize/"}
Formã®å®è£
Formã«ãªã¯ã¨ã¹ããã©ã¡ã¼ã¿ãå®ç¾©ãã¦ãããã¨ãããã以ä¸ãå®ç¾©ãããPKCE
ãå®è£
ããå ´åã¯code_challenge
ã¨code_challenge_method
ãå¿
è¦ã ããæåã¯ããã¾ã§ã¯ãããªãã
ãã©ã¡ã¼ã¿å | 説æ |
---|---|
response_type | ããã¼ã®ç¨®é¡ãå®ç¾©ãããä»åã¯èªå¯ã³ã¼ãããã¼ãªã®ã§åºå®ã§code ã¨ããæååã渡ã |
scope | è¦æ±ããã¦ã¼ã¶ã¼æ
å ±ãåè§ã¹ãã¼ã¹ã§åºåã£ã¦æ¸¡ãã(ä¾ email profile ) |
client_id | RPã«çºè¡ããã¯ã©ã¤ã¢ã³ãID |
state | ãªã¯ã¨ã¹ãæã¨ç¶æ ãã³ã¼ã«ããã¯æã«æ¸¡ãããã«ä½¿ãããããCSRF対çã«ã使ãããâ» ã»ãã¥ãªãã£å¯¾çã®æèã§è§£èª¬ããããã¨ã®æ¹ãå¤ãå°è±¡ |
redirect_uri | ã³ã¼ã«ããã¯æã®RPã¸ã®æ»ãå URL |
nonce | ã»ãã¥ãªãã£å¯¾çç¨ã®ãã©ã¡ã¼ã¿ããããã©ã³ãã æååã§ããã詳ããã¯å¿ è¦ã«ãªã£ããç解ããã |
ã¨ãããããããã®ãã©ã¡ã¼ã¿ãFormã«å®ç¾©ãã
forms.py
class AuthorizeForm(forms.Form): response_type = forms.CharField() scope = forms.CharField() client_id = forms.CharField() state = forms.CharField() redirect_uri = forms.CharField() nonce = forms.CharField()
response_type
ã¯code
åºå®ãªã®ã§ããªãã¼ã·ã§ã³ãã
def clean_response_type(self): response_type = self.cleaned_data["response_type"] if response_type != "code": raise forms.ValidationError("Invalid response_type") return response_type
scope
ã¯åè§ã¹ãã¼ã¹åºåãã®æååã®ä»æ§ã ããããã°ã©ã ã®ä¸ã§ã¯ãªã¹ãã§æ±ãããã®ã§å¤æããã
def clean_scope(self): return self.cleaned_data["scope"].split()
OIDCã®ä»æ§ã§openid
ã¨ããæååã¯å¿
ãå«ãå¿
è¦ãããã®ã§ããªãã¼ã·ã§ã³ãã
def clean_scope(self): scope = self.cleaned_data["scope"].split() if "openid" not in scope: raise forms.ValidationError("Invalid scope") return scope
Viewã®å®è£
ãã£ãããã©ã¡ã¼ã¿ãåãåã£ã¦printãããã°ã§ãã©ã¡ã¼ã¿ãåºåããã¾ã§ã¨ããã
views.py
class AuthorizeView(View): def get(self, request): form = AuthorizeForm(request.GET) if not form.is_valid(): return HttpResponseBadRequest() print("authorize params: ", form.cleaned_data) return HttpResponse("todo")
url.pyã«/authorize/
ãå®ç¾©ãã
urls.py
path("authorize/", views.AuthorizeView.as_view(), name="authorize"),
åä½ç¢ºèª
以ä¸ã®curlãå®è¡ãã¦ã¿ããscope
ã®åè§ã¹ãã¼ã¹ã¯%20
ã«ç½®æããªãã¨curl: (3) URL rejected: Malformed input to a URL function
ãçºçããã®ã§æ³¨æããã
curl -X GET "http://localhost:8000/sample/authorize/?response_type=code&scope=openid%20email&client_id=test&state=abcd&redirect_uri=http://localhost/callback&nonce=efgh"
以ä¸ã®printãããã°çµæãåºåã§ããã
authorize params: {'response_type': 'code', 'scope': ['openid', 'email'], 'client_id': 'test', 'state': 'abcd', 'redirect_uri': 'http://localhost/callback', 'nonce': 'efgh'}`
ä»æ¥ã¯ããã¾ã§ã¨ããã
åèã«ãã¦ãããã®
Authå±ããã®æ¬
åã¨ã³ããã¤ã³ãã®ä»æ§ã¯Authå±ããã®æ¬ã authya.booth.pm
M3ããã®ããã¯ããã°ã®ããã«ã¹ã¯ã©ãããã¦ç解ããOpenID Connect ãã·ãªã¼ãº
å®è£ ããä¸ã§åèã«ããã¦é ãã¦ãã¾ãã