利用Python requests庫實現cas認證
1.準備工作-背景知識
1.1 requests庫簡介:
python有很多可以用來測試介面的模組,個人覺得,requests庫是最好用的, 在Robot Framwork裡,它的測試庫requestsLibrary,也是基於requests寫的。
1.1.1 安裝:
作為第三方模組,使用前,需要安裝,最簡單的安裝方式如下
pip install requests
1.1.2 語法(簡明版):
1)如何傳送請求 :
傳送get請求:requests.get(url, params, headers, cookies, verify, allow_redirects...)
傳送post請求: requests.post(url, params, data, headers, cookies, verify, allow_redirects...)
*****以上只有url引數是必填的,其他可以根據需要選填
*****除了get和post,還支援其他http請求,比如delete等等,不過在我們的cas認證中,只需要get和post;而且一般的介面測試中,最常用的也就是get和post訊息
2)如何得到響應:
假設傳送了一個請求:
r=requests.get(url, params, headers, cookies, verify, allow_redirects...)
那麼以下是返回結果:
r.headers 返回的頭資訊
r.text 返回的主體
r.status_code 返回的狀態碼
1.1.3 基於requests庫,編寫get和post請求
為了讓requests庫更能符合我們的需求,進行了簡單的封裝,重寫了get和post請求傳送:
設定了常用的headers引數
sesssion_id作為引數傳入
對於post訊息,會根據data值,設定Content-Length
#encoding=utf-8 import requests class RestfulTest(object): @staticmethod def send_get_request(url, params= None, session_id= None, verify = False , allow_redirects= False): #disable warnings requests.packages.urllib3.disable_warnings() if params == None: params = {} if session_id == None: cookies = {} else: cookies = {'JSESSIONID':session_id} headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Connection": "keep-alive", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0", } get_response = requests.get(url, params=params, headers=headers, cookies=cookies, verify=verify, allow_redirects=allow_redirects) return get_response @staticmethod def send_post_request(url, params= None, data= None, session_id= None, verify= False, allow_redirects=False): #disable warnings requests.packages.urllib3.disable_warnings() if params == None: params = {} if data == None: data = {} if session_id == None: cookies = {} else: cookies = {'JSESSIONID':session_id} headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Connection": "keep-alive", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Content-Length": str(len(data)) } post_response = requests.post(url, params=params, data=data, headers=headers, cookies=cookies, verify=verify, allow_redirects=allow_redirects) return post_response
1.2 cas 認證原理
CAS旨在為 Web 應用系統提供一種可靠的單點登入方法
Single Sign On,簡稱SSO,SSO使得在多個應用系統中,使用者只需要登入一次就可以訪問所有相互信任的應用系統
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。
CAS Server 需要獨立部署,主要負責對使用者的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登入時,重定向到 CAS Server
CAS Client 與受保護的客戶端應用部署在一起,以 Filter 方式保護受保護的資源。對於訪問受保護資源的每個 Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,如果沒有,則說明當前使用者尚未登入,於是將請求重定向到指定好的 CAS Server 登入地址,並傳遞 Service (也就是要訪問的目的資源地址),以便登入成功過後轉回該地址使用者在第 3 步中輸入認證資訊,如果登入成功,CAS Server 隨機產生一個相當長度、唯一、不可偽造的 Service Ticket,並快取以待將來驗證,之後系統自動重定向到 Service 所在地址,併為客戶端瀏覽器設定一個 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產生的 Ticket 過後,在第 5,6 步中與 CAS Server進行身份合適,以確保 Service Ticket 的合法性
在該協議中,所有與 CAS 的互動均採用 SSL 協議,確保ST 和 TGC 的安全性。協議工作過程中會有 2 次重定向的過程,但是 CAS Client 與 CAS Server 之間進行 Ticket 驗證的過程對於使用者是透明的。
總結一下,如下:訪問服務: SSO 客戶端傳送請求訪問應用系統提供的服務資源。
定向認證: SSO 客戶端會重定向使用者請求到 SSO 伺服器。
使用者認證:使用者身份認證。
發放票據: SSO 伺服器會產生一個隨機的 Service Ticket 。
驗證票據: SSO 伺服器驗證票據 Service Ticket 的合法性,驗證通過後,允許客戶端訪問服務。
傳輸使用者資訊: SSO 伺服器驗證票據通過後,傳輸使用者認證結果資訊給客戶端。
2. python程式碼實現cas認證
以下程式碼實現的是我們被測server的cas登入,不同產品,獲得cookie值方式可能有所不同,post的data值可能也有所不同,但是大致原理是一致的
#usr/bin/env python #encoding=utf-8 from restfulTest import RestfulTest from dataProcess import DataProcess class LoginToServer(object): @staticmethod def get_service_sessionId_redirectUrl(service_url): response = RestfulTest.send_get_request(service_url) cookieValue = response.headers['set-cookie'] redirectUrl = response.headers['location'] sessionId = DataProcess.get_first_matching_group_by_pattern(cookieValue, 'JSESSIONID=(\w+); Path') return sessionId, redirectUrl @staticmethod def cas_server_authentication(cas_server_url, userName="admin", userPasswd="admin"): response1 = RestfulTest.send_get_request(cas_server_url) cas_server_sessionId = DataProcess.get_first_matching_group_by_pattern(response1.headers['set-cookie'], 'JSESSIONID=(\w+); Path') submitLt = DataProcess.get_first_matching_group_by_pattern(response1.content, 'name="lt" value="(\w+)"') http_data_for_auth = "username="+userName+"&password="+userPasswd+"<="+submitLt+"&_eventId=submit&submit=Log+In" response2 = RestfulTest.send_post_request(cas_server_url, data = http_data_for_auth, session_id = cas_server_sessionId ) acceptLt= DataProcess.get_first_matching_group_by_pattern(response2.content, 'name="lt" value="(\w+)"') http_data_for_confirm ="_eventId_accept=Accept<="+acceptLt response3 = RestfulTest.send_post_request(cas_server_url, data = http_data_for_confirm, session_id = cas_server_sessionId ) casTicket = DataProcess.get_first_matching_group_by_pattern(response3.headers['set-cookie'], 'CASTGC=(\S+); Path=\/irisCAS; Secure') redirectUrl = response3.headers['location'] return cas_server_sessionId, casTicket, redirectUrl @staticmethod def redirect_to_service(service_url, service_sessionId): response = RestfulTest.send_get_request(service_url, session_id = service_sessionId, allow_redirects= True) return response @staticmethod def login_to_service(service_url, userName="admin", userPasswd="admin"): service_sessionId, redirectToCas = LoginToServer.get_service_sessionId_redirectUrl(service_url) cas_server_sessionId, casTicket, redirectToServer = LoginToServer.cas_server_authentication(redirectToCas, userName, userPasswd) response = LoginToServer.redirect_to_service(redirectToServer, service_sessionId) if response.status_code == 200: print "Login To Service Success" else: print "Login To Service Fail" return service_sessionId