domaindrivendev / Swashbuckle.WebApi

Seamlessly adds a swagger to WebApi projects!
BSD 3-Clause "New" or "Revised" License
3.07k stars 677 forks source link

Authorization with Azure Active Directory, Help needed #671

Open RobDaPraia opened 8 years ago

RobDaPraia commented 8 years ago

I would like to enable Authorization with Azure Active Directory but I don't succeed and I'm looking for a working example.

I see the following in https://github.com/domaindrivendev/Swashbuckle/issues/647 but I could not reproduce it to a working example. Is there somebody who got this working and could help me to set this up with detailed steps?

Oleksandr-Tokmakov commented 8 years ago
  1. Register 'swagger' application on AD as web application
  2. Select 'swagger' application in application list and go to configure section
  3. Scroll down to 'permissions to other applications' and press 'Add application' button
  4. In appeared popup change filter setting 'SHOW' to 'All Apps' and press confirm on the right side
  5. Select your Web Api application and press confirm button
  6. Web Api application will be added to application list
  7. On right side of added web api find 'delegated permissions' dropdown and select 'Access {web api name}'
  8. Add reply URL - ' http://{your_swagger_url}/swagger/ui/o2c-html ' to reply URL list
  9. Click on the Manage manifest button in the command bar, and select Download manifest. Open the JSON application manifest file and set the “oauth2AllowImplicitFlow” value to “true”. By default, it is “false”.
  10. "oauth2AllowImplicitFlow": true,
  11. Save the updated JSON file and upload it by clicking the Manage manifest button in the command bar, selecting Upload manifest, browsing to your updated manifest file and then selecting it. Once uploaded, your Web API is now configured to use OAuth 2.0 Implicit Grant to authenticate users.
  12. Go to the 'keys' section and select required duration(currently available 1 or 2 years options) for new key
  13. Press save button in the bottom of the portal
  14. Copy new generated key from 'keys' section value and save it somewhere NOTICE key will appear ONLY when settings were saved and will be available while you stay on current page
  15. In the bottom of the portal click on 'VIEW ENDPOINTS' button and copy OAuth 2.0 Authorization Endpoint
  16. Open SwaggerConfig.cs file and find 'c.OAuth2("oauth2") ... ' line
  17. Find 'AuthorizationUrl' method parameter and copy-paste value from OAuth 2.0 Authorization Endpoint from azure
  18. Add new scope:
  19. .Scopes(scopes =>
  20. {
  21. scopes.Add("user_impersonation", "Access {app_name}");
  22. });
  23. Scroll down to EnableOAuth2Support method call and set method parameters:
  24. CLIENT ID value from swagger application configuration on azure portal as Client ID method parameter
  25. Generated key from step 10 to Client Secret method parameter
  26. Realm parameter - ' http://{swagger_url}/swagger/ui/o2c-html ' (in my case - http://localhost:54154/swagger/ui/o2c-html)
  27. appName parameter - ' Swagger '
  28. scopeSeparator - ' ' (whitespace)
  29. go to the Web Api application on azure portal to config section → scroll to single sign-on → copy APP ID URI and paste it to addition query parameter - ' new Dictionary<string, string> { { "resource", "{app_id_url}" } } ' (for example - new Dictionary<string, string> { { "resource", "https://{tenant_name}.onmicrosoft.com/{api_app_name}" } })
  30. Go to the Web Api application on azure portal to config section → scroll to single sign-on → copy APP ID URI
  31. Back to web api application on azure portal and scroll to the 'permissions to other application' in web api
  32. Ensure that 'Windows Azure Active Directory' has 'read directory data' permission checked in Application Permission dropdown and 'Read directory data' and 'Sign in and read user profile' permissions in 'Delegated Permissions' dropdown

I hope it will help.

RobDaPraia commented 8 years ago

Wow, impressive!

Thanks a lot, going to test it, will definitely help, see some steps I didn't know about.

Followed the steps, and it seems like the authentication works, the swagger button turns blue, and when I press the 'Try it out!" button I see the Curl adds Authorization bearer like:

curl -X GET --header 'Accept: application/json' --header 'Authorization: Bearer e..FUw' 'https://domain-aadwebapidemo.azurewebsites.net/api/Values'

However the response is

`{ "Message": "Authorization has been denied for this request." }

401

{ "pragma": "no-cache", "date": "Fri, 04 Mar 2016 10:16:50 GMT", "www-authenticate": "Bearer", "server": "Microsoft-IIS/8.0", "x-aspnet-version": "4.0.30319", "x-powered-by": "ASP.NET", "content-type": "application/json; charset=utf-8", "cache-control": "no-cache", "content-length": "61", "expires": "-1" }`

Another client demo page I created, not swagger, but Angular JavaScript with JS ADAL library works calling the same Web API Controller with oauth2.

Maybe you have some tips/ideas for me what could be wrong in my code or extra test steps. Might be difficult without knowing my code, but any help is appreciated

Oleksandr-Tokmakov commented 8 years ago

Ensure that you pass correct resource parameter in step 29. Resource it's id of application that you are going to call from swagger. On azure portal you can find it in your api application in APP ID URL textbox. Also check 2-7 steps.

RobDaPraia commented 8 years ago

Yes!

Works now, great, thanks a lot!!

I modified step 29 a little. Instead of placing the url as resource i used the Client ID Guid and now it works (the copied APP ID URL did not work)

var queryStringParams = new Dictionary<string, string> { { "resource", "{Wep_API_Client_ID_Guid}" } };

pratushbajpai commented 8 years ago

This is just great and immensely helpful.

Just one observation on above. "resource", "{Wep_API_Client_ID_Guid}" is not necessary the value on Azure AD configuration portal for the Web API tenant. It should be the value used by WebAPI server side code while using Azure AD Client. WindowsAzureActiveDirectoryBearerAuthenticationOptions.Audience or TokenValidationParameters.AllowedAudience

This value in API server code can be different from the ClientID or App Url.

iouri-s commented 8 years ago

I believe there is a missing step which is to uncomment the c.OperationFilter(); line in SwaggerConfig.cs and implement it as described here (scroll down to "Second, create the OperationFilter class").

This will make an on/off switch appear next to each operation that will start the auth flow.

pratushbajpai commented 8 years ago

I'd created a post on above based on the comments above and our learnings on this https://blogs.msdn.microsoft.com/pratushb/2016/04/28/enable-swagger-to-authenticate-against-azure-ad/

iouri-s commented 8 years ago

Typo on the first line: bought = brought.

From: pratushbajpai [mailto:notifications@github.com] Sent: Thursday, April 28, 2016 5:06 PM To: domaindrivendev/Swashbuckle Swashbuckle@noreply.github.com Cc: Iouri Simernitski iouris@microsoft.com; Manual manual@noreply.github.com Subject: Re: [domaindrivendev/Swashbuckle] Authorization with Azure Active Directory, Help needed (#671)

I'd created a post on above based on the comments above and our learnings on this https://blogs.msdn.microsoft.com/pratushb/2016/04/28/enable-swagger-to-authenticate-against-azure-ad/https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fblogs.msdn.microsoft.com%2fpratushb%2f2016%2f04%2f28%2fenable-swagger-to-authenticate-against-azure-ad%2f&data=01%7c01%7ciouris%40microsoft.com%7c9e5443397ca04190e06708d36fc20c4c%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=Co5WOY%2bzOZxcczcSh%2blAm8rIFFWrNn1wDcZVwnfAe1c%3d

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHubhttps://github.com/domaindrivendev/Swashbuckle/issues/671#issuecomment-215598098

pratushbajpai commented 8 years ago

Thanks!

On Thu, Apr 28, 2016 at 5:09 PM, iouri-s notifications@github.com wrote:

Typo on the first line: bought = brought.

From: pratushbajpai [mailto:notifications@github.com] Sent: Thursday, April 28, 2016 5:06 PM To: domaindrivendev/Swashbuckle Swashbuckle@noreply.github.com Cc: Iouri Simernitski iouris@microsoft.com; Manual < manual@noreply.github.com> Subject: Re: [domaindrivendev/Swashbuckle] Authorization with Azure Active Directory, Help needed (#671)

I'd created a post on above based on the comments above and our learnings on this https://blogs.msdn.microsoft.com/pratushb/2016/04/28/enable-swagger-to-authenticate-against-azure-ad/ < https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fblogs.msdn.microsoft.com%2fpratushb%2f2016%2f04%2f28%2fenable-swagger-to-authenticate-against-azure-ad%2f&data=01%7c01%7ciouris%40microsoft.com%7c9e5443397ca04190e06708d36fc20c4c%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=Co5WOY%2bzOZxcczcSh%2blAm8rIFFWrNn1wDcZVwnfAe1c%3d>

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub< https://github.com/domaindrivendev/Swashbuckle/issues/671#issuecomment-215598098>

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/domaindrivendev/Swashbuckle/issues/671#issuecomment-215598518

RobDaPraia commented 8 years ago

Thanks a lot for the blog post. I was so happy that Oleksandr-Tokmakov could explain in detail. I would never have solved this on my own, and I could not find instruction on the internet. Hope your blog post will help other developers as well

azurefunda commented 7 years ago

Hi All, I have followed exact same steps as mentioned, but upon clicking on the authorize button. i am redirected to a link that says " Sorry, but we're having trouble signing you in. We received a bad request. ". Can you please point me to what might be the issue here ? I have double checked all the mentioned steps and followed them correctly.

premchandpl commented 7 years ago

@Oleksandr-Tokmakov @RobDaPraia Thanks to both of you a lot. I have followed the steps and I am able to resolve my issue. As rob siad, I also have to use the client id instead of AppId uri for my web api to work in the swagger UI. Thanks a lot lot lot for the all the steps that has been mentioned. It was really helpful and I am bookmarking this github post

DavidStrickland0 commented 7 years ago

FYI: for anyone fighting this. These directions are outdated. There is no longer a SwaggerConfig.cs file Azure Portal no longer has a "View Endpoints" etc. Wish I could update the instructions but still trying to figure this out myself but thought Id mention what I've found so far.

Thomle commented 7 years ago

@DavidStrickland0 You can find the Enpoints in Azure Active Directory -> App Registrations -> Endpoints. You will find the Endpoints button in the top navigation bar, next to the New application registration button.

azurefunda commented 7 years ago

Any info on having the same thing working for Asp.Net Core ? We dont have swaggerconfig.cs over there..

premchandpl commented 7 years ago

@sachiniti2 We have successfully implemented swagger in Asp.Net Core. Let me know how can I help you on this one.

hollowdrutt commented 7 years ago

@sachiniti2

For asp.net core 2.0 you can still follow the instructions in https://github.com/domaindrivendev/Swashbuckle/issues/671#issuecomment-192141472 and https://blogs.msdn.microsoft.com/pratushb/2016/04/28/enable-swagger-to-authenticate-against-azure-ad/

Instead of configuring swagger in SwaggerConfig.cs you can do it in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddSwaggerGen(options =>
    {
        options.DescribeAllEnumsAsStrings();
        options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
        {
            Title = "HTTP API",
            Version = "v1",
            Description = "The Service HTTP API",
            TermsOfService = "Terms Of Service"
        });
        options.AddSecurityDefinition("oauth2", new OAuth2Scheme
        {
            Type = "oauth2",
            Flow = "implicit",
            AuthorizationUrl = "https://login.microsoftonline.com/{azuread_tenantid}/oauth2/authorize",
            Scopes = new Dictionary<string, string>()
            {
                { "user_impersonation", "Access {swaggerAppName}" }
            }
        });
        options.OperationFilter<AssignOAuth2SecurityRequirements>();
    }
    ...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    ...
    var stringDict = new Dictionary<string, string>();
    stringDict.Add("resource", "https://{tenant_name}.onmicrosoft.com/{api_app_name}");
    app.UseSwagger()
                .UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
                    c.ConfigureOAuth2("{swaggerApplicationId}", "{swaggerKey}", "https://{swagger_url}/swagger/ui/o2c-html", "{swaggerAppName}"," ", stringDict);
                });
   ...
}

