To authenticate with AzureAD I put the folling Code in an Console Application
private static async Task<string> GetAuthTokenAsync(string tendent,string AppIdUri , string ClientID)
{
/*
<add key="ida:Audience" value="https://mehler.ws/ToDoWebApi" />
<add key="ida:ClientID" value="f0e91727-3edd-4b00-9630-591166a74e4b" />
*/
var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tendent));
AuthenticationResult result = authContext.AcquireToken(AppIdUri, ClientID , new Uri(Settings.Default.WebApiReplyAdress));
return result.CreateAuthorizationHeader();
}
the Method AcquireToken Shows a Screen where I am asked to Input my Credentials.
I accidently selected the Account I log in with in Windows 10. Now the Screen doesn't show up any more an the application uses my Windows 10 Account automatically. Does anyone know how to fix this Problem, so that the Screen shows up again?
Token's are cached to alleviate complexity in your app. You will need to clear the token cache if you want the user to log back in... typically you would setup a logout function.
More information on token cache: http://www.cloudidentity.com/blog/2013/10/01/getting-acquainted-with-adals-token-cache/
How to logout:
authContext.TokenCache.Clear();
string requestUrl = "https://login.microsoftonline.com/{0}/oauth2/logout?post_logout_redirect_uri={1}";
Task.Run(async () =>
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
var response = await client.SendAsync(request);
});
{0} - Fully qualified name of your Azure Active Directory e.g.
yourad.onmicrosoft.com or tenant id.
{1} - The URL of your application where a user must be redirected
back after the logout is complete. This should be properly URL
encoded.
An easy way is to pass to AcquireToken PromptBehavior.Always, there's an overload for that. That will cause ADAL to ignore the cache and will ask the service for a clean prompt
I found a very simple Solution myself to once clear the Cache.
Delete Cookies in Internet Explorer / Edge ;-)
Thanks anyway for the Answers hot to implement proper Logout Code and Force Prompt for Login allways.
Related
Is it possible to get a 3-legged auth without user input ?
https://aps.autodesk.com/en/docs/oauth/v2/tutorials/get-3-legged-token/
I have the below code which triggers the web browser to ask for login and press "allow"
button.
I can't run autoamted tasks like this, is there a way to call the API in adeffrent way
in order to pass my credentials and get authorised programmatically ??
public async Task<string> GetCode()
{
var requesturl = $"https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id={client_id}&redirect_uri={redirecturl}&scope=data:create%20data:read%20data:write";
Process.Start(new ProcessStartInfo(requesturl) { UseShellExecute = true });
listener = new HttpListener();
listener.Prefixes.Add(url);
listener.Start();
Console.WriteLine("Listening for connections on {0}", url);
// Handle requests
Task<string> listenTask = HandleIncomingConnections();
this.code = listenTask.Result;
GetToken();
// Close the listener
listener.Close();
return code;
}
In order to access private user data you need the permission of the user to access it. The way you request permission is with the oauth2 consent screen this is standard part of Oauth2.
So no you cant automate that. AutoDesk-forgue does return a refresh token as part of its oauth2 flow.
What you can do is request authorization once store your refresh token and use the refresh token to request a new access token whenever you need to access the api again.
In this way your automation will run just fine without you.
I'm currently building a Xamarin app that uses WebAuthenticator to handle all authentication purposes. After calling AuthenticateAsync, the client is taken to an auth provider to login using their credentials. However, their system uses something called DUO, an app for different two-factor authentication methods. So when they use this it opens another app and puts the original client in the foreground. The problem arises right when the client is redirected back to the app. The access token is never passed. I also noticed this same issue when the client opens a different app. Is there a way to persist the authURI when it's put in foreground?
This is the current implementation for the call to the AuthenticateAsync
try
{
var authResult = await Device.InvokeOnMainThreadAsync(async () =>
{
var authUrl = BuildAuthUrl();
var redirect = new Uri(Redirect);
return await WebAuthenticator.AuthenticateAsync(url: BuildAuthUrl(), callbackUrl: new Uri(Redirect));
});
string code = authResult.Properties["code"];
var token = await GetToken(code);
I created an asp.net webform application using ADFS. Sign in and sign out work perfectly using the default method that comes with the template.
Eg of signout button method that is included in the template
protected void Unnamed_LoggingOut(object sender, LoginCancelEventArgs e)
{
// Redirect to ~/Account/SignOut after signing out.
string callbackUrl = Request.Url.GetLeftPart(UriPartial.Authority) + Response.ApplyAppPathModifier("~/Account/SignOut");
HttpContext.Current.GetOwinContext().Authentication.SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
WsFederationAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType);
}
I have set up a timer and upon reaching zero I tried using the above code to log the user out but it doesn't work.No error thrown.
Any suggestion how to perform logout here?
What worked for me is to upon timeout to call the click event of a hidden button which in turn causes the below code to run.
// Redirect to ~/Account/SignOut after signing out.
string callbackUrl = Request.Url.GetLeftPart(UriPartial.Authority) + Response.ApplyAppPathModifier("~/Account/SignOut");
HttpContext.Current.GetOwinContext().Authentication.SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
WsFederationAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType);
ADFS is the server that is responsible for authenticating the user and for managing the user session. The website/form is just using this service. It makes sense that a site that uses this service cannot have full control over it. It would make more sense to me to log out the user from the ADFS server and have that server do the heavy lifting for you.
Note the ADFS server keeps a user logged in into ADFS server, and note that when a user requests access to a resource this manifests in an access_token. They are different things. Typically when signing somebody out with a product like identity server, in order to log out you’ll need to do two things:
Revoke the access token
Log out on the authentication server, (if
that is desired, one could argue that isn’t desirable)
Note the explicit difference between session and token. You’ll notice these concepts are also in ADFS. After a quick google search you’ll find the difference between WebSSOLifetime and TokenLifetime. I would suggest configuring those to invalidate the tokens and sessions, and thereby logging the user out after an x amount of minutes.
Hope this helps.
Have you tried the above code that you have posted directly without the timer? and did it work?
Also, Try implementing the below code and see if it works.
public void LogOut()
{
var module = FederatedAuthentication.WSFederationAuthenticationModule;
module.SignOut(false);
var request = new SignOutRequestMessage(new Uri(module.Issuer), module.Realm);
Response.Redirect(request.WriteQueryString());
}
I'm currently setting up a new project with a Web API and a MVC UI (will eventually have a mobile UI as well which can talk to the same API).
So, I have the following plan:
User navigates to the MVC UI which takes them off to the IdentityServer4 server to log in or sign up
IdentityServer user is then added to the applications own user table in the database
Permissions can then be set on the user to limit their access
This means the identity server is just that, an identity server (and means I allow people to log in through Google, etc. without worrying about their roles and permissions).
So, to achieve the above, I need to check the user's permission on the API, NOT on the client (the client could be anything - web, phone app, JavaScript client, etc. so we can't rely on that to handle user permissions).
On the API, I have implemented a Permissionhandler and PermissionRequirement authorization policy. So, on the API controller or method, I can do something like: [Authorize(Policy = "CreateUser")]. It looks like I'll need to have a policy per system permission.
So in the authorisation handler I need to:
Get the current user's username
If they exist in the app database, check their permissions and auth or deny
If they don't exist in the app database, add them, then we can set their permissions later from the admin panel
This was going well up until I tried to request the user's username from the identity server. I understand I need to use the UserInfoClient to do that, but I can't figure out how to use the user's token/credentials to get their claims from the identity server or to at least get their User.Identity.Name.
Now I could just use the sub ID to add the user to the application database, but then whoever's managing the permissions would have no idea who that person is, so I need to use their email really.
Now in the MVC client, I can see User.Identity.Name without any problems, but in the API that value is null!?
So my question is: how on earth do I get the current user's Identity.Name, username or email from within the API?
Thanks.
Think I've cracked it now.
var mvcContext = context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext;
if (mvcContext != null)
{
// Use the UserInfo endpoint to get the user's claims
var discoveryClient = new DiscoveryClient("http://localhost:5000");
var doc = await discoveryClient.GetAsync();
var accessToken = await mvcContext.HttpContext.Authentication.GetTokenAsync("access_token");
var userInfoClient = new UserInfoClient(doc.UserInfoEndpoint);
var response = await userInfoClient.GetAsync(accessToken);
var claims = response.Claims;
}
This is detailed right at the bottom of https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies so according to Microsoft, it's the right way.
You did however spark this idea, thank you Win. I had been staring at this bloody thing for hours. All you need sometimes is someone else to say something, anything, and the curse is broken! :)
I am still open to a better way of achieving this, if anyone has one.
Cheers
I believe you already configure IdentityServerAuthentication in Web API similar like this -
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://UrlOfIentityServer",
RequireHttpsMetadata = false,
ApiName = "exampleapi"
});
...
}
When you make a web service call, you will need to pass the same token received from IdentityServer like this -
using (var httpClient = new HttpClient())
{
string accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
httpClient.BaseAddress = new Uri("http://UrlOfWebAPI");
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return await httpClient.GetStringAsync("api/clock/time");
}
Basically what I'm trying to do is to get recent tweets from a user and do stuff with them. I'm using Tweetinvi with PIN-based authentication, as described on the website, like this:
// Create a new set of credentials for the application
var appCredentials = new TwitterCredentials("CONSUMER_KEY", "CONSUMER_SECRET");
// Go to the URL so that Twitter authenticates the user and gives him a PIN code
var url = CredentialsCreator.GetAuthorizationURL(appCredentials);
// This line is an example, on how to make the user go on the URL
Process.Start(url);
// Ask the user to enter the pin code given by Twitter
var pinCode = Console.ReadLine();
// With this pin code it is now possible to get the credentials back from Twitter
var userCredentials = CredentialsCreator.GetCredentialsFromVerifierCode(pinCode, appCredentials);
// Use the user credentials in your application
Auth.SetCredentials(userCredentials);
Now the problem is that I have to sign in and connect to Twitter every time I launch my application via browser, which is mildly annoying. I've tried to save my authentication details in a text file (Consumer Key, Consumer Secret, Access Token, Access Token Secret), and then just insert the info into appCredentials and userCredentials, but with no results, as I keep getting TwitterNullCredentialsException. So how do I save my credentials so that I don't have to reconnect on every launch?
I am the main developer of Tweetinvi.
If you store the 4 credentials information you can then reuse them with 2 different solutions :
Auth.SetUserCredentials("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET");
// OR
var creds = new TwitterCredentials("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET");
Auth.SetCredentials(creds);
The documentation might help you set up your application : https://github.com/linvi/tweetinvi/wiki/Introduction