HP ALM 12.21 REST API - 401 Unauthorized - C# - c#

I am trying to use the API against our ALM 12.21 server, but always ends up with "401 Unauthorized". It seems that I get the auth cookie back correctly, but when I try to do something after that I am unauthorized.
I use this the get this to get auth cookie (seems to work):
HttpWebRequest myauthrequest = (HttpWebRequest)WebRequest.Create("https://server/qcbin/authentication-point/alm-authenticate");
string AuthenticationXML = #"<alm-authentication>
<user>username</user>
<password>password</password>
</alm-authentication>";
byte[] Requestbytes = Encoding.UTF8.GetBytes(AuthenticationXML);
myauthrequest.Method = "POST";
myauthrequest.ContentType = "application/xml";
myauthrequest.ContentLength = Requestbytes.Length;
myauthrequest.Accept = "application/xml";
Stream RequestStr = myauthrequest.GetRequestStream();
RequestStr.Write(Requestbytes, 0, Requestbytes.Length);
RequestStr.Close();
HttpWebResponse myauthres = (HttpWebResponse)myauthrequest.GetResponse();
var AuthenticationCookie = myauthres.Headers.Get("Set-Cookie");
AuthenticationCookie = AuthenticationCookie.Replace(";Path=/;HTTPOnly", "");
I am not sure if the .Replace is needed. Just read it somewhere. I get 401 both with or without it though, when trying to do subsequent requests.
Trying e.g. this after getting auth cookie:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://server/qcbin/rest/domains/FS/projects/P3602_SLS_Project/defects/1");
req.Method = "GET";
req.ContentType = "application/xml";
req.Accept = "application/octet-stream";
req.Headers.Set(HttpRequestHeader.Cookie, AuthenticationCookie);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
Stream RStream2 = res.GetResponseStream();
XDocument doc = XDocument.Load(RStream2);
Which fails with 401.
Anyone have complete working code for the ALM 12.21 REST API?

You need two main cookies to get the ALM REST API works perfectly.
LWSSO_COOKIE_KEY
QCSession
almURL = "https://..com/qcbin/"
authEndPoint = almURL + "authentication-point/authenticate"
qcSessionEndPoint = almURL + "rest/site-session"
After you get successful response for authEndPoint you will get the LWSSO_COOKIE_KEY
Use that cookie in your next request to qcSessionEndPoint, it should give you QCSession cookie.
Use both LWSSO_COOKIE_KEY and QCSession cookies in your subsequent requests to get data from ALM.
I see that you are using octet-stream to get the defect response. When I checked the documentation, it can return one of the following types.
"application/xml"
"application/atom+xml"
"application/json"
Just in case, if you need to see some working implementation in python, here it is https://github.com/macroking/ALM-Integration/blob/master/ALM_Integration_Util.py
It may give you some idea.

Thank you #Barney. You sent me in the correct direction :-) For anyone interested, I managed it like this, e.g. for getting defect ID 473:
Logging on to create a CookieContainer and then use that to do the actual ALM data fetch:
private void button1_Click(object sender, EventArgs e)
{
string almURL = #"https://url/qcbin/";
string domain = "domain";
string project = "project";
CookieContainer cookieContainer = LoginAlm2(almURL, "username", "password", domain, project);
HttpWebRequest myWebRequest1 = (HttpWebRequest)WebRequest.Create(almURL + "/rest/domains/" + domain + "/projects/" + project + "/defects/473");
myWebRequest1.CookieContainer = cookieContainer;
myWebRequest1.Accept = "application/json";
WebResponse webResponse1 = myWebRequest1.GetResponse();
StreamReader reader = new StreamReader(webResponse1.GetResponseStream());
string res = reader.ReadToEnd();
}
public CookieContainer LoginAlm2(string server, string user, string password, string domain, string project)
{
//Creating the WebRequest with the URL and encoded authentication
string StrServerLogin = server + "/api/authentication/sign-in";
HttpWebRequest myWebRequest = (HttpWebRequest)WebRequest.Create(StrServerLogin);
myWebRequest.Headers[HttpRequestHeader.Authorization] = "Basic " + Base64Encode(user + ":" + password);
WebResponse webResponse = myWebRequest.GetResponse();
CookieContainer c = new CookieContainer();
Uri uri = new Uri(server);
string StrCookie = webResponse.Headers.ToString();
string StrCookie1 = StrCookie.Substring(StrCookie.IndexOf("LWSSO_COOKIE_KEY=") + 17);
StrCookie1 = StrCookie1.Substring(0, StrCookie1.IndexOf(";"));
c.Add(new Cookie("LWSSO_COOKIE_KEY", StrCookie1) { Domain = uri.Host });
//Then the QCSession cookie
string StrCookie2 = StrCookie.Substring(StrCookie.IndexOf("QCSession=") + 10);
StrCookie2 = StrCookie2.Substring(0, StrCookie2.IndexOf(";"));
c.Add(new Cookie("QCSession", StrCookie2) { Domain = uri.Host });
//Then the ALM_USER cookie
string StrCookie3 = StrCookie.Substring(StrCookie.IndexOf("ALM_USER=") + 9);
StrCookie3 = StrCookie3.Substring(0, StrCookie3.IndexOf(";"));
c.Add(new Cookie("ALM_USER", StrCookie3) { Domain = uri.Host });
//And finally the XSRF-TOKEN cookie
string StrCookie4 = StrCookie.Substring(StrCookie.IndexOf("XSRF-TOKEN=") + 12);
StrCookie4 = StrCookie4.Substring(0, StrCookie4.IndexOf(";"));
c.Add(new Cookie("XSRF-TOKEN", StrCookie4) { Domain = uri.Host });
return c;
}
Works like a charm :-)