Instead of AssignOAuth2SecurityRequirements from the tutorial you could use https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs

Erw1n commented 6 years ago

@hollowdrutt Any idea on why it could be that the 'resource' value from stringDict isn't being sent when authenticating?

joaopgrassi commented 6 years ago

I cannot thank you enough! I was trying this for weeks without solving it. Also helped me to make it work with my Angular 2+ Spa. Plus it works on ADFS on premises.

vbullinger commented 6 years ago

Any update to this? All of the documentation is very outdated and can't be followed.

domaindrivendev commented 6 years ago

Are you referring to the documentation in

domaindrivendev commented 6 years ago

Are you referring to the documentation in general or specifically OAuth integration with Azure? If it’s the former, then why not contribute, create a PR to enhance the docs (it is FOSS after all)? If it’s the latter then I would argue it’s outside the scope of this specific project, which is to generate Swagger descriptions for APIs directly from the routes, action signatures and models in your code

domaindrivendev commented 6 years ago

A blog post would be perfect for the latter

vbullinger commented 6 years ago

The latter: the documentation of, for example, Oleksandr's seemingly great answer. None of that exists in the state that he posted it in, yet others seemed to think it was perfect.

Oleksandr-Tokmakov commented 6 years ago

I'm glad that my guide was helpful but I haven't been working with AAD and swagger since that times. So I can't help you. But I will try to find some time to refresh my knowledge and write a blog post.

