I am trying to implement Authentication in our website using the Azure AD, following the below reference. Our website uses the below stack ASP.NET, MVC5 hosted on IIS. basically use OpenId Connect protocol for website authentication and use oAuth2.0 protocol for delegated access to use the token for Authorization.
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
Getting token from the Azure AD logic is there in the Startup.Auth.cs class, which is invoked from the OwinStartup class.
When I implement this in our site, Startup.Auth.cs ConfigureAuth is executed only once during the APP start and as per the above reference.
Decorating the controller classes with the [Authorize] or adding the SignIn() with check if the request is authenticated or not and call the Authenticate code again.
public void SignIn()
{
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
The issue is that The SignIn() method is not getting in our application and also curious on what the [Authorize] attributes does?
I highly appreciate any insight on these. Thanks much in advance.
ACS does not support OpenId Connect and is no longer being developed - hence the first part of the answer would be - what you are trying to do is not supported.
That said, are you certain you are referring to ACS? That sample refers to Azure AD, which is a different offering.
For the rest of the answer I will assume that you do refer to Azure AD.
From your description I am not understand what is the problem you are experiencing. ConfigureAuth only needs to be executed once to do its job, which is adding to the request processing pipeline the modules (middleware) responsible for handling authentication. I am not sure to what code you are referring to with "Authenticate". There should be no such call here - when you request a route decorated with [authorize], ASP.NET will enforce that the caller is authenticated; if it isn't, as it is the case for the first request, this causes the opened connect middleware to generate a sign in request. The Signin() method does pretty much the same the same, but without having to attempt access to a resource marked with [authorize].
Don't use [Authorize] attribute with the controllers if you have explicit SignIn() action.
You might be messing up with authentication cookie and Session variable.
Check this link
for details.
Related
I need some help with Azure API Management service.
At the moment we have a SinglePage App which is using two Backend Services (WebApi .Net Core) hosted on Azure. To Authenticate and Authrize user we are using IdentityServer (also hosted on Azure as a service) + SubscriptionService. Here IdSrv is authenticating the user and it also defines to which APIs the webapp has access. The SubscriptionService has information if the user has rights to given APIs. More or less like that.
So the flow is:
WebApp -> redirect to IdSrv endpoint -> login -> back to UI -> ask backend with user credentials (token)
Now, we want to add Azure API Management to the mix and I am struggling how to do that...
Initially we were thinking that we can hide everything including the IdentityServer behind API Management gateway, but looks like this doesn't make sense or is impossible. I found this as a helpfull reference: Generate Access Token and validate against IdentityServer4 through Azure API Management in which the second answer is quite important remark.
Based on that I think that I need to leave the Client to use IdentityServer to authenticate as this requires UI interaction but then somehow set a global policy in API Management to authorize the user using mentioned Send-Request policy. And then change backend to accept the JWT tokens from this policy? Is my thinking correct? How to implement that?
Or I should just pass the authorization-header from client request through API Management?
All those things are new for me so it could be that I missed something or messed up the terms...
The way you integrate APIM into picture may depend on goals you want to achieve with APIM. You could hide IdSrv behind APIM since there is Client credentials flow that would allow APIM to authenticate/authorize itself to an API, or you could have user authorize APIM once via Auth code grant and then store refresh tokens and use them to talk to an API. But I'm not sure that would be best since it quite a bit changes you system and forces you to solve other problems instead, like how to authenticate user to APIM. In some cases this may be a good approach, it's up to you to decide.
If you're fine with keeping IdSrv facing user, then we have APIM receiving a token with every request. You could then have a global/API policy in APIM that would send token received from user to SUbscriptionService to check user authorization to make a call) can do that with send-request policy), and either let the call pass or deny. This approach is most useful if you want to use different auth mechanism between APIM and backend, because if APIM is doing authorization work, your backend could avoid checking any user access, and instead just authorize APIM to do everything.
Check out this sample on how to authorize requests using external service: https://learn.microsoft.com/en-us/azure/api-management/policies/authorize-request-using-external-authorizer
it is quite late from asking this question but here I described how we have done that. We cover UI clients and Device clients with SSL Certification auth on APIM. In short words:
UI Client is being redirected to ID Server Loging page
APIM is doing Token validation with ID Server
APIM is doing SSL Certification verification in DB and returning back token like data for devices to pass some "device account" information.
More details can be found here:
Can anybody help me?
I built a Jhipster monolithyc app using Security based on Keycloak. This keycloak access to my corporative ldap and all works perfect. When somebody wants a page it redirects to http://localhost:8080/login and it redirect to keycloak to sing in, it returns to http://localhost:8080/login and it gets the token of the login user, so the user can access base on his role-user permissions.
Now, we want to expose the api to third party companies so as to reuse the bussiness logic of my app. (we can do it with web services but we want to expose our restful api). They have their own applications (desktop, web, etc) and we want to expose our api so they can communicate with us with the same securicy policies. they have users in our ldap. can anybody tell me which is the best way to expose it with user-role permissions.
One way is that they can send us their login information (user, password). We know it is not the best way , but we dont know how to do it other way. Does anybody know how to login with keycloak based on this user login. We enabled direct conecction and we are able to get the Keycloak access token with password flow. But, if we do this way, how can we convert this token in a OAuth2Authentication object so we can generate JSESSIONID to make the calls to the api?
We disabled csrf to make this possible.
Any ideas?
Thanks in advance
After a few days research, I reached a solution.
Here is the code:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Bean("resourceServerRequestMatcher")
public RequestMatcher resources() {
return new AntPathRequestMatcher("/external-access/**");
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.requestMatcher(resources()).authorizeRequests()
.anyRequest().authenticated();
}
}
This way I have both WebSecurity based on Keycloak and password flow base Resource. For this solution, the api I want to expose has both /api /external-api mappings, first for web navigation and the other for direct access. To access via the second way you have to call first keycloak to get a token and then access /external-api with that token.
Perhaps there is a better solution (client credentials), but i need the login user to resuse my endpoints.
Azure AD B2C with UWP sample on GitHub requires some optional steps as described on the GitHub readme which asks for us to create a web API in step 4 and hence use API scopes for that web API in the code written in app.xaml.cs
public static string[] ApiScopes = { "https://fabrikamb2c.onmicrosoft.com/demoapi/demo.read" };
Problem : I don't have a backend API for my project yet and I don't want to make a traditional web API for my project, I will be using Azure Functions for a serverless API.
But the Sign In button leads to getting authenticationToken with following method:
authResult = await App.PublicClientApp.AcquireTokenAsync(App.ApiScopes, GetUserByPolicy(App.PublicClientApp.Users, App.PolicySignUpSignIn), UIBehavior.SelectAccount, string.Empty, null, App.Authority);
As you can see above that App.ApiScopes are provided here which is a must parameter in this method, if I provide a list of string[] with an empty string only here, I am able to login but I don't see any token in the output in my UWP UI.
So how can I bypass this API scope problem and have a working sample for myself, or do I have to create a web API for some kind of security reason I mean is that a mandatory part?
You can use your app's client_id as the scope in order to get a token issued to itself.
This approach is fine if you want to tightly couple your client and API, however if you end up having multiple Azure functions, multiple clients and don't want all clients to be able to call all functions, you'll need to start splitting up their app registrations and define scopes accordingly.
I have created a Xamarin.Forms project and a Table API project. Both have been created through the QuickStart menu in Azure Portal.
I have configured an Azure AD in my portal and I can successfully retrieve a token from the AD through my XForms app. But when I try to login to the Table API using the LoginAsync method from the MobileServiceClient, I receive a "You do not have permission to view til directory or page."
I have been looking through the following guides but with no luck.
How to configure your App Service application to use Azure Active Directory login
Add authentication to your Xamarin.Forms app
How to: Work with authentication
I have also look at the following question but didn't find a solution.
Cordova AAD server flow authentication hangs on Android and iOS
I Am thinking that I might be missing some specific authentication on the Table API project?
Here is my code and setups:
PCL PROJECT IN XFORMS
var ar = await authContext.AcquireTokenAsync(Constants.GraphResourceUri, Constants.ClientId, userCredintials);
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
var client = new MobileServiceClient(Constants.ApplicationUrl);
var user = await client.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
The Constants.ClientID is the ClientId of the Native Client app and not the webserver. If I switch it around I get a 404.
EXAMPLE OF CONTROLLER FROM TABLE API PROJECT
[Authorize]
public class StatisticController : ApiController
TABLE API StartUp.cs CONFIGURATION
public void Configuration(IAppBuilder app)
{
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions());
ConfigureMobileApp(app);
}
MOBILE SERVICE AUTH SETUP
SINGLE SING-ON AD SETTINGS
NATIVE CLIENT APP SETTINGS
EDIT
I can duplicate the error through PostMan with the following setup:
I tried to include a "X-ZUMO-AUTH" header with the value of the access_token but with the same result. Still no permission. I also tried to exclude every header in the POST request but with no changes. Does this mean that POST requests from my mobile app or Postmand is not allowed?
If I manually browse to mysite.azurewebsites.net/.auth/login/aad in a browser, then I can log in with the users from my AD. So it seems that the AD is communicating correctly with the service and vise versa.
FIXED IT
Great thanks to mattchenderson! As he suggests I should change the constant GraphResourceUri to the client id of my service instead of the normal graph api. Along with adding a single instance of the client I can now successfully log in to my service.
POST requests are allowed, and I use Postman all the time for testing.
The most common cause of an issue like this is an audience validation issue. The audience is a property of the AAD token which says for what resource is this token valid. Given the code above, I would expect the audience to be equal to Constants.GraphResourceUri. My guess is that this is actually the graph API, and not your application, and that would cause a validation failure, although I would expect it to happen when you call LoginAsync(). I would suggest trying the web application client ID instead (that's the Client ID from the "MOBILE SERVICE AUTH SETUP" screenshot).
For an easier time debugging, you can take your AAD token to something like http://jwt.io, and that will help you see the token properties. "aud" is expected to the same as the client ID of the application as registered in the portal, and you want the issuer fields to match up as well. Make sure the token is not expired either.
When using the token to access protected APIs, there are two ways to provide it:
Use the token returned as part of LoginAsync() in the X-ZUMO-AUTH header of your request. This will automatically be done by the SDK for table operations using the same MobileServiceClient.
Use the AAD token directly according to the bearer token spec. That is, include it in the Authorization header, with the value "Bearer ", replacing token with your value.
Also, I see in your code that you are creating a new MobileServiceClient for the login operation. This is something we generally discourage, as the login information is attached to the MobileServiceClient object. If you lose a reference to that, you lose the login information (and a few other settings), and they won't be applied to your table operations. The recommendation is to use a single instance that is referenced elsewhere - for example, in Xamarin, a static variable within your shared code.
During the recent Microsoft Cloud roadshow in London, something that came out of one of the talks on App Service was using AAD B2C for authentication.
It is possible currently to add Azure AD as an authentication for an API App:
Calling this API app from a browser based web app with no authorization header results in a 302 redirect immediately followed by a 401 response.
It was mentioned at the cloud event that it would be possible to call an API app anonymously from a web app, and have the azure App service handle the redirection to the AAD login page, get the token on successful login and then pass the call on to the API app and return the data.
However, I am struggling to see how this can be achieved without any responsibility on the calling web app to handle the redirect. Normally you would handle a 401 response from an API by obtaining a bearer token via AAD on the client side and sending it through as the authorisation header with the api request.
I have been through numerous examples on the Azure site and others and all of them are handling the logon/obtaining the token in the client web app.
Is this even possible?
UPDATE I just realized (as pointed out by #Darrel-Miller that you don't really want to allow the user to put the credentials in.
The only thing that is still unclear to me, is where do you want to provide the credentials for AAD?, What is it exactly what you would like to accomplish.
Even more, why would you use AAD if there no user interaction at all.
If all that you want is a secure connection you can just use the standard application key for the web api without enabling AAD. And its as pretty straight forward to just add the MS_ApplicationKey to your header and you are good to go.
As you described in your comment you have a webclient that tries to do the requests and gets the 302, that is why my original answer wast that you would use ADAL. But now that I get deeper into what you want probably what you want to use is KurveJS :
https://github.com/MicrosoftDX/kurvejs
And it has the AAD app model v2 with Active Directoy B2C.
This makes it easy to add third party identity providers such as Facebook and signup/signin/profile edit experiences using AD B2C policies
You can read more about it here:
https://github.com/MicrosoftDX/kurvejs/blob/master/docs/B2C/intro.md
Do you mean this??
https://msdn.microsoft.com/en-us/magazine/dn463788.aspx
Just use ADAL nuget package to handle the call...
You can read this from the post:
As soon as the execution hits the call to AcquireToken, you’ll get the authentication dialog shown in Figure 8. ADAL takes care of contacting the right endpoint and rendering the authentication experience provided by the server in a pop-up dialog without requiring you to write any UI code.
I hope this works for you!