(401) Unauthorized Error When Calling Web API from a Console Application - asp.net-web-api

When I call my WEB API from my Console Application, I encounter:
The remote server returned an error: (401) Unauthorized.
This application runs in Interanet (Windows Authentication)
Uri uri = new Uri("http://myServer/api/main/foo");
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;
using (Stream data = client.OpenRead(uri))
{
using (StreamReader sr = new StreamReader(data))
{
string result = sr.ReadToEnd();
Console.WriteLine(result);
}
}
Updated
If I replace
client.Credentials = CredentialCache.DefaultCredentials;
with this line
client.Credentials = new NetworkCredential( username, password);
it works fine but I need the current credential to be set automatically.
Any idea?
Thanks in advance ;)

You use the default windows credentials here
client.Credentials = CredentialCache.DefaultCredentials;
Specify the credential that you want to authenticate using the following code:
var credential = new NetworkCredential(, , );
serverReport.ReportServerCredentials.NetworkCredentials = credential;

following line is the cause of this behaviour :
client.Credentials = CredentialCache.DefaultCredentials;
Actually this line assigns the credentials of the logged in user or the user being impersonated ( which is only possible in web applications ) , so what I believe is that you have to provide credentials explicitly (http://msdn.microsoft.com/en-us/library/system.net.credentialcache(v=vs.110).aspx) , thanks.

Related

AcquireTokenSilentAsync not working

I have the following setup:
var authContext = new AuthenticationContext("https://login.microsoftonline.com/common");
string redirectUri = Url.Action("Authorize", "Planner", null, Request.Url.Scheme);
Uri authUri = authContext.GetAuthorizationRequestURL("https://graph.microsoft.com/", SettingsHelper.ClientId,
new Uri(redirectUri), UserIdentifier.AnyUser, null);
// Redirect the browser to the Azure signin page
return Redirect(authUri.ToString());
This takes you to:
// Get the 'code' parameter from the Azure redirect
string authCode = Request.Params["code"];
// The same url we specified in the auth code request
string redirectUri = Url.Action("Authorize", "Planner", null, Request.Url.Scheme);
// Use client ID and secret to establish app identity
ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
//FileTokenCache at specific location
TokenCache fileTokenCache = new FilesBasedAdalV3TokenCache("C:\\temp\\justin.bin");
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthorityTenantID, fileTokenCache);
AuthenticationResult authResult = null;
try
{
// Get the token silently first
authResult = await authContext.AcquireTokenSilentAsync(SettingsHelper.O365UnifiedResource, credential, UserIdentifier.AnyUser);
}
catch (AdalException ex)
{
authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, fileTokenCache);
authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(authCode, new Uri(redirectUri), credential, SettingsHelper.O365UnifiedResource);
}
The token is successfully saved in the file and it seems that it is also being successfully retrieved. However the silent token acquisition still gives an exception to get token first using the non silent function. What am I missing please?
Note that O365UnifiedResource is set to https://graph.microsoft.com/
solved this by using
new UserIdentifier("<email address used to login microsoft apps>", UserIdentifierType.RequiredDisplayableId)
instead of
UserIdentifier.AnyUser
and fixed the client ID to be the APP ID as specified in the registration of the app

WebRequest returns 404 when switching to SSL

