มาลองใช้ Spring Authorization Server กันดู
จากที่ Spring team ได้ ประกาศว่าจะทำโครงการ Spring Authorization Server เมื่อประมาณเมษาปีนี้ (2020) โดยจะแยก OAuth2 Authorization Server ออกจาก Spring Security ทำให้ version ใหม่ๆ ไม่สมารถสร้าง OAuth2 Authorization Server ได้แล้ว และใครที่ใช้อยู่อาจจะต้องยังไม่อัพเดต Spring Security version ใหม่ และรอว่าเมื่อไหร่โครงการนี้จะเสร็จ และแล้วโครงการนี้ก็คลอดมาให้เราลองใช้แต่ยังอยู่ในขั้นทดลองอยู่ และมั่นใจว่าจะออกมา version ที่ใช้งานจริงได้ในไม่ช้านี้
ในบทความนี้จะมาลองใช้งาน Spring Authorization Server ก็ออมาให้ทดลองใช้กัน โดยจะสร้าง OAuth2 Authorization Server ด้วย Spring Authorization Server และ Resource Server ที่จะต้อง authorize ด้วย OAuth2 JWT โดยอ้างอิงจากตัวอย่างที่ Spring Security team สร้างไว้
เท้าความกันหน่อย มาปกป้อง Microservice ด้วย OAuth2 ใน Spring Boot
Create Authorization Server Project
เราใช้ Spring Intializr สร้าง project เลือกเฉพาะ Spring Web และ Spring Security เท่านั้นในตอนสร้าง project เพราะเราจะไปเพิ่ม Spring Authorization Server ทีหลัง ในบทความนี้จะใช้ Gradle project
ใช้ IDE อย่าง IntellJ เปิด project ที่สร้างมา และเพิ่ม Spring Authorization Server dependency ในส่วน dependencies ของ build.gradle
implementation 'org.springframework.security.experimental:spring-security-oauth2-authorization-server:0.0.3'
Add Authorization Server Config
สำหรับการสร้าง Authorization Server ด้วย Spring Authorization Server เราจะต้องสร้าง config ให้กับ Spring Security (annotation สำหรับน่าจะยังไม่เสร็จ) ซึ่งจะสร้าง config ด้วย WebSecurityConfigurerAdapter
เหมือน Spring Security ทั่วไป จะใช้ applyDefaultConfiguration
เพื่อตั้งค่าต่างๆ ให้กับ Spring Security อย่างเช่น endpoint ต่างๆ ที่จำเป็นสำหรับ Authorization Server ที่ใช้ protocol OAuth2
สร้าง registeredClientRepository
bean ที่มากับ Spring Authorization Server เพื่อใช้เป็นข้อมูลของ Client ที่จะอนุญาตให้ใช้งานระบบ จะเห็นได้ว่ามี fix ค่าของ Client ID เป็น messaging-client
และ Client Secret เป็น secret
ทำให้ตัวอย่างใช้งานได้แค่เพียง Client เดียวเท่านั้น และเก็บข้อมูลใว้ใน memory ของระบบเท่านั้น (ยังไม่ได้ลองว่าใช้ JDBC Repository ได้ไหม)
สร้าง keySource
bean เพื่อจัดการ key ของระบบใน version นี้มี implementation เดียวคือ StaticKeyGeneratingKeyManager
(จะถูกแทนที่ CryptoKey ในอนาคตก็น่าจะ secure มากขึ้น)
สุดท้ายเป็น UserDetailsService
เหมือนกับ Spring Security ทั่วไปเลย (ซึ่งก็ใช้ Spring Security ทั่วไปนั้นหล่ะ 555) สำหรับเก็บข้อมูล User ที่ใช้งานระบบและก็เก็บไว้ใน memory เช่นเดียวกัน
เพียงเท่านี้เราก็สร้าง Authorization Server ได้แล้ว (แบบ In Memory ก่อน 555)
อาจจะเปลี่ยน port ของ Authorization Server หน่อยเพื่อไม่ให้ชนกับ Client App หรือ Resource Server โดยเพิ่ม server.port
ในไฟล์ application.yaml
Run Authorization Server
หลังจากที่สร้าง Config แล้ว ก็ทดลอง run Authorization Server ขึ้นมาด้วยคำสั่ง gradle bootRun
หรือจะ run Application จาก IntelliJ ก็ได้ จะเห็นได้ว่า Spring Boot Application ทำงานบน port 9000
ใน log จะแสดง Filter ที่ใช้โดยมี endpoint ที่ใช้สำหรับ OAuth2 protocol ดังนี้
POST /oauth2/token
— เป็น Token endpoint
POST /oauth2/authorize
— เป็น Authorization endpoint
GET /oauth2/authorize
— เป็น Authorization endpoint เช่นกัน
POST /oauth2/revoke
— เป็น Token revoke endpoint
GET /oauth2/jwks
— เป็น JWT key endpoint
ซึ่ง Authorization endpoint จะใช้ HTTP method POST หรือ GET ก็ได้
Test Authorization Server
ลองใช้ Postman ทดลอง request token เพื่อเอา access token จาก Authorization Server กำหนดค่าของ Body grant_type
เป็น client_credentials
และ scope
เป็น message.read
ด้วย Basic Auth username เป็น client_id messaging-client
และ password เป็น client_secret secret
เหมือนกับที่เรากำหนดใน config ก็จะได้ assess token เป็น response กลับมา และเอาไปใช้ authentication กับ Resource Server ได้
ในบทความนี้ผมสร้าง Resource Server ไว้ แต่ขอไม่กล่าวถึงในรายละเอียด ด้วย dependency oauth2-resource-server
โดยกำหนด jwk-set-uri
เป็น JWT key endpoint ของ Authorization server
เมื่อลอง request ไปที่ endpoint /messages
ของ Resource Server โดยที่ไม่ได้กำหนด Authorization จะได้ response HTTP code 401
เนื่องจากเราไม่มีสิทธิ์ใช้งาน Resource Server และเมื่อเราใช้ token ที่ได้รับมากำหนด Authorization เป็นแบบ Bare Token ก็จะได้ response body เป็นข้อมูลของ endpoint นั้น
สรุป
จากที่ทดลองใช้ Spring Authorization Server มาสร้าง OAuth2 Authentication Server ที่อยู่ในช่วงกำลังพัฒนา จะเห็นได้ว่าตัวอย่างที่ Spring team ให้มานั้นมันยังใช้ไม่ได้เลยเสียทีเดียวทำให้ต้องมาแก้เพื่อให้รันผ่าน แต่ตัว Spring Authorization Server เองทำมาได้ดีเลยทีเดียวทำให้ง่ายต่อการนำมาประยุกต์ใช้สร้าง OAuth2 Authorization Server เอง และบาง endpoint ที่ ถ้าเราใช้ OAuth2 Authorization Server ตัวเก่า อาจจะจำเป็นต้องพัฒนาบาง endpoint เองแต่ Spring Authorization Server มีมาให้พร้อมใช้งาน OAuth2 potocol แม้ว่าจะยังไม่สมบูรณ์ ซึ่งตอนนี้ก็ได้แต่รอว่าตัว Release จะออกมาเมื่อไหร่จะได้นำมาใช้จริงๆ กันเสียที