C# console application authentication session - c#

How could someone implement the az login (Azure CLI) experience in a C# Console application?
In that case, a browser window is opened, the user authenticates and after that he can access the private resources.
My guess is that the authentication token is stored somewhere, but where? Session variable, file..?
Update
I found out that there is a folder ~/.azure storing the relevant information. So the question is more on the first part (starting a browser and getting the resulting token).

How could someone implement the az login (Azure CLI) experience in a C# Console application?
1.Starting a browser with Process.Start(#"http://url");. After user enter his credential, you will get the authorization code. Copy it.
2.Get an authorization code.
3.Get access token with following code:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("ContentType", "application/json");
var requestURl = new Uri($"https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token");
string body = "{\"client_id\": \"3c35ed0b-a441-4c57-9d1c-3a3b0392d9c3\",\"code\":\"the_code_you_copy_in_the_second_step\",\"redirect_uri\": \"https://localhost\",\"grant_type\": \"authorization_code\",\"client_secret\": \"xxxxxxxxxxxxxx\",\"scope\": \"user.read\"}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
var response = client.PostAsync(requestURl, stringContent).Result;
}
4.The result:
For more detials about how to get authorization code and access token you could refer to this article.

Related

403 Forbidden Error in Keycloak API (view-users)

I'm having issues trying to access auth/admin/realms/{realm-name}/users API. I've already tried everything from other questions and answers, but nothing seems to work. Steps that I did:
The user already has a role that has realm-management and view-users on it.
I've already assigned this same role to my client in the scopes section.
I can't have Service Accounts Enabled in my client because I need to have Access Type as confidential, and that won't allow my user to access Login page from Application.
I've also already tried to give 'view-users' role to my user and to my client individually as a Client role, it also didn't work.
My code in C#:
var authState = await AuthenticationProvider.GetAuthenticationStateAsync();
var user = authState.user;
var tokenResult = await TokenProvider.RequestAccessToken();
_accessToken = _tokenResult.Value;
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var request = new HttpRequestMessage(HttpMethod.Get, $"{url}/auth/admin/realms/{realm name}/users");
request.Headers.Add("Accept", "application/json");
var response = await _client.SendAsync(request);
// Rest of code that gets response and deserializes to array of users.
I honestly don't know what to do. Any help would be very appreciated. Thanks so much!
Since Keycloak's Rest API endpoints changes very often (e.g. BasePath, Signature etc.), I found very useful:
login to keycloak's admin panel (UI) and see from developer tools the endpoint for fetching the users (on Users menu item in Manage group parent). In particular, {$HOST}/admin/realms/{$REALM_NAME}/users is the endpoint in version 17.0.1.
I also assigned the client role view-users from realm-management to one of my realm users as it is displayed below (UI of version 17.0.1)
I was able to fetch the users by just adding user's access token to the request.