darewreck54 commented 6 years ago

@hollowdrutt What do you do in the case where the swagger and the web api are the same service. In this case, swagger is signing in to itself and I think you can only use set the resource to it's client id. The APP ID Url will produce a "invalid_request" error.

If you set the client id as the resource, the token that is produce won't work for the web api which has the jwtaudience configured with the app ID URL.

Anyone experience this issue? Thanks, Derek

bkwdesign commented 6 years ago

@darewreck54 - the above works for me, even if Swagger UI is being served from the same app service node where the Web API is hosted. In all cases, it's important you create 2 app registrations in Azure AD: one for the "client" (Swagger), and one for the "protected resource" (Web API)

bkwdesign commented 6 years ago

@vbullinger - one of the main things that has changed, is that the 'classic AD management portal' referred to in @pratushbajpai's article, has been shut down and now everything can be done in portal.azure.com

I used to have everything working. Now I'm revisiting this for another OAuth / API project.. but.. am not quite getting everything aligned correctly this time around. Will post back here if I figure everything out.

darewreck54 commented 6 years ago

In my case there is only one aad. The swagger client and the web api are the same app service and uses the same aad id. Why would you create two in this case. You are just signing into yourself. That is the main difference why it’s working for you since the issue is related to signing in as yourself

On Mar 9, 2018, at 8:09 AM, Brian notifications@github.com<mailto:notifications@github.com> wrote:

@darewreck54https://github.com/darewreck54 - the above works for me, even if Swagger UI is being served from the same app service node where the Web API is hosted. In all cases, it's important you create 2 app registrations in Azure AD: one for the "client" (Swagger), and one for the "protected resource" (Web API)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/domaindrivendev/Swashbuckle/issues/671#issuecomment-371857525, or mute the threadhttps://github.com/notifications/unsubscribe-auth/APbCzny487KWLuFI4_LWsqLGvDhJpxIYks5tcqlFgaJpZM4HodzT.

ssanket commented 5 years ago

In my case I had to update reply url to 'https://{your swagger host}/swagger/oauth2-redirect.html', everything else in the instructions still applies and works great!