-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug] Redirect URI is set to http instead of https when deploying to Azure App Service for Docker container (Linux) #115
Comments
I'm seeing the same behavior using example 1-1, deployed to a regular Azure App Service (not docker). Reply urls in azure are set to https, "domain" in the appsettings.json is set to https, but when I try to use the login mechanism, it's passing http as my reply url. Works fine in localhost while debugging. |
@BurritoSmith : did you add the right redirect URIs (with https:) in the app registration for your application? |
Spec(updated on 07/05/2020) Why?In order to avoid customers to have to update the redirect URI in the code when they deploy their Web apps, the redirect URI is computed automatically by ASP.NET Core (part of the auth code flow), and also by Microsoft.Identity.Web (in Note that this does not prevent developers to add redirect URI in the app registration portal, but this allow them to have the same code for debugging locally and for deployed applications if they wish to. The MSAL.NET part is here: microsoft-identity-web/src/Microsoft.Identity.Web/TokenAcquisition.cs Lines 334 to 338 in c2f81fd
Although this solves many cases, there are cases (like working in containers, or with reverse proxys), where this is not flexible enough The openIDConnect redirect URI is computed by ASP.NET Core, but can be overriden by subscribing to the OpenIdConnect Same problem for the post logout redirect URI used in global sign-out. It needs to be overridable, and that can be done but subscribing to the What?Given the following config "CallbackPath": "/signin-oidc",
"SignedOutCallbackPath ": "/signout-callback-oidc", The proposal is to add new properties in
Given the following config // "CallbackPath": "/signin-oidc",
// "SignedOutCallbackPath ": "/signout-callback-oidc",
"RedirectUri ": "http://mywebapp.mycompany.com/signin-oidc",
"PostLogoutRedirectUri": "http://mywebapp.mycompany.com/signout-callback-oidc",
microsoft-identity-web/src/Microsoft.Identity.Web/WebAppAuthenticationBuilderExtensions.cs Lines 62 to 68 in 2739123
In the var redirectToIdpHandler = options.Events.OnRedirectToIdentityProvider;
options.Events.OnRedirectToIdentityProvider = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpHandler(context);
// Override the redirect URI to be what you want
if(microsoftIdentityOptions.RedirectUri != null)
{
context.ProtocolMessage.RedirectUri = (microsoftIdentityOptions.RedirectUri;
}
};
var redirectToIdpForSignOutHandler = options.Events.OnRedirectToIdentityProviderForSignOut;
options.Events.OnRedirectToIdentityProviderForSignOut = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpForSignOutHandler(context);
// Override the redirect URI to be what you want
if (microsoftIdentityOptions.PostLogoutRedirectUri )
{
context.ProtocolMessage.PostLogoutRedirectUri = microsoftIdentityOptions.PostLogoutRedirectUri;
}
};
}); __ |
@jmprieur yes, the redirect URIs in the app registration are set to https. I actually mis-informed you yesterday when I said my app was hosted on azure (it was late in the day and I was tired and confused about which particular one this was....). This particular app is an internal one that is hosted behind a load balancer. The nodes host the application on http using ports to separate each application in IIS but the load balancer accepts https traffic then forwards that on to the nodes over http. So in this model the nodes seem to be checking themselves and determining that they are being hosted over http and therefore changing the reply url that gets passed up accordingly. I haven't sniffed the traffic out, but it's possible that in the flow, they're actually passing the machine name that's hosting them rather than the host.domain name we're using to reach our LB. IE http://mymachinename:44200 instead of https://myhost.mydomain.com. I have seen a few different errors from the MS login about mismatched reply URLs when the machine names are not included. In any case, being able to override the behavior you described above would be a must for our situation. We can not rely on our machines accurately obtaining a computed return URL. I assumed that it was using the "domain" property in the JSON config as the reply url. To me, you could use that in conjuction with the signin-oidc, or just add another property in the json config for us to manipulate what the reply url should be. |
Thanks for the explanation @BurritoSmith . yes, we would use the CallbackPath JSON property:
|
So am I understanding it correct that the property will be set to the following?
That would be perfect for me, and also having the possibility to not specify the full path for local development. |
I had a little bit of time this morning to play around with trying to manually add the return URI into the process. I was working with the file you mention above @jmprieur (microsoft-identity-web/src/Microsoft.Identity.Web/TokenAcquisition.cs) and wasn't able to get it to inject my return URI into the MS Login GET request with the querystring parameter set to my manual override. There is obviously something else going on deeper in the plumbing that I didn't dig into. Just for the heck of it, I also tried updating the CallbackPath property now to an absolute URI and that did not work (as I wouldn't expect it to since this hasn't been implemented in my current version) but it did throw an exception as it was not able to be parsed. Please let us know when you've implemented your suggested changes so I can come back to this in my project. For now, I've had to roll back to an older version of our OpenID authentication process. thanks so much. |
@BurritoSmith, we have prioritized fixing this issue (cc: @jennyf19) public void ConfigureServices(IServiceCollection services)
{
services.AddSignIn(Configuration);
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme,
options => {
var redirectToIdpHandler = options.Events.OnRedirectToIdentityProvider;
options.Events.OnRedirectToIdentityProvider = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpHandler(context);
// Override the redirect URI to be what you want
context.ProtocolMessage.RedirectUri = "your redirect URI";
};
});
// More code here ...
} |
I tested this solution, and it works for sign-in 👍 The sign-out redirect URI (post_logout_redirect_uri) is still http though. You can test the app at https://demoopenid.azurewebsites.net/. |
@mochr : thanks for confirming. Updating the code snippet: public void ConfigureServices(IServiceCollection services)
{
services.AddSignIn(Configuration);
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme,
options => {
var redirectToIdpHandler = options.Events.OnRedirectToIdentityProvider;
options.Events.OnRedirectToIdentityProvider = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpHandler(context);
// Override the redirect URI to be what you want
context.ProtocolMessage.RedirectUri = "your redirect URI";
context.ProtocolMessage.PostLogoutRedirectUri = "your post logout URI";
};
});
// More code here ...
} |
Thanks for the suggestion! I tested it and found that I needed to add the post logout URI to the https://demoopenid.azurewebsites.net/ has been updated with the code below. public void ConfigureServices(IServiceCollection services)
{
services.AddSignIn(Configuration);
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme,
options => {
var redirectToIdpHandler = options.Events.OnRedirectToIdentityProvider;
options.Events.OnRedirectToIdentityProvider = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpHandler(context);
// Override the redirect URI to be what you want
if(Configuration["AzureAd:WebAppURI"] != null)
{
context.ProtocolMessage.RedirectUri = Configuration["AzureAd:WebAppURI"] + Configuration["AzureAd:CallbackPath"];
}
};
var redirectToIdpForSignOutHandler = options.Events.OnRedirectToIdentityProviderForSignOut;
options.Events.OnRedirectToIdentityProviderForSignOut = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpForSignOutHandler(context);
// Override the redirect URI to be what you want
if (Configuration["AzureAd:WebAppURI"] != null)
{
context.ProtocolMessage.PostLogoutRedirectUri = Configuration["AzureAd:WebAppURI"] + Configuration["AzureAd:SignedOutCallbackPath"];
}
};
});
// More code here ...
} |
@jmprieur @jennyf19 I can confirm your suggested additions to the startup.cs file are also working in my above described environment. I agree with @mochr that your suggested change is more ideal however so I will wait to wait to re-implement this for our .net core 2.2 to .net core 3.1 upgrade when you have things finalized. Thanks so much for your work on this! |
Thanks for the quick response, but I don't think this issue is fully fixed. When i run the 1-2-AnyOrg example, the |
Yes, I have added the master branch as a dependency to the example project, and built from source. |
Oh, I see, this does not work for the first leg of the Auth code flow handled by the Web app when the user signs-in. |
Hi, @TimThaens. Please try the methods specified in article Configure ASP.NET Core to work with proxy servers and load balancers to enable forwarded headers instead of using these redirect properties. |
@BurritoSmith @goshmiller @graemeWT @TimThaens @krispenner We've been directed by the ASP .NET Core team to remove the MicrosoftIdentityOptions values of The AspNetCore guidance for working with proxies is here Address the issue centrally by using UseForwardedHeaders to fix up the request fields like scheme. The container scenario should have been addressed by default in .NET Core 3.0 If there are issues with this for you, please contact the ASP .NET Core team, as they will be the right team to assist with this. More info here. |
Hi,
Thanks for this email.
It is going to take me a while to work out what it means but I guess it is important.
Regards
Graeme
From: jennyf19 <[email protected]>
Sent: Wednesday, 24 June 2020 2:39 AM
To: AzureAD/microsoft-identity-web <[email protected]>
Cc: Graeme Thomson <[email protected]>; Mention <[email protected]>
Subject: Re: [AzureAD/microsoft-identity-web] [Bug] Redirect URI is set to http instead of https when deploying to Azure App Service for Docker container (Linux) (#115)
@BurritoSmith<https://github.com/BurritoSmith> @goshmiller<https://github.com/goshmiller> @graemeWT<https://github.com/graemeWT> @TimThaens<https://github.com/TimThaens> @krispenner<https://github.com/krispenner>
We've been directed by the ASP .NET Core team to remove the MicrosoftIdentityOptions values of RedirectUri, PostLogoutRedirectUri, and ForceHttpsRedirectUris from the public API. These will be removed in the next release (0.2.0-preview).
The AspNetCore guidance for working with proxies is here<https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1>
Address the issue centrally by using UseForwardedHeaders to fix up the request fields like scheme.
The container scenario should have been addressed by default in .NET Core 3.0<https://devblogs.microsoft.com/aspnet/forwarded-headers-middleware-updates-in-net-core-3-0-preview-6/>
If there are issues with this for you, please contact the ASP .NET Core team<https://github.com/dotnet/aspnetcore>, as they will be the right team to assist with this.
More info<#223> here.
cc: @jmprieur<https://github.com/jmprieur> @Tratcher<https://github.com/Tratcher>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#115 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAZRCTXDPLFH4A2UCBAHLYLRYDLBVANCNFSM4MNDW5PA>.
|
Many thanks, @jennyf19 |
Thanks for confirming, @TimThaens |
Updated the documentation Deploying Web apps to App services as Linux containers |
- Apply redirect config as added by AzureAD/microsoft-identity-web#115 - Add Signout redirect - Add Application Insights - Covers issue #1 and even already some role-based experiments
Hi, I have cretaed an ASP.Net Core 3.1 application with Azure AD authenticated. In my local I have not faced any issue because localhost is in exceptional list , when I hosted it on IIS on my dev server I am getting error like "The reply URL specified in the request does not match the reply URLs configured for the application: clientID". On Azure portal there is no option to register our URLs as 'http' but my dev server does not have SSL settings. How can we resolve this issue. Our web server is configured through load balancer. Can we do any settings in load balancer or from .net application. Could you please suggest me? Thanks in Advance!! Regards, |
Hi @jmprieur , I am facing same issue with ASP.net MVC project as well. Could you please suggest me the fix ? |
I have gone through implementing the forwarded headers as described in https://github.com/AzureAD/microsoft-identity-web/wiki/Deploying-Web-apps-to-App-services-as-Linux-containers but I still get redirect_uri=http instead of https in my deployed linux container. ASP.NET Core 3.1, Microsoft.Identity.Web 1.16.1, OpenIdConnect 3.1.19. Is there anything else I missed besides:
and:
For now I'm going to implement the forcing of https through the redirect callback handler thing as described above since I need to move forward (no pun intended!) with this... |
@Tratcher, can you please help? |
I implemented the OnRedirectToIdentityProvider additions to one project that uses:
and it works fine, it redirects back to the modified https page and everything is handled well. I have a second project that uses:
and it does redirect back to the modified https page but something in that signin-oidc code is erroring out, still saying that the reply URL (http) doesn't match the one in the app registration (https). I cannot readily find the controller code that handles this callback to debug further. And the forwarded headers doesn't work at all and I have no clue how to debug that further. |
The scheme has to be changed in too many places for the OnRedirectToIdentityProvider approach to work reliably. Let's get the forwarders working instead. Start with the troubleshooting steps at |
@Tratcher This is a project that is built into a Linux container and then published to an Azure Web App. Does there need to be something special done to the Azure load balancer or something? What would I put into the KnownProxies? |
Oh, there's a similar scenario here: dotnet/aspnetcore#24151 If you're creating your own dockerfile then add the following: |
Ah yes. Got it! I'm wondering how I could have stumbled upon that any sooner. After inserting that environment variable everything works. I can now remove the past two day's worth of messy trial-and-error code I had going on to try to make this all happen. Thanks! |
- Apply redirect config as added by AzureAD/microsoft-identity-web#115 - Add Signout redirect - Add Application Insights - Covers issue #1 and even already some role-based experiments
I encountered the same situation using options.Events.OnRedirectToIdentityProvider = async context =>
{
// Call what Microsoft.Identity.Web is doing
await redirectToIdpHandler(context);
// Override the redirect URI to be what you want
context.ProtocolMessage.RedirectUri = "your redirect URI";
context.ProtocolMessage.PostLogoutRedirectUri = "your post logout URI";
}; worked for me. Confirmed. |
Hi, I've been tried all suggestions here, but no one have solved my problem. My configurations: Program.cs ...
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
...
// first use
app.UseForwardedHeaders();
... nginx.conf server {
listen 80;
listen [::]:80;
server_name sts.des.mycompany.com;
access_log off;
error_log off;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name sts.des.mycompany.com;
ssl_certificate /etc/nginx/ssl/bundle-sts.crt;
ssl_certificate_key /etc/nginx/ssl/private-sts.key;
ssl_protocols SSLv3 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling off;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
location /diag {
alias /usr/share/nginx/html/diag.txt;
default_type text/plain;
}
location / {
proxy_pass https://sts-service:8443;
proxy_ssl_server_name on;
proxy_ssl_name $server_name;
proxy_set_header Host $host;
proxy_set_header Referer $http_referer;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto HTTPS;
proxy_http_version 1.1;
proxy_buffering on;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
port_in_redirect off;
limit_req zone=one burst=10 nodelay;
}
} Dockerfile FROM mcr.microsoft.com/dotnet/aspnet:$VERSION AS base
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENV ASPNETCORE_URLS="http://+:8080;https://+:8443"
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
ENV http_proxy="http://10.1.X.X:80"
ENV https_proxy="http://10.1.X.X:80"
ENV no_proxy="localhost"
RUN apk add --no-cache icu-libs
RUN apk add --no-cache icu-data-full
WORKDIR /app
EXPOSE 8080
EXPOSE 8443
RUN adduser \
--disabled-password \
--home /app \
--gecos '' app \
&& chown -R app /app
USER app Any suggestion? Regards. |
What do the troubleshooting logs say? |
@Tratcher, I do not have access to logs, some internal policies is required to take it. But a I’ve been solved the problem, removing the first nginx block (:80 to :443 redirect) and leaving the application do the https redirection, no code changed. nginx.conf (server block) server {
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
server_name sts.des.mycompany.com;
ssl_certificate /etc/nginx/ssl/bundle-sts.crt;
ssl_certificate_key /etc/nginx/ssl/private-sts.key;
ssl_protocols SSLv3 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling off;
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types application/atom+xml application/geo+json application/javascript application/x-javascript application/json application/ld+json application/manifest+json application/rdf+xml application/rss+xml application/xhtml+xml application/xml font/eot font/otf font/ttf image/svg+xml text/css text/javascript text/plain text/xml;
gzip_disable "MSIE [1-6]\.";
location /diag {
alias /usr/share/nginx/html/diag.txt;
default_type text/plain;
}
location / {
proxy_pass http://sts-service:80;
proxy_set_header Host $host;
proxy_set_header Referer "https://$server_name$request_uri";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Original-For $remote_addr;
proxy_set_header X-Original-Proto "https";
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-Port 443;
proxy_http_version 1.1;
proxy_buffering on;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
port_in_redirect off;
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|mp3|ogg|ogv|webm|htc|woff2|woff)$ {
expires 1d;
access_log off;
add_header Cache-Control "public";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_pass http://sts-service:80;
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1h;
access_log off;
add_header Cache-Control "public";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_pass http://sts-service:80;
}
} |
Which Version of Microsoft Identity Web are you using ?
Microsoft Identity Web 1.0.0-preview
Where is the issue?
Other? - please describe;
Probably valid for most cases.
Is this a new or existing app?
This is an experiment to test an app with Microsoft.Identity.Web deployed to Azure App Service for Docker Containers.
Repro
redirect_uri=http%3A%2F%2F<your app service name>.azurewebsites.net%2Fsignin-oidc
instead ofredirect_uri=https%3A%2F%2F<your app service name>.azurewebsites.net%2Fsignin-oidc
.Expected behavior
Expected to be redirected to the HTTPS-page.
Actual behavior
Error AADSTS50011 is shown in the browser, as there is a mismatch between registered redirect-URIs.
Possible Solution
Maybe there is a way to configure the App Service to avoid this issue? Or is there a way to configure Microsoft.Identity.Web to use HTTPS in the redirect URI?
Additional context/ Logs / Screenshots
The application log shows the following:
Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]: Failed to determine the https port for redirect.
There is a hint here that SSL should not be enabled in the web app, but how is it possible to not have SSL enabled in the web app, but still have HTTPS in the redirect URI?
The text was updated successfully, but these errors were encountered: