CAS
, JWT
在研究CAS的時候撞得滿頭包,老樣子會記錄一些遇到的問題,也會稍微介紹一下CAS protocol整體流程以及和jwt流程的差異性。
對於Single Sign On為何,相信網路上已有諸多解釋,在此不多贅述。
但需要先有一個觀念是,User登入時會有兩種session,一種是SSO session,另一種則是在Client local site session。
因此即便從sso中登出,廢止了sso session,如果Server沒有通知底下全部的Client Service將這個User登出的話,就會發生已登入的Client Service,因為session沒有被廢除,所以依然還在登入狀態,但其他的Client Service卻會重新要求登入,導致狀態不一致。
Server使用套件(請加入在build.gradle):
Client使用套件(請加入在pom.xml):
Ticket Granting Tikcet(TGT): 用來證明使用者已經在CAS系統登入過,登入成功後系統會將TGT存在快取,並將id的值存入TGC,這樣之後只要比對id就能知道使用者是否登入。
Ticket Granting Cookie(TGC): 就是用來存TGT id的作用,登入後會將此物件返回給使用者,驗證時會攜帶TGC到Server確認是否登入。
Service Ticket(ST): 除了返回TGC以外,CAS還會為當前使用的服務(也就是當下的CAS Client)註冊,產生票據後連同TGC一起返回給使用者。
先附上CAS社群的使用指南: https://apereo.github.io/cas/6.0.x/protocol/CAS-Protocol.html#cas-protocol
從圖片中可以看到整個protocol的時序圖和整體流程,不過我自己畫了張流程圖,接著會以下圖來依序說明:
一樣先附上社群文章:
https://apereo.github.io/cas/6.6.x/installation/Configure-ServiceTicket-JWT.html
jwt的流程也是基於CAS protocol的流程下去做調整,為何會選擇將jwt替換掉ST呢? 其實這兩者的功用是完全一樣的差,差別只在於如果希望拿到ST後不用再回去跟Server驗證一次,而是在Client端的部分驗證jwt字串,字串裡面會包含有ST的資訊以及過期時間等等資訊,只要驗證過後就馬上發放請求資源,進而減少Client和Server溝通的次數。
因為流程很類似,只有最後不同,就不多加描述了~
接下來這段都是實作中遇到的一些bug shooting和設定問題還有雜談,或許遇到問題時這邊能找到一些答案~
從社群上可以看到使用了Overlay方式來deploy專案,因為他不希望你動到cas project的原始碼的關係,所以即便你抓了下來,也看不到任何的原始碼,會覺得怎麼專案就這麼空?? 他的概念是如果你有想要針對cas server做設定,或者想要覆蓋原先檔案的寫法的話,必須要在project path\cas\src\main\resources
這個路徑底下放上去你的設定檔案,例如針對cas server設定很重要的application.properties
。[4]
有一點必須說一下,假設今天當你從git抓下來後,build完之後,他會產出一個cas.jar,只需要把這個jar deploy到tomcat,啟動後就ok了~ 但是這樣對開發來說時常需要去調整設定檔什麼之類的,每改一次就要build一次再重新deploy真的太煩人!!!
所以建議直接將專案導入到eclipse或個人習慣用的ide,同時把cas.jar解壓後,將cas\WEB-INF\classes
這個資料夾設定成專案的source之一,這樣啟動後才會有cas project預設的一些html可以呈現。
##
# CAS Log4j Configuration
#
# logging.config=file:/etc/cas/log4j2.xml
server.servlet.context-parameters.isLog4jAutoInitializationDisabled=true
logging.level.org.apereo.cas=DEBUG
# CAS Server
cas.server.name=https://sso.server.com:8443
cas.server.prefix=https://sso.server.com:8443/cas
##
# CAS Web Application Embedded Server SSL Configuration
#
server.ssl.key-store=file:keystore的路徑\ssodemo.keystore
server.ssl.key-store-password=123456
#server.ssl.key-password=123456
##
# CAS Authentication Credentials
#
cas.authn.accept.users=test::123456
#cas.authn.accept.name=Static Credentials
# LDAP Authentication Connection Setting
# LDAP 的相關設定請參考cas 5.0版本的會比較齊全
#cas.authn.ldap[0].type=AD
# basedn = ldap物件的基底位址,代表輸入帳號密碼認證時會從這個路徑開始找
#cas.authn.ldap[0].baseDn=cn=xxx,dc=xxx
#cas.authn.ldap[0].subtreeSearch=true
#cas.authn.ldap[0].searchFilter=cn={user}
#cas.authn.ldap[0].enhanceWithEntryResolver=true
#cas.authn.ldap[0].dnFormat=cn=%s,cn=xxx,dc=xxx
#cas.authn.ldap[0].ldapUrl=ldap://ldap的ip
#cas.authn.ldap[0].useSsl=false
#cas.authn.ldap[0].useStartTls=false
#cas.authn.ldap[0].connectTimeout=5000
# binddn = 在AD裡任何一位使用者的DN位址(為了一開始執行使用者身分認證時要進入ldap取得資料,較新的版本會稱為principalName)
#cas.authn.ldap[0].bindDn=cn=xxx,dc=xxx
#cas.authn.ldap[0].bindCredential=上面那組帳號的密碼
#cas.authn.ldap[0].providerClass=org.ldaptive.provider.unboundid.UnboundIDProvider
#cas.authn.ldap[0].connectTimeout=PT10S
# LDAP Authentication principal設定,想回傳想要的屬性可在此設定
#cas.authn.ldap[0].principalAttributeId=sAMAccountName
#cas.authn.ldap[0].principalAttributeList=givenName,cn,mail
#cas.authn.ldap[0].collectDnAttribute=true
#cas.authn.ldap[0].allowMultiplePrincipalAttributeValues=true
#cas.authn.ldap[0].allowMissingPrincipalAttributeValue=true
# Service Registry
cas.serviceRegistry.watcherEnabled=true
cas.serviceRegistry.schedule.repeatInterval=120000
cas.serviceRegistry.schedule.startDelay=15000
# Auto-initialize the registry from default JSON service definitions
cas.serviceRegistry.initFromJson=true
這邊還要搭配json檔案的配置,請在project path\cas\src\main\resources
底下,建立一個資料夾services
,並且建立json檔案,檔名有規定格式,需命名為:name-id.json*。
像下方name: client1_server、id 1,所以檔名就是: client1_server-1.json。
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(https|imaps)://自己設定的client域名",
"name" : "client1_server",
"id" : 1,
"evaluationOrder" : 1
}
如果感覺一直吃不到設定檔的感覺,可以去把classes的資料夾,把他預設的application.properties檔案給砍了,只留下自己寫的即可。
如果不知道jwt的signing key和encrpytion key要設定成什麼,可以先在不設定的情況下啟動一次Server,正常順利的話看看console,系統會自動產出一組給你,請把它複製起來貼在json裡面。
# JWT Tickets
cas.authn.token.crypto.encryptionEnabled=true
cas.authn.token.crypto.signingEnabled=true
"properties" : {
"@class" : "java.util.HashMap",
"jwtAsServiceTicket" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceProperty",
"values" : [ "java.util.HashSet", [ "true" ] ]
},
"jwtAsServiceTicketSigningKey" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceProperty",
"values" : [ "java.util.HashSet", [ "7gInlM_CH3WTNIiatPWHr_...." ] ]
},
"jwtAsServiceTicketEncryptionKey" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceProperty",
"values" : [ "java.util.HashSet", [ "f5E4tGS9v6IXEcm57ix...." ] ]
}
}
# cas logout setting
cas.logout.followServiceRedirects=true
cas.slo.asynchronous=true
"logoutType": "BACK_CHANNEL",
"logoutUrl": "看你想將它導到client的哪個頁面的網址"
[1] JWT Service Ticket
[2] LDAP Authentication
[3] CAS Protocol
[4] CAS Overlay
[5] CAS Properties: JWT Ticket
[6] CAS Properties: LDAP Connection Pool v5.0
[7] CAS Properties: Service Registry
[8] CAS Properties: Single Logout
[9] Single Logout(SLO)
夜雨
由於一開始第一次接觸什麼叫Overlay的關係,一開始抓git抓CAS Server專案包下來的時候選了master版本,結果只看到抓下來一大堆各式各樣的xxx server,看得頭昏眼花又搞不太懂,很不像傳統一個網頁project的樣子…重點是build又要超久!! 後來選了6.0版後,才終於看起來有比較像平常看到的那種專案結構了…