Related

C# eBay OAuth Compliance API Authentication Problems

After many struggles, I was finally able to get the OAuth Authentication/Refresh token process down. I am certain that the tokens I am using in this process are good. But I am struggling to communicate with the Compliance API and I think it may have more to do with my headers authentication process than it does specifically the Compliance API but I am not certain. I've tried so many different combinations of the below code unsuccessfully. I've tried to do the call as a GET and a POST (the call should be a GET). I've tried it with the access token encoded and not encoded. With all of my different code combinations tried I've been getting either an authorization error or a bad request error. You can see some of the various things I've tried from commented out code. Thank you for your help.
public static string Complaince_GetViolations(string clientId, string ruName, string clientSecret, string accessToken, ILog log)
{
var clientString = clientId + ":" + clientSecret;
//byte[] clientEncode = Encoding.UTF8.GetBytes(clientString);
//var credentials = "Basic " + System.Convert.ToBase64String(clientEncode);
byte[] clientEncode = Encoding.UTF8.GetBytes(accessToken);
var credentials = "Bearer " + System.Convert.ToBase64String(clientEncode);
var codeEncoded = System.Web.HttpUtility.UrlEncode(accessToken);
HttpWebRequest request = WebRequest.Create("https://api.ebay.com/sell/compliance/v1/listing_violation?compliance_type=PRODUCT_ADOPTION")
as HttpWebRequest;
request.Method = "GET";
// request.ContentType = "application/x-www-form-urlencoded";
//request.Headers.Add(HttpRequestHeader.Authorization, credentials);
//request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + codeEncoded);
request.Headers.Add(HttpRequestHeader.Authorization, credentials);
//request.Headers.Add("Authorization", "Bearer " + codeEncoded);
request.Headers.Add("X-EBAY-C-MARKETPLACE-ID", "EBAY-US");
log.Debug("starting request.GetRequestStream");
string result = "";
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream())) //FAILS HERE
{
result = streamReader.ReadToEnd();
}
//DO MORE STUFF BELOW
return "STUFF";
}
And I finally figured out a resolution to this problem. The HTML encoding of the entire bearer string was the issue. If anyone needs this in the future your welcome. =)
HttpWebRequest request = WebRequest.Create("https://api.ebay.com/sell/compliance/v1/listing_violation?compliance_type=PRODUCT_ADOPTION")
as HttpWebRequest;
request.Method = "GET";
request.Headers.Add(HttpRequestHeader.Authorization, System.Web.HttpUtility.HtmlEncode("Bearer " + accessToken));
request.Headers.Add("X-EBAY-C-MARKETPLACE-ID", "EBAY-US");
log.Debug("starting request.GetRequestStream");
string result = null;
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}

hoopla-api using ASP.NET WEB API