Having built an app using PCL method in Xamarin and have had it working 100% using standard HTTP I now changed the remote test server to use SSL with self signed certs.
The app contacts a custom API for logging onto a server and querying for specific data.
I've changed the app to look at SSL now and initially got an error regarding Authentication not working or something but turned off SSL related errors for testing using:
ServicePointManager.ServerCertificateValidationCallback += (o, certificate, chain, errors) => true;
in my AppDelegate files FinishedLaunching method which got over that error.
I'm now getting a 404 / protocol error when trying to do my Login POST to the given URL.
I am using HttpWebRequest for my RESTful calls and this works fine if I change back to plain http.
Not sure why but some articles suggested using ModernHttpClient, which I did. I imported the component (also added the package using NuGet) to no avail.
Am I missing something else that I should be configuring in my code related to httpwebresponse when contacting the SSL server or is this component simply incapable of speaking to an SSL server?
My login function is as follows (Unrelated code removed/obfuscated):
public JsonUser postLogin(string csrfToken, string partnerId, string username, string password){
string userEndPoint = SingletonAppSettngs.Instance ().apiEndPoint;
userEndPoint = userEndPoint.Replace ("druid/", "");
var request = WebRequest.CreateHttp(string.Format(this.apiBaseUrl + userEndPoint + #"user/login.json"));
// Request header collection set up
request.ContentType = "application/json";
request.Headers.Add ("X-CSRF-Token", csrfToken);
// Add other configs
request.Method = "POST";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json_body_content = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}";
streamWriter.Write(json_body_content);
streamWriter.Flush();
streamWriter.Close();
}
try{
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader (httpResponse.GetResponseStream ())) {
var content = reader.ReadToEnd ();
content = content.Replace ("[],", "null,");
content = content.Replace ("[]", "null");
if (content == null) {
throw new Exception ("request_post_login - content is NULL");
} else {
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.NullValueHandling = NullValueHandling.Ignore;
JsonUser deserializedUser = JsonConvert.DeserializeObject<JsonUser>(content, jss);
if(content.Contains ("Hire company admin user")){
deserializedUser.user.roles.__invalid_name__5 = "Hire company admin user";
deserializedUser.user.roles.__invalid_name__2 = "authenticated user";
}
return deserializedUser;
}
}
}catch(Exception httpEx){
Console.WriteLine ("httpEx Exception: " + httpEx.Message);
Console.WriteLine ("httpEx Inner Exception: " + httpEx.InnerException.Message);
JsonUser JsonUserError = new JsonUser ();
JsonUserError.ErrorMessage = "Error occured: " + httpEx.Message;
return JsonUserError;
}
}
When making a Web Request using ModernHttpClient, I generally follow the pattern below. Another great library created by Paul Betts is refit, and can be used to simplify rest calls.
using (var client = new HttpClient(new NativeMessageHandler(false, false)))
{
client.BaseAddress = new Uri(BaseUrl, UriKind.Absolute);
var result = await Refit.RestService.For<IRestApi>(client).GetData();
}
The second parameter for NativeMessageHandler should be set to true if using a customSSLVerification.
Here's a look at IRestApi
public interface IRestApi
{
[Get("/foo/bar")]
Task<Result> GetMovies();
}
Number of things I had to do to get this to work.
The Self Signed Cert had to allow TLS 1.2
As the API is Drupal based, HTTPS had to be enabled on the server and a module installed to manage the HTTP specific pages.

Windows.Web.Http.HttpClient + WEB API Windows Authentication

Im using Windows.Web.Http.HttpClient to connect to my WEB API. Application haven't prompted for userid and password, but recently i changed WEB API by moving AuthorizeAttribute filter from Action to Class level. Now my Windows store 8.1 application prompt for user id and password. Please let me know how to set HttpClient to not prompt the login and password. Can any1 suggest me do i need to add header to my httpcleint
using (Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient())
{
// Add a user-agent header
var headers = httpClient.DefaultRequestHeaders;
// The safe way to check a header value from the user is the TryParseAdd method
// Since we know this header is okay, we use ParseAdd with will throw an exception
// with a bad value - http://msdn.microsoft.com/en-us/library/windows/apps/dn440594.aspx
headers.UserAgent.ParseAdd("ie");
headers.UserAgent.ParseAdd("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
using (var response = await httpClient.GetAsync(new Uri(url)))
I dont see a way to send Default credentials.
Disable UI dialogs using HttpBaseProtocolFilter.AllowUI. Try this:
Windows.Web.Http.Filters.HttpBaseProtocolFilter filter =
new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
filter.AllowUI = false;
HttpClient client = new HttpClient(filter);
Uri uri = new Uri("http://localhost/?basic=1");
var response = await client.GetAsync(uri);
System.Diagnostics.Debug.WriteLine(response);
Do you need credentials? Use HttpBaseProtocolFilter.ServerCredential. Try this:
Uri uri = new Uri("http://localhost?ntlm=1");
Windows.Web.Http.Filters.HttpBaseProtocolFilter filter =
new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
filter.AllowUI = false;
// Set credentials that will be sent to the server.
filter.ServerCredential =
new Windows.Security.Credentials.PasswordCredential(
uri.ToString(),
"userName",
"abracadabra");
HttpClient client = new HttpClient(filter);
var response = await client.GetAsync(uri);
System.Diagnostics.Debug.WriteLine(response);
Do you need default Windows credentials (domain credentials)? Simply add the Enterprise Authentication capability to your Package.appxmanifest.
I tried to apply your solution but it doesn't work as expected, or maybe I don't understand what I'm supposed to do.
I need to user the Windows credentials and I have enabled the Enterprise Authentification capability on my UWP app.
I use the code that you suggest:
var filter = new HttpBaseProtocolFilter();
filter.AllowUI = false;
var client = new HttpClient(filter);
HttpResponseMessage response = new HttpResponseMessage();
response = await client.PostAsync(concUri, null);
But the response returns me a 401.3 error...
If I add the login/password to the ServerCredential, this works well:
var filter = new HttpBaseProtocolFilter();
filter.AllowUI = false;
filter.ServerCredential = new Windows.Security.Credentials.PasswordCredential(WebServiceConstants.WebServiceUrl.ToString(), "login", "password");
var client = new HttpClient(filter);
HttpResponseMessage response = new HttpResponseMessage();
response = await client.GetAsync(concUri);
But I don't see what is the role of the Enterprise Authentication capability in this case, if I need to pass the login and the password...

How to Get OAuth Access Token for Pinterest?

I am accessing Pinterest API for getting user's information by using this url but I can not find that how to generate an access token for Pinterest.
According to this blog post, it says that
Pinterest uses OAuth2 to authenticate users
Can you please tell me, from where I can generate OAuth access tokens for Pinterest?
First, register for an app and set up a redirect URI:
https://developers.pinterest.com/manage/
Then, find your client secret under Signature Tester:
https://developers.pinterest.com/tools/signature/
Bring the user to the OAuth dialog like this:
https://www.pinterest.com/oauth/?consumer_id=[client_id]&response_type=[code_or_token]&scope=[list_of_scopes]
If response type if token, it will be appended as a hash in the redirect URI.
If response type is code, see the post below for details on how to exchange code for token:
What's the auth code endpoint in Pinterest?
You need to register a client app under manager Apps option in Dropdown menu when you login
or
https://developers.pinterest.com/manage/
Register your app and you get AppID.
This follow the process in this link you have
http://wiki.gic.mx/pinterest-developers/
Hope this helps
**USING C#**
public string GetOAuthToken(string data)
{
string strResult = string.Empty;
try
{
string Clientid = WebConfigurationManager.AppSettings["Pinterest_Clientid"];
string ClientSecret = WebConfigurationManager.AppSettings["Pinterest_ClientSecret"];
string uri_token = WebConfigurationManager.AppSettings["Pinterest_Uri_Token"];
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri_token);
string parameters = "grant_type=authorization_code"
+ "&client_id="
+ Clientid
+ "&client_secret="
+ ClientSecret
+ "&code="
+ data;
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(parameters);
System.IO.Stream os = null;
req.ContentLength = bytes.Length;
os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
System.Net.WebResponse webResponse = req.GetResponse();
System.IO.Stream stream = webResponse.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(stream);
string response = reader.ReadToEnd();
Newtonsoft.Json.Linq.JObject o = Newtonsoft.Json.Linq.JObject.Parse(response);
strResult = "SUCCESS:" + o["access_token"].ToString();
}
catch (Exception ex)
{
strResult = "ERROR:" + ex.Message.ToString();
}
return strResult;
}
Refer
Pinterest uses the User Flow or Oauth2
When you have an app you ant to use the app flow with an access token
So you need to create the flow yourself or use this tool online
https://frederik.today/codehelper/tools/oauth-access-token-pinterest
To make it yourself
Request Token
Exchange code for Acces Token
https://developers.pinterest.com/docs/api/v5/

WebClient NotFound error but working with HttpWebRequest/Response

In my WinPhone app I'm accessing a REST service.
At the beginnings I was using this code:
WebClient wc = new WebClient();
wc.Credentials = credentials;
wc.Headers["App-Key"] = appKey;
wc.DownloadStringCompleted +=
(o, args) => MessageBox.Show(args.Error == null ? "OK" : "Error");
wc.DownloadStringAsync(uri);
but it suddenly stopped working returning me a "The remote server returned an error: NotFound" error. After a google session and some clicks in the control panel, I didn't get it to work.
I decided to try this other way:
HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
request.Credentials = credentials;
request.Headers["App-Key"] = appKey;
request.BeginGetResponse(asResult =>
{
var response = request.EndGetResponse(asResult) as HttpWebResponse;
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
Dispatcher.BeginInvoke(
() => MessageBox.Show(response.StatusCode.ToString()));
}, null);
and it works.
I also tried to run the first snipped pointing the URI to google's home page and it works (I had to remove the credentials, of course).
Can anyone explain what's going on?
UPDATE
I managed to get it working by replacing the
wc.Credentials = new NetworkCredentials(username, password);
with
wc.Headers["Authorization"] = "Basic someBase64encodedString";
but i still wonder what happened and which are the differences between the first and the second line.
PS: the test URI is: https://api.pingdom.com/api/2.0/checks but you will need an app-key from them.
When using the Credentials property, the HttpWebRequest implementation will wait the challenge response from server before to send the 'Authorization' header value.
But this can be an issue in some cases, so you have to force Basic authentication by providing directly the Authorization header.
Example when using a REST Client library like Spring.Rest :
RestTemplate template = new RestTemplate("http://example.com");
template.RequestInterceptors.Add(new BasicSigningRequestInterceptor("login", "password"));
string result = template.GetForObject<string>(uri);

Resources