利用Python requests庫實現cas認證

1.準備工做-背景知識

1.1 requests庫簡介:

python有不少能夠用來測試接口的模塊,我的以爲,requests庫是最好用的, 在Robot Framwork裏,它的測試庫requestsLibrary,也是基於requests寫的。html

1.1.1 安裝:python

做爲第三方模塊,使用前,須要安裝,最簡單的安裝方式以下瀏覽器

pip install requests緩存

1.1.2 語法(簡明版):安全

1)如何發送請求 :服務器

發送get請求:requests.get(url, params,  headers, cookies, verify, allow_redirects...)restful

發送post請求: requests.post(url, params, data, headers, cookies, verify, allow_redirects...)cookie

*****以上只有url參數是必填的,其餘能夠根據須要選填session

*****除了get和post,還支持其餘http請求,好比delete等等,不過在咱們的cas認證中,只須要get和post;並且通常的接口測試中,最經常使用的也就是get和post消息app

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 隨機產生一個至關長度、惟1、不可僞造的 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+"&lt="+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&lt="+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
相關文章
相關標籤/搜索