I want to make use of the hoopla-api which from their website uses "CURL" and I need to make HTTP "POST, GET" using C#.
They mention that any Questions related to development posted on stackoverflow but I didn't see any post from anyone who asked a question. or perhaps it is just too easy for many people to get this up.
Here is their link https://developer.hoopla.net/docs/authentication
I am not sure how to properly implement this in C#:
Below is my sample GET method.
string res;
string client_id = "myclientid";
string client_secret = "mysecret";
string auth = client_id + ":" + client_secret;
string ContentType = "application/json";
string url = #"https://api.hoopla.net/users";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
//request.Credentials = new NetworkCredential(client_id, client_secret);
request.Headers.Add("Authorization", "Bearer" + auth);
request.ContentType = ContentType;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
res = reader.ReadToEnd();
}
and from their site they do have a python script that imports request module. but not sure if python has this module.
Here is their code :
import requests
client_id = 'your-generated-client-id'
client_secret = 'your-generated-client-secret'
host = 'https://api.hoopla.net'
auth_params = {'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret}
r = requests.post( host+'/oauth2/token', params = auth_params )
access_token = r.json()['access_token']
request_headers = {
'Authorization':'Bearer '+access_token,
'Accept':'application/vnd.hoopla.api-descriptor+json'
}
r = requests.get( host+'/',headers = request_headers )
}
Can anyone assist me in getting this in C#?

Can't create workitem via webrequest in RTC

I'm trying to create a .NET web application integration with RTC, where I would insert new workitems using RTC change management services, as defined in this article (specifically in "Create a Change Request"). I was able to get the URL-to-be-used inside services.xml file (/oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/) and my goal is to insert data using JSON.
My code is basically the following:
CookieContainer cookies = new CookieContainer();
HttpWebRequest documentPost = (HttpWebRequest)WebRequest.Create(rtcServerUrl + "/oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/order");//"Order" is the workitem name
documentPost.Method = "POST";
documentPost.CookieContainer = cookies;
documentPost.Accept = "application/json";
documentPost.ContentType = "application/x-oslc-cm-change-request+json";
documentPost.Timeout = TIMEOUT_SERVICO;
string json = "{ \"dc:title\":\"" + title + "\", \"rtc_cm:filedAgainst\": [ { \"rdf:resource\" : \"" + rtcServerUrl + "/resource/itemOid/com.ibm.team.workitem.Category/" + idCategory + "\"} ] }"; //dc:title and rtc_cm:filedAgainst are the only two mandatory data from the workitem I'm trying to create
using (var writer = new StreamWriter(documentPost.GetRequestStream()))
{
writer.Write(json);
writer.Flush();
writer.Close();
}
Encoding encode = System.Text.Encoding.UTF8;
string retorno = null;
//Login
HttpWebRequest formPost = (HttpWebRequest)WebRequest.Create(rtcServerUrl + "/j_security_check");
formPost.Method = "POST";
formPost.Timeout = TIMEOUT_REQUEST;
formPost.CookieContainer = request.CookieContainer;
formPost.Accept = "text/xml";
formPost.ContentType = "application/x-www-form-urlencoded";
String authString = "j_username=" + userName + "&j_password=" + password; //create authentication string
Byte[] outBuffer = System.Text.Encoding.UTF8.GetBytes(authString); //store in byte buffer
formPost.ContentLength = outBuffer.Length;
System.IO.Stream str = formPost.GetRequestStream();
str.Write(outBuffer, 0, outBuffer.Length); //update form
str.Close();
//FormBasedAuth Step2:submit the login form and get the response from the server
HttpWebResponse formResponse = (HttpWebResponse)formPost.GetResponse();
var rtcAuthHeader = formResponse.Headers["X-com-ibm-team-repository-web- auth-msg"];
//check if authentication has failed
if ((rtcAuthHeader != null) && rtcAuthHeader.Equals("authfailed"))
{
//authentication failed. You can write code to handle the authentication failure.
//if (DEBUG) Console.WriteLine("Authentication Failure");
}
else
{
//login successful
HttpWebResponse responseRetorno = (HttpWebResponse)request.GetResponse();
if (responseRetorno.StatusCode != HttpStatusCode.OK)
retorno = responseRetorno.StatusDescription;
else
{
StreamReader reader = new StreamReader(responseRetorno.GetResponseStream());
retorno = "[Response] " + reader.ReadToEnd();
}
responseRetorno.Close();
formResponse.GetResponseStream().Flush();
formResponse.Close();
}
As I was managed to search for in other forums, this should be enough in order to create the workitem (I have a very similar code working to update workitems using "" URL and PUT method). However, instead of create the workitem in RTC and give me some response with item's identifier, the request's response returns a huge JSON file that ends with "oslc_cm:next":"https:///oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/%7B0%7D?oslc_cm.pageSize=50&_resultToken=_AAY50FEkEee1V4u7RUQSjA&_startIndex=50. It's a JSON representation of the XML I receive when I access /oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/ directly from browser, like I was trying to do a simple query inside the workitem's collection (even though I'm using POST, not GET).
I also tried to use PUT method, but then I receive a 405 status code.
Does anyone have an idea of what am I missing here? My approach is wrong, even though with the same approach I'm able to update existing workitem data in RTC?
Thanks in advance.

Using HttpWebRequest to login to instagram

Hey guys so I'm trying to write a C# Application in which the user can login to their instagram account from a WPF. The problem I'm having is getting the authorization code. When I use this code I keep getting the login page URL, not the successful login page.
Help please!
Any feedback is appreciated! been stuck on this a while
private static AuthInfo GetInstagramAuth(string oAuthUri, string clientId, string redirectUri, InstagramConfig config,
string login, string password)
{
List<Auth.Scope> scopes = new List<Auth.Scope>();
scopes.Add(Auth.Scope.basic);
var link = InstaSharp.Auth.AuthLink(oAuthUri, clientId, redirectUri, scopes);
// Логинимся по указанному узлу
CookieAwareWebClient client = new CookieAwareWebClient();
// Зашли на страницу логина
var result = client.DownloadData(link);
var html = System.Text.Encoding.Default.GetString(result);
// Берем токен
string csr = "";
string pattern = #"csrfmiddlewaretoken""\svalue=""(.+)""";
var r = new System.Text.RegularExpressions.Regex(pattern);
var m = r.Match(html);
csr = m.Groups[1].Value;
// Логинимся
string loginLink = string.Format(
"https://instagram.com/accounts/login/?next=/oauth/authorize/%3Fclient_id%3D{0}%26redirect_uri%3Dhttp%3A//kakveselo.ru%26response_type%3Dcode%26scope%3Dbasic", clientId);
NameValueCollection parameters = new NameValueCollection();
parameters.Add("csrfmiddlewaretoken", csr);
parameters.Add("username", login);
parameters.Add("password", password);
// Нужно добавить секретные кукисы, полученные перед логином
// Нужны заголовки что ли
string agent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
client.Headers["Referer"] = loginLink;
client.Headers["Host"] = "instagram.com";
//client.Headers["Connection"] = "Keep-Alive";
client.Headers["Content-Type"] = "application/x-www-form-urlencoded";
//client.Headers["Content-Length"] = "88";
client.Headers["User-Agent"] = agent;
// client.Headers["Accept-Language"] = "ru-RU";
//client.Headers["Accept-Encoding"] = "gzip, deflate";
client.Headers["Accept"] = "text/html, application/xhtml+xml, */*";
client.Headers["Cache-Control"] = "no-cache";
// Запрос
var result2 = client.UploadValues(loginLink, "POST", parameters);
// Постим данные, Получаем code
// New link не на апи, а на instagram
string newPostLink = string.Format(
"https://instagram.com/oauth/authorize/?client_id={0}&redirect_uri=http://kakveselo.ru&response_type=code&scope=basic", clientId);
HttpWebRequest request =
(HttpWebRequest) WebRequest.Create(newPostLink);
request.AllowAutoRedirect = false;
request.CookieContainer = client.Cookies;
request.Referer = newPostLink;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = agent;
string postData = String.Format("csrfmiddlewaretoken={0}&allow=Authorize", csr);
request.ContentLength = postData.Length;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] loginDataBytes = encoding.GetBytes(postData);
request.ContentLength = loginDataBytes.Length;
Stream stream = request.GetRequestStream();
stream.Write(loginDataBytes, 0, loginDataBytes.Length);
// send the request
var response = request.GetResponse();
string location = response.Headers["Location"];
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("--Responce from the webrequest--");
Console.ResetColor();
Console.WriteLine(((HttpWebResponse)response).ResponseUri+"\n\n");
// Теперь вытаскиваем код и получаем аутентификацию
pattern = #"kakveselo.ru\?code=(.+)";
r = new System.Text.RegularExpressions.Regex(pattern);
m = r.Match(location);
string code = m.Groups[1].Value;
// Наконец, получаем токен аутентификации
var auth = new InstaSharp.Auth(config); //.OAuth(InstaSharpConfig.config);
// now we have to call back to instagram and include the code they gave us
// along with our client secret
var oauthResponse = auth.RequestToken(code);
return oauthResponse;
}
}
I was using this website as an example and CookieAwareWebClient is just a WebClient that handles Cookies. I'll post it below:
using System;
/// <summary>
/// A Cookie-aware WebClient that will store authentication cookie information and persist it through subsequent requests.
/// </summary>
using System.Net;
public class CookieAwareWebClient : WebClient
{
//Properties to handle implementing a timeout
private int? _timeout = null;
public int? Timeout
{
get
{
return _timeout;
}
set
{
_timeout = value;
}
}
//A CookieContainer class to house the Cookie once it is contained within one of the Requests
public CookieContainer Cookies { get; private set; }
//Constructor
public CookieAwareWebClient()
{
Cookies = new CookieContainer();
}
//Method to handle setting the optional timeout (in milliseconds)
public void SetTimeout(int timeout)
{
_timeout = timeout;
}
//This handles using and storing the Cookie information as well as managing the Request timeout
protected override WebRequest GetWebRequest(Uri address)
{
//Handles the CookieContainer
var request = (HttpWebRequest)base.GetWebRequest(address);
request.CookieContainer = Cookies;
//Sets the Timeout if it exists
if (_timeout.HasValue)
{
request.Timeout = _timeout.Value;
}
return request;
}
}
Are you sure the login process on the website don't use javascript in some step(s)?
As far as i'm aware, if it's the case webrequests won't do the job.
All datas/actions that are javascript related will be non-existent through mere webrequests.
I noticed that for security reasons, Websites with personnal accounts tend to mix their login process with javascript now, to avoid bots requests.
Okay So I Figured out the issue. If you want to use webrequests and webresponses you need to make sure that the header information is correct. The issue with mine was I wasn't passing enough information from the browser. To see this information i used Tamper Data
It's an add on for Firefox and allows you took look at everything you are sending or receiving to/from the server.

