Working with Azure Episode 1: Secure your Spring boot application with Oauth2 + Azure Active Directory (Part 1: Authentication)
Introduction
สวัสดีครับบทความนี้จะเป็นตอนแรกของซีรีย์ Working with Azure ซึ่งเราจะเจาะลึก tools และ approach ต่างๆที่ใช้ในการ Develop web application จากบทความ Tech stack ของ ExxonMobil ที่พี่ Tanat Lokejaroenlarb และผมเขียนขึ้นมา Tech Stack ของ ExxonMobil และใน EP แรกนี้เราจะมาดูกันว่าการทำให้ Web service ของเราปลอดภัยนั้นต้องเริ่มจากอะไรกัน?
Authentication and Authorization
เกริ่นคร่าวๆนั้นการสร้าง Web Service ต้องมีการตรวจสอบและจำกัดสิทธิในการเข้าถึง Endpoint แต่ละอันซึ่งอาจจะมีกลุ่มผู้ใช้ที่แตกต่างกันซึ่งแบ่งได้เป็นสองส่วนคือ Authentication และ Authorization
Authentication: การตรวจสอบ identity ของ client ว่าคนๆใช่คนที่เรารู้จักหรือไม่
Authorization: การตรวจสอบ access ของ client ว่าคนๆนี้มีสิทธิที่จะเข้าถึงข้อมูลของ endpoint นั้นๆหรือไม่
ในที่นี้เราจะเลือกใช้ Oauth2 ในการทำ Authentication and Authorization เนื่องจากเป็น Protocol ที่เป็น stardard และใช้กันแพร่หลายในการ Secure Application
Oauth2
การที่ Client จะสามารถ Authenticate เข้า service เราผ่าน Oauth2 นั้น ต้องมีสิ่งที่เรียกว่า Bearer Token แนบมากับ Authorization header ซึ่งเป็น Jwt มีข้อมูลของ Client อยู่ซึ่งมีด้วยกันหลาย Flow อาทิ เช่น Client Credentials, Authorization Code, Implicit, etc. ข้อมูลเพิ่มเติมที่: https://oauth.net/2/grant-types/
ซึ่งในวันนี้ผมขอเลือกใช้ Client Credentials Grant เพื่อสาธิตในส่วนของ resource server ว่าเราจะทำอย่างไรเพื่อดักจับ และ validate Oauth2 token ที่ได้รับมาจาก Client
รูปด้านล่างคือการทำงานของ Client Credentials Flow แบบคร่าวๆ
Create AzureAD application
ขั้นแรกเราจะทำการสร้าง application บน AzureAD ขึ้นมา 2 ตัว
ตัวที่หนึ่งจะเป็นตัวแทน Resource Server
ตัวที่สองจะเป็นตัวแทนของ Client Application
วิธีสร้าง Application บน Azure AD: https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal
Gradle Dependencies
Dependencies ที่ต้องใช้มีแค่ 2 ตัว
ตัวแรกใช้ในการสร้าง Web Service ของ Spring Boot
spring-boot-starter-web
ตัวที่สองเอาไว้ใช้สำหรับ Oauth2 configuration ของ Spring Boot
spring-starter-oauth2-resource-server
Hello AzureAD Endpoint
สร้าง Endpoint ง่ายๆขึ้นมาตัวหนึ่งซึ่ง return response เป็น String
Oauth2 Configuration
ระบุ issuer-uri และ jwt-set-uri ซึ่งก็คือ endpoint ของ Azure AD ที่ใช้ในการ validate Jwt Token signature และ issuer
YOUR_TENANT_ID: Tenant Id ของ AzureAD application ที่เราสร้างขึ้นมาเรียบร้อยแล้ว
สร้าง configuration class ของ Oauth2
- http.authorizeRequest: เลือก endpoint ที่ต้องการ secure อย่างเช่นในที่นี้ a.antMatchers(“/azuread”) จะทำการ match endpoint /azuread และตามด้วย .fullyAuthenticated() เพื่อบอกว่าเราต้องการที่จะให้มีการ authenticate ที่ endpoint ที่matchกับpattern
- .exceptionHandling: เพื่อสร้างตัว handler เวลาที่ authenticate ไม่ผ่านจะ return Https Status 401 กลับไป
- .oauth2ResoureceServer().jwt: เพื่อบอกว่าเราจะใช้ oauth2 protocol ในการทำ authentication ตัว Spring จะทำการ validate Jwt ตาม configuration ที่เราใส่ไว้ใน application.yaml
Your endpoint is secured
ทีนี้ลองใช้ Postman ยิงไปที่ localhost:8080/azuread จะเห็นได้ว่า Response Status ที่ได้กลับมาจะเป็น 401 Unauthorized เนื่องจากเรายังไม่ได้ทำการแนบ Bearer Token ไปกับ header
คราวนี้เราจะทำการแนบ Token ไปกับ header ด้วย
ขั้นแรกเราต้องไปขอ Access Token มาก่อนโดนการยิง request ไปที่ endpoint ดังนี้
CLIENT_APPLICATION_ID: Client Id ของ AzureAD application ที่เป็นตัวแทนของ Client
CLIENT_APPLICATION_SECRET: Secret ของ AzureAD application ที่เป็นตัวแทนของ Client
RESOURCE_APPLICATION_ID: Client Id ของ AzureAD application ที่เป็นตัวแทนของ Resource Server
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencodedclient_id={CLIENT_APPLICATION_ID}
&scope={RESOURCE_APPLICATION_ID}/.default
&client_secret={CLIENT_APPLICATION_SECRET}
&grant_type=client_credentials
ตัวอย่างการยิง request เพื่อ get access token
ขั้นตอนสุดท้ายกลับไปยิง Request หา localhost:8080/azuread ใหม่แต่คราวนี้แนบ Bearer Token ไปกับ Authorization Header ด้วยจะเห็นได้ว่าคราวนี้ Response Status กลับมาเป็น 200 OK พร้อม Response Body
What does this mean?
การที่เราแนบ Bear Token ไปกับ request เพื่อให้ทางฝั่ง Web Service นั้นตรวจสอบว่าเราคือคนที่มันรู้จักมั้ยหรือก็คือเป็น part ของการยืนยันตัวตน (Authentication) นั่นเอง
Source Code
Link: https://github.com/NonTechCompany/spring-oauth2-azuread
Contact
Email: chan.suttichujit@gmail.com
GitHub: https://github.com/NonTechCompany
Credit
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow