I want to access NiFi and do some actions through external web application created in C# using proxy user request. For that,
I have created C# web application and hosted as secure connection(https).
I need to access NiFi components using its REST API service without authorization token. Added C# web application certificate into NiFi truststore and added certificate name as user (CN=machineName) in NiFi. Also, added "proxy user request" policy for the newly added user.
In C# web application, added "X-ProxiedEntitiesChain = <username>" in header while requesting NiFi API. But it returns "unknown user" error in response. Please find the sample code below,
var httpWebReq=(HttpWebRequest)WebRequest.Create("https://testhost:8080/nifi-api/access");
httpWebReq.Headers["X-ProxiedEntitiesChain"] = "<username>";
httpWebReq.Method = "GET";
var response = (HttpWebResponse)httpWebReq.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
return responseString;
Based on the available information the most likely problem is that you are not using a properly authorized user.
Check that you are using the proper username, and confirm that it is actually authorized for access.
(And of course make sure you don't just pass the string "username")
Related
I have an on-premise Dynamics CRM (2016) that is configured with ADFS (3.0). When a user want's to Login, they get redirected to the ADFS login page and the user enter their Windows AD credentials.
From a .net core application I need to make request to the CRM api using HttpClient. When I try to send the credentials like I normally would for a Windows Auth CRM it doesnt work. I get a 401 Unauthorized. Like below.
HttpClient client = new HttpClient(new HttpClientHandler() { Credentials = new NetworkCredential("myuser", "mypassword", "mydomain") });
var result = client.GetAsync("https://mycrmaddress/api/data/v8.0/accounts");
I also tried using Adal to retrieve a token and attach it as a bearer token to the request but I'm unable to get a token with adal. When I try I receive the following:
The authorization server does not support the requested 'grant_type'. The authorization server only supports 'authorization_code'
ADFS 3.0 doesn't support this flow.
I cannot upgrade to ADFS 4.0 so I would like to know what are my options to make an authenticated call to CRM api (without prompting a login window as this application is a service).
Is there any configuration I can do on ADFS so my first example work? Or is it possible to do it with Adal even if it's ADFS 3.0? Or any other solution...
I found the answer to my question. It's kinda hackish, but I tested it myself and it works. As a temporary solution this will do the trick.
Details are available here: https://community.dynamics.com/crm/f/117/t/255985
ADFS 3.0 supports the Authorization Code flow and this what we will use in this case.
We need to retrieve an authorization code. Normally at this steps a windows is prompted to the user to enter its credentials. By doing a POST and sending the user/password it's possible to retrieve an authorization code.
{authProvider} - ADFS Uri - something like
https://adfs.mycompany.com/adfs/oauth2/
{ClientId} - The Guid used to
by your infrastructure team to add your application to ADFS
{RedirectUri} - The IFD Uri for dynamics - should match the redirect
Url used to by your infrastructure team to add your application to
ADFS
username - The User set up on ADFS and in Dynamics
password - The password for the above user
Then we make the following call with these information using HttpClient.
var uri = $"{authProvider}authorize?response_type=code&client_id={clientId}&resource={redirectUri}&redirect_uri={redirectUri}";
var content = new FormUrlEncodedContent(new[] {
new KeyValuePair<string,string>("username",username),
new KeyValuePair<string,string>("password",password),
});
var responseResult = _httpManager.PostAsync(uri, content).Result;
The response content will be an html page (Remember normally this flow prompts a login page to the user). In this page there will be a form that contains the authorization code. using a library like HtmlAgilityPack retrieve the token. This is the hackish part of the solution.
Now that we have an authorization code we need to retrieve an access token.
For that we need to make the following call
var uri = $"{authProvider}token";
var content = new FormUrlEncodedContent(new[] {
new KeyValuePair<string,string>("grant_type","authorization_code"),
new KeyValuePair<string,string>("client_id",clientId),
new KeyValuePair<string,string>("redirect_uri",redirectUri),
new KeyValuePair<string,string>("code",code)
});
var response = await _httpManager.PostAsync(uri, content);
The response content will be a json string that will contain the access token.
With the access token, make the call to CRM rest API.
You will need to attach the token to the HttpClient in the header as a bearer token.
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token);
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
From now on you can make calls to CRM api and you will be authorized. However be carefull normally access token are short lived. You will either need to increase their lifetime or request a new token everytime it's expired.
I want to retrieve all the list of SharePoint online using REST API in c#.
For this, i am using below code
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create("https://o365.sharepoint.com/sites/test-site/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.ContentLength = 0;
But i am getting below error
403:Forbidden Access denied. Before opening files in this location. you must first browse to the web site and select the option to login automatically.
So i have searched on this and found that we have to pass AuthenticationToken, which is written in this link
https://msdn.microsoft.com/en-us/library/jj164022.aspx
endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
But how do i get the accesstoken ?
From that same page:
[…] It also assumes that you have a valid OAuth access token that is stored in the accessToken variable. You do not need the access token if you make this call from inside an add-in web, as you would in a SharePoint-hosted add-in. Note that you cannot obtain an access token from code that is running on a browser client. You must obtain the access token from code that is running on a server. Context Token OAuth flow for SharePoint Add-ins and Authentication Code OAuth flow for SharePoint Add-ins explain how you can obtain an access token.
I am writing an app that will talk with Salesforce. Salesforce provides access to APIs via OAuth. I've been attempting to go through the OAuth authentication process described here. Currently, I'm attempting to authorize my app. I have the following code.
// Ask Salesforce for a request token
var request = (HttpWebRequest)(WebRequest.Create(String.Format("https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id={0}&redirect_uri=http://localhost:5004/home/AuthCallback", CONSUMER_KEY)));
request.Method = "POST";
request.ContentType = "application/json";
// Retrieve the request token from the response
var response = (HttpWebResponse)(request.GetResponse());
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string accessCodeData = accessCodeReader.ReadToEnd();
}
This code is triggered when a user clicks a button in my ASP.NET MVC view. When executed, this code calls to Salesforce. I see a request in fiddler. The request header looks like this:
POST /services/oauth2/authorize?response_type=code&client_id={consumerKey}&redirect_uri=http://localhost:5004/home/AuthCallback HTTP/1.1
I am in fact passing my consumer key, I'm just removing it from the example. Regardless, this request returns a 302, with a body size of 0. I might be misunderstanding something. However, I was expecting to get a request token. I was then going to use the request token to get the access token.
What am I doing wrong?
You are misusing the API.
Take a closer look at the sequence diagram at their page (under Obtaining an Access Token): in the auhorization_code flow you are supposed to redirect the browser to their page so that the user sees the login page, provides his/her credentials and you get the token back. Instead, you are trying to POST there using a web request from your server.
This particular flow belongs then to the passive flows group, this group is intended to be used in browser apps, your server redirects the browser to their server and you basically get the response to the uri passed in the redirect_uri parameter and this should point back to your application at your server.
There are other flows, of them one is suited for non-browser apps, it is called resource owner password flow. In this flow it is your application that hosts the login UI and you send the username/password to the authorization server and you get the token back. It is to be read in their docs however whether this flow is supported.
Read more here: http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
Take a look how I handle the OAuth2 flow to Google, using the DotNetOpenAuth library. This is a direct solution, applying it to any other provider should be straightforward.
http://www.wiktorzychla.com/2014/11/simple-oauth2-federated-authentication.html
I am struggling to understand and set up a Service and Consumer where the Service will run as the user logged into the Consumer.
My consumer is an MVC application. My Service is a Web Api application. Both run on separate servers within the same domain. Both are set to use Windows Auth.
My consumer code is:
private T GenericGet<T>(string p)
{
T result = default(T);
HttpClientHandler handler = new HttpClientHandler() { PreAuthenticate = true, UseDefaultCredentials = true };
using (HttpClient client = new HttpClient(handler))
{
client.BaseAddress = new Uri(serviceEndPoint);
HttpResponseMessage response = client.GetAsync(p).Result;
if (response.IsSuccessStatusCode)
result = response.Content.ReadAsAsync<T>().Result;
}
return result;
}
In my Service I call User.Identity.Name to get the caller ID but this always comes back as the consumer App Pool ID, not the logged in user. The consumer App Pool is running as a Network Service, the server itself is trusted for delegation. So how do I get the logged in User? Service code:
// GET: /Modules/5/Permissions/
[Authorize]
public ModulePermissionsDTO Get(int ModuleID)
{
Module module= moduleRepository.Find(ModuleID);
if (module== null)
throw new HttpResponseException(HttpStatusCode.NotFound);
// This just shows as the App Pool the MVC consumer is running as (Network Service).
IPrincipal loggedInUser = User;
// Do I need to do something with this instead?
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
ModulePermissionsDTO dto = new ModulePermissionsDTO();
// Construct object here based on User...
return dto;
}
According to this question, Kerberos is required to make this set up work because the HttpClient runs in a separate thread. However this confuses me because I thought the request sends an Authorization header and so the service should be able to use this and retrieve the user token. Anyway, I have done some testing with Kerberos to check that this correctly works on my domain using the demo in "Situation 5" here and this works but my two applications still wont correctly pass the logged in user across.
So what do I need to do to make this work? Is Kerberos needed or do I need to do something in my Service to unpack the Authorisation header and create a principal object from the token? All advice appreciated.
The key is to let your MVC application (consumer) impersonate the calling user and then issue the HTTP requests synchronously (i.e. without spawning a new thread). You should not have to concern yourself with low-level implementation details, such as NTLM vs Kerberos.
Consumer
Configure your MVC application like so:
Start IIS Manager
Select your MVC web application
Double click on 'Authentication'
Enable 'ASP.NET Impersonation'
Enable 'Windows Authentication'
Disable other forms of authentication (unless perhaps Digest if you need it)
Open the Web.config file in the root of your MVC application and ensure that <authentication mode="Windows" />
To issue the HTTP request, I recommend you use the excellent RestSharp library. Example:
var client = new RestClient("<your base url here>");
client.Authenticator = new NtlmAuthenticator();
var request = new RestRequest("Modules/5/Permissions", Method.GET);
var response = client.Execute<ModulePermissionsDTO>(request);
Service
Configure your Web API service like so:
Start IIS Manager
Select your Web API service
Double click on 'Authentication'
Disable 'ASP.NET Impersonation'.
Enable 'Windows Authentication'
If only a subset of your Web API methods requires users to be authenticated, leave 'Anonymous Authentication' enabled.
Open the Web.config file in the root of your Web API service and ensure that <authentication mode="Windows" />
I can see that you've already decorated your method with a [Authorize] attribute which should trigger an authentication challenge (HTTP 401) when the method is accessed. Now you should be able to access the identity of your end user through the User.Identity property of your ApiController class.
The key issue with double hop is delegation of user credential to second call. I want to elaborate a little bit about it. C1 = client browser , S1 = First Server , S2 = Second Server.
Suppose our complete system support window authentication. When user access S1 from browser , its default window credential pass to server S1, but when S1 make a call to S2 , by default it don't pass credential to S2.
Resolution :
We must enable window authentication/ impersonation on both machines.
WE need to enable delegation between server so that S1 can trust to S2 and will pass credential to S2.
You can find some useful details at below links :
http://blogs.msdn.com/b/farukcelik/archive/2008/01/02/how-to-set-up-a-kerberos-authentication-scenario-with-sql-server-linked-servers.aspx
https://sqlbadboy.wordpress.com/2013/10/11/the-kerberos-double-hop-problem/
If you are trying to access service which is hosted on windows authentication then do following.
var request = new RestRequest(Method.POST);
If you want to use applications default credentials which must have access on hosted service server
request.UseDefaultCredentials = true;
or user below to pass the credentials manually
request.Credentials = new NetworkCredential("Username", "Password", "Domain");
im just going to dive straight in and give you a little background on what im trying to do, what i've tried, and the obstacles in my way. so here goes..
MY GOAL
To post to a facebook profile or wall from a desktop application.
The desktop application will be used by individual users who have their own facebook account.
The aim is to create each user their own facebook app and get the app id and app secret.
And then use the app id and app secret in the desktop application ( Saved somewhere in database or config )
to allow the user of the desktop application to post to their profile without having to enter their email address and password to login first
So in summary, 1 facebook app per facebook account.
The app settings will be saved in each users desktop application
Post to their own facebook via their own facebook app without logging in
The main emphasis here being that the user does not have to log in manually via a window or browser.
I have created my facebook app and have set it to live status.. i have also added in all possible permissions and extended permissions in the settings ( Within facebook ) just to make sure i wasnt missing anything.
So I do have my AppID and App secret.. I also have my Client Token which it says to use in place of the app secret for 'auth methods'. I use this to get my access token. I tried the app secret and it doesnt return the access token
MY ATTEMPTS :
C# FACEBOOK SDK
So, i started with and am still trying to use the c# sdk
I can retrieve my access token but cannot post.
I get he below errors all the time with whatever i try... these are just 2 of the many code examples i have tried.
(OAuthException - #2500) An active access token must be used to query information about the current user.
dynamic r = fb.Post("me/feed", new { message = "My seconds wall post using Facebook C# SDK" });
(OAuthException - #190) The client token cannot be used for this API
dynamic r = fb.Post("kevin.maguire.965/feed", new { message = "My second wall post using Facebook C# SDK" });
I read the following extract from the below link which states my access token is an app token and i need a access token for a user or page?
Need Help on OAuthException Code 2500
Error 2500 means you have no access token or an app access token but are trying to access /me/ - 'me' is a placeholder for 'current user or page ID' so won't be valid without an access token for a user or page
So, i have tried to get the userID back using the following Answer ( Facebook C# SDK Get Current User )
var fb = new FacebookClient("access_token");
dynamic result = fb.Get("me", new [] { fields = "id" });
var userId = result.id;
I get the access token which i assume is the app token and not the user token
dynamic result = fb.Get("oauth/access_token", new
{
client_id = this.ApplicationId,
client_secret = this.AppSecret,
grant_type = "client_credentials"
});
fb.AccessToken = result.access_token;
So i have no idea at this moment in time how to post to my profile
I am able to achieve the above using twitter where i can use the secret, token, id etc ... they provide and I can successfully post to my twitter account from a desktop application WITHOUT logging into my twitter account.
Another user has also found it quite easy to post to twitter without any real issues. ( facebook c# sdk getting started )
He also seems to have had success which i have not using the same code - this code was uses in June 2012 so there could have been breaking changes released since
then.
I got the message : (OAuthException - #2500) An active access token must be used to query information about the current user... when i used the sdk.
When i tried to get the access token using a web request and then pass that token to the sdk object to create a facebookclient i got this message
(OAuthException - #190) Invalid OAuth access token signature.
WebRequest request = WebRequest.Create("https://graph.facebook.com/oauth/access_token? grant_type=client_credentials&client_id=999999999999999&client_secret=edefefr8e09r8e08r080r8er0e");
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string accesstoken = reader.ReadToEnd();
MessageBox.Show("accesstoken")
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
var fb = new FacebookClient(accesstoken);
dynamic parameters = new ExpandoObject();
parameters.message = "test";
dynamic result = fb.Post("me/feed", parameters);
var id = result.id;
Obviously in the code above i changed the id and secret to dummy values.
So basically folks...the above links and above code are only a pinch of what I have tried to date in the last few days... i've basically ran out of options and am missing something here which could be averting my attention easily.. or maybe not :) i dont know.
If any one would even have a simple windows form, or wpf window application example using the c# sdk or using restsharp or just using WebRequest object with 'POST' method then I would be eternally greatful.
Just to iterate again that it is a desktop application and not ASP.net .
Many thanks folks for your attention and time.
From what I can see you are supplying an incorrect access token. Since you haven't provided the code with regards to obtaining the access token, may I suggest you take a look at this link which explains how to build a Facebook application, including obtaining an access token via a WebBrowser control.
EDIT: You are supplying the app access token but are trying to post as a user. For this operation you need a user access token which you can obtain by following the steps in the link above.