HttpWebRequest in c#

I am making a Get request with following code:
TheRequest = (HttpWebRequest)WebRequest.Create(aURL);
TheRequest.Method = "GET";
TheRequest.CookieContainer = TheCookies;
TheRequest.UserAgent = GetUserAgent();
TheRequest.KeepAlive = false;
TheRequest.Timeout = 20000;
TheRequest.ReadWriteTimeout = 20000;
TheRequest.AllowAutoRedirect = true;
TheRequest.Headers.Add("Accept-Language", "en-us");
TheResponse = (HttpWebResponse)TheRequest.GetResponse();
TheResponseString = new StreamReader(TheResponse.GetResponseStream(), Encoding.ASCII).ReadToEnd();
After this I take the cookies as follows:
string theCookieHeader = TheResponse.Headers[HttpResponseHeader.SetCookie];
Then I process the string to be in proper cookie format and put it in cookie container to give it in next POST request. From the Response string (TheResponseString) I create the proper Post data and the cookies from cookiecontainer.
My code for POST request is as follows:
TheRequest = (HttpWebRequest)WebRequest.Create(aURL);
TheRequest.Method = "POST";
TheRequest.CookieContainer = TheCookies;
TheRequest.UserAgent = GetUserAgent();
TheRequest.KeepAlive = false;
TheRequest.Timeout = 20000;
TheRequest.ReadWriteTimeout = 20000;
TheRequest.AllowAutoRedirect = true;
TheRequest.ContentType = "application/x-www-form-urlencoded";
TheRequest.Headers.Add("Accept-Language", "en-us");
byte[] bytes = Encoding.ASCII.GetBytes(aPostDataString);
TheRequest.ContentLength = bytes.Length;
Stream oStreamOut = TheRequest.GetRequestStream();
oStreamOut.Write(bytes,0,bytes.Length);
oStreamOut.Close();
TheResponse = (HttpWebResponse)TheRequest.GetResponse();
TheResponseString = new StreamReader(TheResponse.GetResponseStream(), Encoding.ASCII).ReadToEnd();
Now the problem is I have two websites,they are partner websites,they have every thing same(It seems but if you doubt about anything then please tell me),but for one website it works fine and for other one it gives the response string of websites Error Page.
Please help me what to see for diagnosing the problem.
I had similar problem. Try to save the cookies from request, after you got the responce or even better, put this code in finally block. Run it once for TheRequest.Host and second time for the host of your second site. Also look if you need http or https
foreach (Cookie c in TheRequest.CookieContainer.GetCookies(new Uri("http://" + TheRequest.Host)))
{
TheCookies.SetCookies(new Uri("http://" + TheRequest.Host), c.Name + "=" + c.Value);
}

Categories

Resources