I try to GET query from MVC app to OWIN SelfHost. Both have WindowsAuth. MVC is running from Visual Studio in one virtual machine, OWIN SelfHost works as service in other virtual machine. Response is always 401. I tried to set Credentials,PreAuthenticate in WebRequest - nothing changed. I can't let anonymous auth in my system. How I should make request? Thanks.
The solution was found:
WebRequest req = WebRequest.Create(Properties.Settings.Default.SelfHostAdress + "/api/data/GetReportsOrgStructTreeView?currentUserName=" + currentUsername + "&parentNodeId=" + parentNodeId + "&filterId=" + filterId);
req.UseDefaultCredentials = true;
req.PreAuthenticate = true;
WebResponse resp = req.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
content = sr.ReadToEnd();
return content;
Related
Hello Office / SharePoint Developers,
I am working on a project based on the Office Developer Patterns and Practices Sample where a console application accesses a WebAPI which then access SharePoint Online as the logged in user: The sample is here: https://github.com/SharePoint/PnP/tree/master/Samples/AzureAD.WebAPI.SPOnline
Question:
When I attempt to upload a file to the document library, I get an error 401 "The remote server returned an error: (401) Unauthorized".
The file read options such as listing the documents and querying for documents works fine.
The user credentials I supply are of a user that is the site collection admin, owner, and global admin on the tenant.
I get an access token from SharePoint online based on the token I get in the native client.
public string GetAccessToken(string accessToken)
{
string clientID = _clientId;
string clientSecret = _clientSecret;
var appCred = new ClientCredential(clientID, clientSecret);
var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.windows.net/common");
AuthenticationResult authResult = authContext.AcquireToken(new Uri(_spoUrl).GetLeftPart(UriPartial.Authority), appCred, new UserAssertion(accessToken));
return authResult.AccessToken;
}
This is the CSOM that uploads the file. I know it works as I can paste it into a console app and using (SharePointOnlineCredentails) it works fine.
string newToken = _tokenSvc.GetAccessToken(accessToken);
using (ClientContext cli = new ClientContext(_spoUrl))
{
cli.ExecutingWebRequest += (s, e) => e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + newToken);
cli.AuthenticationMode = ClientAuthenticationMode.Default;
using (var fs = new FileStream(#"c:\test.txt", FileMode.Open))
{
var fi = new FileInfo("test.txt");
var list = cli.Web.Lists.GetByTitle("documents");
cli.Load(list.RootFolder);
cli.ExecuteQuery();
var fileUrl = String.Format("{0}/{1}", list.RootFolder.ServerRelativeUrl, fi.Name);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(cli, fileUrl, fs, true);
Web web = cli.Web;
Microsoft.SharePoint.Client.File newFile = web.GetFileByServerRelativeUrl(fileUrl);
cli.Load(newFile);
cli.ExecuteQuery();
ListItem item = newFile.ListItemAllFields;
item["CRUID"] = "CRU_1337";
item.Update();
cli.ExecuteQuery();
}
}...
TLDR: I get 401 on file upload. Reads work. I am using CSOM with an access token that is supposed to be a webAPI on behalf of the logged in user.
I look forward to hearing your advice!
Chris
I am not sure whether we could upload/download files from SP using access tokens with CSOM now , see discussion here two years ago . But we could use sharepoint online rest api to upload files to sharepoint online , i tried below code and it works fine in the code sample AzureAD.WebAPI.SPOnline :
string sharePointUrl = ConfigurationManager.AppSettings["SharePointURL"];
string newToken = GetSharePointAccessToken(sharePointUrl, this.Request.Headers.Authorization.Parameter);
using (ClientContext cli = new ClientContext(sharePointUrl))
{
cli.AuthenticationMode = ClientAuthenticationMode.Default;
cli.ExecutingWebRequest += (s, e) => e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + newToken);
cli.AuthenticationMode = ClientAuthenticationMode.Default;
byte[] bytefile = System.IO.File.ReadAllBytes(#"e:\log.txt");
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create("https://xxx.sharepoint.com/sites/xxx/" + "/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents')/Files/add(url='log.txt',overwrite=true)");
endpointRequest.Method = "POST";
endpointRequest.Headers.Add("binaryStringRequestBody", "true");
endpointRequest.Headers.Add("Authorization", "Bearer " + newToken);
endpointRequest.GetRequestStream().Write(bytefile, 0, bytefile.Length);
HttpWebResponse endpointresponse = (HttpWebResponse)endpointRequest.GetResponse();
}
The code below is ended up being the solution to my question:
/* Beginning CSOM Magic */
using (ClientContext cli = new ClientContext(_spoUrl))
{
/* Adding authorization header */
cli.ExecutingWebRequest += (s, e) => e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + newToken);
cli.AuthenticationMode = ClientAuthenticationMode.Default;
//Get Document List
List documentsList = cli.Web.Lists.GetByTitle(_libraryName);
var fileCreationInformation = new FileCreationInformation();
//Assign to content byte[] i.e. documentStream
var data = System.IO.File.ReadAllBytes(#"c:\test.txt");
fileCreationInformation.Content = data;
//Allow owerwrite of document
fileCreationInformation.Overwrite = true;
//var siteURL = _spoUrl;
var documentListURL = "shared documents";
//var documentName = "/test.txt";
//Upload URL
fileCreationInformation.Url = string.Concat(_spoUrl,"/",documentListURL,"/",documentName);
Microsoft.SharePoint.Client.File uploadFile = documentsList.RootFolder.Files.Add(
fileCreationInformation);
//Update the metadata for a field having name "DocType"
uploadFile.ListItemAllFields["CRUID"] = cruId;
uploadFile.ListItemAllFields.Update();
cli.ExecuteQuery();
}
I am converting an existing application from QBXML to use the QBOE API V3 for the QuickBooks Online accounts. I have managed to complete the OAuth and have what appears to be valid tokens/secrets using the DevDefined toolkit. I am stuck on generation of the oauth_signature. All the documentation points me to use the Intuit.Ipp DLL's however I can't because it is written to .net 4.0 framework and the server my application runs on only has 2.0 loaded. I can move my application but testing that upgrade would put me after the cut off deadline (4/16/2014). Is there a way I can build the signature using the DevDefined or some other option?
The application runs on IIS 6.0, DotNet Framework 2.0, with ASP.VB.
Is the cutoff 4/16 now? I didn't see that announced anywhere. I thought it was 3/15.
I haven't tested this on .NET 2.0 but this just uses DevDefined without all the overhead. It will handle the signing and the http request for you.
using System.Text;
using DevDefined.OAuth.Consumer;
using DevDefined.OAuth.Framework;
// etc...
public void doGet()
{
IOAuthSession session = CreateSession();
string resp = session.Request().Get().ForUrl("https://quickbooks.api.intuit.com/v3/company/"
+ realmId + "/query?query=select * from customer where DisplayName='" + name + "'").ToString();
}
public void doPost(string Name)
{
IOAuthSession session = CreateSession();
string reqBody = "<Customer xmlns=\"http://schema.intuit.com/finance/v3\" domain=\"QBO\" sparse=\"false\">";
reqBody += "<DisplayName>" + Name + "</DisplayName>";
reqBody += "</Customer>";
byte[] bytes = Encoding.UTF8.GetBytes(reqBody);
session.ConsumerContext.UseHeaderForOAuthParameters = true;
IConsumerRequest req = session.Request().WithRawContentType("application/xml").WithRawContent(bytes);
req = req.WithAcceptHeader("application/xml");
req = req.ForUrl("https://quickbooks.api.intuit.com/v3/company/"
+ realmI + "/customer");
string resp = req.Post().ToString();
}
private IOAuthSession CreateSession()
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = Properties.Settings.Default.consumerKey,
ConsumerSecret = Properties.Settings.Default.consumerSecret,
SignatureMethod = SignatureMethod.HmacSha1
};
IOAuthSession session = new OAuthSession(consumerContext);
session.AccessToken = myAccessToken;
return session;
}
I have a .net website on IIS that has an virtual directory pointing to MVC application. I am trying to reuse a sitemaster.master on the RAzor view header.
I have this code below on a Razor view _hearder_it.cshtml.
I am doing a StreamReader on test.aspx page which has a sitemaster.master only. The req.GetResponse does return the stream from the sitemaster(menu bar etc.). However the sitemaster.master has Request.Cookies and the cookies never have a value. I know they should have a value because I already test outside of the mvc application. The cookie changes the view of the sitemaster and that is the reason I need it.
//This code does returns the stream .
WebRequest req = HttpWebRequest.Create(url );
req.Method = "GET";
string source;
using (StreamReader reader = new StreamReader(req.GetResponse().GetResponseStream()))
source = reader.ReadToEnd();
Response.Write(source); // I get HTML result back from my sitemaster.master.
Cookies are sent in request headers, while you don't add any cookies to your webrequest here. Here is a post that might help you
I added the cookie in the CookieContainer. This code is working successfully.
This code is in Razor view _header_it.cshtml:
#{
string userTyp3 = Request.Cookies["MY_USERTYPE"] != null ? Server.UrlDecode(Request.Cookies["MY_USERTYPE"].Value) : "";
CookieCollection _CookieCollection2 = new CookieCollection();
HttpWebRequest _request2 = (HttpWebRequest)WebRequest.Create("http://MySite_TEST/it/test.aspx");
_request2.Method = "GET";
_request2.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
_request2.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)";
_request2.Referer = "http://MySite_TEST/it";
_request2.KeepAlive = true;
//Here is auth cookie, works fine
_request2.CookieContainer = _cookieContainer;
_request2.CookieContainer.Add(( new Cookie ( "MY_USERTYPE", userTyp3 , "/", "MySite_TEST") )) ;
_request2.Headers.Add(HttpRequestHeader.CacheControl, "no-cache=set-cookie");
HttpWebResponse _response2 = (HttpWebResponse)_request2.GetResponse();
StreamReader _reader2 = new StreamReader(_response2.GetResponseStream());
Response.Write(_reader2.ReadToEnd()); //
_response2.Close();
_reader2.Close();
}
I used the example on this URL:
http://stackoverflow.com/questions/2476092/login-website-curious-cookie-problem?rq=1]
Thank you
I'm working on a WinRT app that does login to a webpage and get some data. The problem is that I'm getting a "HttpRequestException: An error occurred while sending the request" message. Here is the code:
Uri url = new Uri("https://miyoigo-b.yoigo.com/selfcare/login");
HttpContent msg = new StringContent("account[cli]=" + number + "&password=" + pass);
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
handler.UseCookies = true;
handler.CookieContainer = new CookieContainer();
HttpClient req = new HttpClient(handler);
req.DefaultRequestHeaders.Add("Host", "miyoigo-b.yoigo.com");
req.DefaultRequestHeaders.ExpectContinue = false;
HttpResponseMessage response = await req.PostAsync(url, msg);
string responseBody = await response.Content.ReadAsStringAsync();
I've been trying a lot of thing I found over the internet, even disabling my firewall, but nothing worked. I'm porting this from a Windows Phone app and it did work with this:
Uri url = new Uri("https://miyoigo-b.yoigo.com/selfcare/login");
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.Method = "POST";
req.Headers["Host"] = "miyoigo-b.yoigo.com";
req.CookieContainer = new CookieContainer();
req.BeginGetRequestStream(new AsyncCallback(WriteCallback), req);
And afterwards, in the Callback I created a Stream and wrote the credentials.
Any idea?? I know that the problem is only with this webpage, maybe I'm forgetting to send something or the format of the POST content is not correct...
Thanks
Finally the problema was that Win8 Metro Apps only accepts SSL3.1 and this webpage was using SSL3.0. The solution was using the new version of the webpage.
Thank you all
I have been looking for a way to remove an attachment from Jira using the SOAP Api, but it seems that this is not possible natively, and I would prefer not having to implement a new plugin for Jira, as suggested in the accepted answer to this question, or recompiling the existing plugin to support this as mentioned here.
This answer to the abovementioned question seems to do exactly what I want, but alas, I can't get i to work. The response i get is an error stating that:
XSRF Security Token Missing
JIRA could not complete this action due to a missing form token.
You may have cleared your browser cookies, which could have resulted in the expiry of your current form token. A new form token has been reissued.
As I am using Asp.Net MVC C#, I have used the code from the answer, as is, with only the server url adjusted, as well as with different credentials (a Jira user) and the username/password passed through as request parameters using:
os_username=jirausername&os_password=xxxxxxx
The code I am currently using is as follows:
public void RemoveAttachment(string issueid, string attachmentid)
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment url
string attachmenturl = baseUrl + "/secure/DeleteAttachment.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid;
client.Credentials = new System.Net.NetworkCredential("jirausername", "xxxxxxx");
string response = client.DownloadString(attachmenturl);
}
}
I ended up using a method that first requests the deletion confirmation form, then extracts a required token from the form, and finally posts something equivalent to the form content in order to delete the attachment. Code below.
public void RemoveAttachment(string issueid, string attachmentid)
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment deletion confirm url
string confirmurl = baseUrl + "/secure/DeleteAttachment!default.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid + "&os_username=jirauser&os_password=xxxxxx";
//Create a cookie container to maintain the xsrf security token cookie.
CookieContainer jiracontainer = new CookieContainer();
//Create a get request for the page containing the delete confirmation.
HttpWebRequest confirmrequest = (HttpWebRequest)WebRequest.Create(confirmurl);
confirmrequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
confirmrequest.CookieContainer = jiracontainer;
//Get the response and the responsestream.
WebResponse confirmdeleteresponse = confirmrequest.GetResponse();
Stream ReceiveStream = confirmdeleteresponse.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader confirmreader = new StreamReader(ReceiveStream);
// Read the content.
string confirmresponse = confirmreader.ReadToEnd();
//Create a regex to extract the atl/xsrf token from a hidden field. (Might be nicer to read it from a cookie, which should also be possible).
Regex atl_token_matcher = new Regex("<input[^>]*id=\"atl_token\"[^>]*value=\"(?<token>\\S+)\"[^>]*>", RegexOptions.Singleline);
Match token_match = atl_token_matcher.Match(confirmresponse);
if (token_match.Success)
{
//If we found the token get the value.
string token = token_match.Groups["token"].Value;
//Compute attachment delete url.
string deleteurl = baseUrl + "/secure/DeleteAttachment.jspa";
//Construct form data.
string postdata = "atl_token=" + HttpContext.Current.Server.UrlEncode(token) + "&id=" + issueid + "&deleteAttachmentId=" + attachmentid + "&Delete=Delete&os_username=jirauser&os_password=xxxxxx";
//Create a post request for the deletion page.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(deleteurl);
request.KeepAlive = false;
request.CookieContainer = jiracontainer; // Remember to set the cookiecontainer.
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
//Turn our request string into a byte stream
byte[] postBytes = Encoding.ASCII.GetBytes(postdata);
//Make sure you specify the proper type.
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
//Send the post.
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
//Get the response.
WebResponse deleteresponse = request.GetResponse();
// Open the responsestream using a StreamReader for easy access.
StreamReader deleteresponsereader = new StreamReader(deleteresponse.GetResponseStream());
// Read the content.
string deleteresponsecontent = deleteresponsereader.ReadToEnd();
// do whatever validation/reporting with the response...
}
else
{
//We couldn't find the atl_token. Throw an error or something...
}
}
Edit:
Same thing works for removing comments. Replace 'attachment' with 'comment' and 'deleteAttachmentId' with 'commentId' and you should be good to go.