2016-10-17 70 views
4

我想在F#中創建一個調用Jira REST API來讀取/創建問題的.NET應用程序。在JIRA中使用OAuth在.NET/F中使用REST調用#

我用OpenSSL生成了.pub.pem,並用公鑰創建了Jira中的應用程序鏈接。

下面是簽名的功能,我放在一起(根據掉一些C#代碼,我在博客中找到),這樣得到我最初的令牌響應:

let rsasha1 (signingKey : string) str = 
    let rsa = new RSACryptoServiceProvider() 
    rsa.FromXmlString(signingKey) 
    let shaHashObject = new SHA1Managed() 
    let data = Encoding.ASCII.GetBytes(str : string) 
    let hash = shaHashObject.ComputeHash(data) 
    let signedValue = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")) 
    Convert.ToBase64String(signedValue, Base64FormattingOptions.None) 

這是我的功能用做ルM(也可從片段在網上找到)

/// Request a token and return: 
/// oauth_token, oauth_token_secret, oauth_callback_confirmed 
let requestToken() = 

    let queryParameters = 
     ["oauth_callback", "oob" 
     "oauth_consumer_key", consumerKey 
     "oauth_nonce", System.Guid.NewGuid().ToString().Substring(24) 
     "oauth_signature_method", "RSA-SHA1" 
     "oauth_timestamp", currentUnixTime().ToString() 
     "oauth_version", "1.0"] 

    let signingString = baseString "POST" requestTokenURI queryParameters 

    let rsaSignature = rsasha1 consumerSecretXML signingString 

    let realQueryParameters = ("oauth_signature", rsaSignature)::queryParameters 

    let req = WebRequest.Create(requestTokenURI, Method="POST") 
    let headerValue = createAuthorizeHeader realQueryParameters 
    req.Headers.Add(HttpRequestHeader.Authorization, headerValue) 

    let resp = req.GetResponse() 
    let stream = resp.GetResponseStream() 
    let txt = (new StreamReader(stream)).ReadToEnd() 

    let parts = txt.Split('&') 
    (parts.[0].Split('=').[1], 
    parts.[1].Split('=').[1], 
    parts.[2].Split('=').[1] = "true") 

成功返回令牌信息,但我不能確定下一步該怎麼做,一旦我有令牌。我基於此的原始C#代碼使用的是HMACSHA1而不是RSASHA1,並簡單地將消費者密鑰與令牌密鑰連接起來,然後再次調用簽名函數。

我無法得到這個工作方式。我必須將.pem文件中的私鑰轉換爲XML,才能將其讀入RSACryptoServiceProvider。如果在轉換之前嘗試將令牌密鑰連接到私鑰上,則會出現錯誤。

我該如何去簽署令牌密鑰,以便我可以對Jira進行後續REST調用?

+0

在請求中使用會話cookie現在您已經創建了一個會話,這只是在隨後對服務器的所有請求中設置cookie的問題。 將會話對象存儲在客戶端上。你這樣做的方式取決於你的客戶如何實現。 當您想要提出請求時,請從會話中獲取cookie名稱和值,並使用它們在請求的標題中設置「cookie」字段。您可以在下面看到一個示例: 標題:{cookie:JSESSIONID = 6E3487971234567896704A9EB4AE501F} –

+0

Sergey Tihon推薦[推特](https://twitter.com/sergey_tihon/status/788240599686213633):[Atlassian.SDK]( https://www.nuget.org/packages/Atlassian.SDK/)。 –

回答

1

我們無法獲得的OAuth工作的最好時刻,但通過@黑爾格的回答,我們能夠僞造記錄的啓發用戶的方式。

#r "System.Net.Http" 

open System 
open System.Collections.Generic 
open System.Net 
open System.Net.Http 
open System.Net.Http.Headers 

let toKVPairSeq l = 
    Seq.map (fun (k, v) -> KeyValuePair(k, v)) l 

let handler = new HttpClientHandler() 
let client = new HttpClient(handler) 
client.BaseAddress <- Uri "http://jira/" 
let authRequestContent = new FormUrlEncodedContent([ 
                 "os_username", "jira-user" 
                 "os_password", "jira-password" 
                 "os_cookie", "true" 
                 "os_destination", "" 
                 "user_role", "" 
                 "atl_token", "" 
                 "login", "Log+In" 
                ] |> toKVPairSeq) 
let request = new HttpRequestMessage() 
let result1 = client.PostAsync("login.jsp", authRequestContent).Result 
result1.EnsureSuccessStatusCode() 
printf "%A %s" result1.StatusCode <| result1.Content.ReadAsStringAsync().Result 
let result2 = (client.GetAsync "rest/api/latest/issue/ISSUE-1").Result 
printf "%A %s" result2.StatusCode <| result2.Content.ReadAsStringAsync().Result 
2

這可能不是你想要的答案,但我做了一些你需要的東西。我沒有使用任何其他「普通」身份驗證(通過JSON),但是當我通過身份驗證時,我又重新使用Session變量JSESSIONID(cookie)。

如果這適用於您(您的身份驗證,然後抓取JSESSIONID,然後重新使用它),下面的代碼應該工作(作爲原則)。

請注意,我正在使用FSharp.Data <package id="FSharp.Data" version="2.3.1" targetFramework="net46" />,也許在同一次運行中會出現一些「朋友」(一些其他軟件包依賴項)。

另請注意,我爲查詢返回的JSON引用了一個文件,因此如果您打算使用JSON提供程序並執行搜索或類似搜索,則需要一些JSON來推斷搜索結果來自。

希望代碼能給你一些指示。

是的,這個代碼很可能不是F#;-)

#r "System.Servicemodel" 
#r "System.Xml" 
#r @"..\packages\FSharp.Data.2.3.1\lib\net40\fsharp.data.dll" 

open FSharp.Data 
[<Literal>] 
let baseUrl = "https://jira" 

[<Literal>] 
let jiraUrlQuery = baseUrl + "/rest/api/2/search?jql=text%20~%20%22some text%22%20ORDER%20BY%20created%20DESC" 

[<Literal>] 
let loginUrl = "/rest/auth/1/session" 

//[<Literal>] 
let creds = sprintf "{\"username\": \"%s\", \"password\": \"%s\" }" 

[<Literal>] 
let loginInfoExample = "{\"session\":{\"name\":\"JSESSIONID\",\"value\":\"åæø8F95074F7398C68961708066EC6342A8\"},\"loginInfo\":{\"failedLoginCount\":7,\"loginCount\":434,\"lastFailedLoginTime\":\"2016-08-02T13:15:27.392+0200\",\"previousLoginTime\":\"2016-08-05T08:46:45.168+0200\"}}" 

type LoginInfo = JsonProvider<loginInfoExample> 

let login = Http.Request(baseUrl+loginUrl, httpMethod="POST", body=HttpRequestBody.TextRequest(creds "SomeUserName" "SomePassword"), headers= [ "Content-Type", "application/json" ]) 
//let login = JsonValue.Request(baseUrl+loginUrl, httpMethod="POST", headers= [ "Content-Type", "application/json" ]) 

let getText = 
    function 
    | Text s -> s 
    | _ -> "" 

let loggedIn = LoginInfo.Parse(getText login.Body).Session.Value.ToString() 

type JiraIssues = JsonProvider< ".\JIRA\query.json" > //jiraUrlQuery> 

let listOfCases = JiraIssues.Parse(Http.Request(jiraUrlQuery, cookies=["JSESSIONID", loggedIn]).Body |> getText) 

listOfCases.Issues |> Seq.map (fun x -> x.Fields.Summary, x.Fields.Created) |> Seq.sortByDescending (fun (s,c) -> c) |> Seq.iter (fun (s,c) -> printfn "%A: %s" c s) 
+0

這是否說明最近版本的JIRA不支持應用程序的基本身份驗證? –

+0

可能不是。但是,在某個地方發回一些oauth標記仍然是「同樣的原則」,並且某個地方通常是某種cookie。 –