Retrieving user information in Azure Function (C#) from Angular-cli application

I'm having troubles retrieving user information inside an Azure Function and have no idea how to do this. I've tried different things already, but nothing seems to work...
First of all, I created an Angular-cli application and am able to login using the "adal-angular5" npm-package.
When I want to retrieve information from a HttpTriggering Azure function, I can't seem to find how to get more information about the user using the token from the angular app (or how to validate the logged in user). I'm including it in the headers of the message.
headers.append('Authorization', `Bearer ${this.adal5Service.userInfo.token}`);
I've created an app registration in Azure AD including my reply URL, Permissions to "Microsoft Graph" and "Windows Azure Active Directory"
Does anyone know how to do this? (If more information should be necessary to solve... just tell me, and I'll happily provide that)
Things I tried already
Code below with both requestUrl's (one is in comment) and with/without sending the token in the header
using (var client = new HttpClient())
{
//var requestUrl = $"https://graph.windows.net/me?api-version=1.6";
var requestUrl = $"https://graph.microsoft.com/v1.0/me/";
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = client.SendAsync(request).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
var user = JsonConvert.DeserializeObject<AdUser>(responseString);
return user;
}

Azure AD authentication with asp.net Identity for authorisation

I tried to look for all over internet but couldn't see how I can achieve what I was asked to. Here is my enterprise app which uses Asp.net Identity for form based authentication. I had extended User and Role along with Groups to provide authorization in my code. (note: not using any group/role directives).
Now I was asked to look at possibility of changing code to accommodate Azure Active Directory authentication. I tried reading on how you can register app, send user to Azure site for authentication, get back token etc. However I'm stuck at 'what-afterwards?' I have authenticated user How can I use my existing Asp.net Identity model where user was stored in sql database. How to use this token to relate the existing user.
Moreover, when I change my project to allow Azure AD, it removes Aspnet.Identity package as its not compatible with Azure AD !!
I even tried manually keeping both packages side by side, I got to point where user is sent to authenticate on Azure, diverted back to home page and again to login on Azure AD in never ending loop.
to summarize the question, How can I authenticate user from AAD and keep using existing Roles and groups authorization.
Edit:
I tried creating separate web service which will authenticate user and send JWT token. which works find if I call it directly on browser, however, when I tried to call this service from my web app I get weird error
Application with identifier 'a2d2---------------' was not found in the directory azurewebsites.net
Weird part here is name of directory is 'azurewebsites.net' and not the default directory I'm using.
Update
Here is code which throws error
public async Task<ActionResult> Login(string returnUrl)
{
try
{
// get the access token
AuthenticationContext authContext = new AuthenticationContext(authority, new TokenCache());
var clientCredential = new ClientCredential(clientId, password);
//Error on below line
AuthenticationResult result = await authContext.AcquireTokenAsync(resourceId, clientCredential);
// give it to the server to get a JWT
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
......
try this:
var client = new RestClient("https://login.microsoftonline.com/{tenant-
Id}/oauth2/v2.0/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "password");
request.AddParameter("application/x-www-form-urlencoded",
"grant_type=password&client_id={client-Id}&client_secret={client-
secret}&scope={scopeurl}&userName={username}&password={password}",
ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var json = response.Content;
var JSONObject = JObject.Parse(json);
var token = (string)JSONObject["access_token"];
I had a similar issue so I created an Office 365 owin security plugin. I shared the code on github. It's based on the katana project at codeplex.
You can find the source code at https://github.com/chadwjames/wakizashi.
You will need to register your application here. When registering the application set the call back uri to https://yourdomain/signin-office365
The Application ID is your Client Id and the Password is your Client Secret.
Once you have it registered you can modify the Startup.Auth.cs and add something like this to the ConfigureAuth method.
//setup office 365
var office365Options = new Office365AuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["ada:ClientId"],
ClientSecret = ConfigurationManager.AppSettings["ada:ClientSecret"],
Provider = new Office365AuthenticationProvider
{
OnAuthenticated = async context =>
{
await
Task.Run(
() => context.Identity.AddClaim(new Claim("Office365AccessToken", context.AccessToken)));
}
},
SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie
};
office365Options.Scope.Add("offline_access");
app.UseOffice365Authentication(office365Options);
When I have more time I hope to create a nuget package for this.

How to remove a users manager in AzureAD using Microsoft.Azure.ActiveDirectory.GraphClient

I'm using the Microsoft.Azure.ActiveDirectory.GraphClient (Version 2.1.0) to write an app for Azure AD user management. I'm able to set the Manager of a user but have no idea how to clear the field.
Unfortunately the sample project provided on GitHub do not contain this function either.
I managed to clear the "manager" field using the code below. It is not using the Microsoft.Azure.ActiveDirectory.GraphClient library but gets the job done.
var token = <get your adal token here>
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var url = "https://graph.windows.net/<tenant domain>/users/<userid>/$links/manager?api-version=1.6"
var resp = httpClient.DeleteAsync(url).Result;
if (!resp.IsSuccessStatusCode)
{
// log / throw exception etc.
}
You need to perform a DELETE HTTP request to https://graph.microsoft.com/v1.0/users/<user_email>/manager/$ref (make sure to replace the <user_email> in the URL.
A successful call will receive 204 response code and empty string as the response body.
This method is currently missing from the Microsoft Graph API docs but should be added in the future. (see here)
Also you should start using Microsoft Graph (graph.microsoft.com) instead of Azure AD Graph (graph.windows.net) as the latter is becoming obsolete. (See here)
//Assign and remove user's manager
// User.Manager = newUser as DirectoryObject;
User.Manager = null;

OneDrive API with C#, get authentication code programmatic

I have to write an application, no matter what language (c#, Java, shell, python ...) that can connect to OneDrive and then uploads file.
Following the OneDrive API I found that i need in one step to go to the browser (manually and to post a url that combines client_id and client_security to get an authentication code so i can connect my client with it to get the access token. (oAuth2 protocol)
I need to get the access_token pragmatically, i don't need any manual step to be involved.
I tried in c# to use the WebBrowser component to navigate to the url and to get the access token, I found that the browser stays in the same url and not getting the final url that includes the auth_code!
My code looks like:
// Initialize a new Client (without an Access/Refresh tokens
var client = new Client(options);
// Get the OAuth Request Url
var authRequestUrl = client.GetAuthorizationRequestUrl(new[] { Scope.Basic, Scope.Signin, Scope.SkyDrive, Scope.SkyDriveUpdate });
// TODO: Navigate to authRequestUrl using the browser, and retrieve the Authorization Code from the response
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.ScrollBarsEnabled = false;
wb.ScriptErrorsSuppressed = true;
wb.Navigate(authRequestUrl);
Console.WriteLine(wb.Version);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
wb.Document.InvokeScript("evt_Login_onload(event)");
Uri myUrl = wb.Url;
Anyone can help with fixing this, or maybe suggest other ideas please?
Thanks in Advance!
It looks like you're creating a Windows desktop app using C#. There's actually an example at https://msdn.microsoft.com/en-us/library/hh826529.aspx for using the WebBrowser class to get the authorization code, then the token, then make an API. In short, you'll first need to send a request to the following URL with your client_id and scopes.
https://login.live.com/oauth20_authorize.srf?client_id=YOUR_CLIENT_ID&scope=YOUR_SCOPE_STRING&response_type=code&redirect_uri=https://login.live.com/oauth20_desktop.srf
In the response, you'll get the authorization code which you'll need to use to send another request to with your client_id, client_secret, authorization code like the following.
https://login.live.com/oauth20_token.srf?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&redirect_uri=https://login.live.com/oauth20_desktop.srf&code=AUTHORIZATION_CODE&grant_type=authorization_code
When you finally receive the access token, you can make requests to the API using your access token similar to the following.
"https://apis.live.net/v5.0/me?access_token=ACCESS_TOKEN". The "me" can be changed to any other folder or directory.
I hope that helps.
dont u think the scope u provided are wrong, they should be wl.basic, wl.signin, and if ur using new onedrive api then it should be onedrive.readonly or onedrive.readwrite
if ur using liveconnect api for the purpose of using onedrive then scope should be wl.skydrive or wl.contacts_skydrive or wl.skydrive_update
depending upon ur uses (refer https://msdn.microsoft.com/en-us/library/hh243646.aspx)
and can u more elaborate how ur trying to get the access_token, from above it is quite confusing to me
Have you solved you issue?
Have you tried to use the LiveSDK to authenticate?
Have a look at my question there, it might help you :
Onedrive API vs LiveSDK
I have used the following code, after installing both the LiveSDK and the OneDrive SDK, and this does not require any login after the first authorization. However it "may" have to be a RT app (windows store or windows phone store)
var authClient = new LiveAuthClient();
var authResult = await authClient.LoginAsync(new string[] {
"wl.signin", "onedrive.readwrite", "onedrive.appfolder"});
if (authResult.Session == null)
throw new InvalidOperationException("You need to sign in and give consent to the app.");
var Connection = new ODConnection("https://api.onedrive.com/v1.0",
new MicrosoftAccountAuthenticationInfo() { TokenType = "Bearer",
AccessToken = odArgs.Session.AccessToken });
Toan-Nguyen's answer almost helps me. On the step 2 (when I should send a request with authorization code) I get the response with error "Public clients can't send client secret". This answer said it's neccessary to remove the attribute client_secret from url.

Categories