IdentityServer4 configure OpenId connect provider to use proxy server - identityserver4

I am using IdentityServer4 to provide authentication and token generation for my new services and I have it all working successfully. I have configured my server to use Azure AD as an oidc provider which has been working ok in my staging environment because the ip address for Azure AD is configured in the firewall. Today that ip address appears to have changed because my code is unable to make a call to Azure AD to get the openid well known configuration (https://login.microsoftonline.com/[mytenantid]/.well-known/openid-configuration).
I configure the provider using the following code:
services.AddAuthentication()
.AddOpenIdConnect("oidc", "AzureAD", options =>
{
options.ClientId = Configuration["adclientid"];
options.ClientSecret = Configuration["adsecret"];
options.Authority = $"{Configuration["addomain"]}{Configuration["adtenantid"]}";
options.UseTokenLifetime = true;
options.CallbackPath = "/signin-oidc";
options.RequireHttpsMetadata = false;
})
.AddCookie();
Our company does have a proxy server available which will let my code make the calls and not be affected whenever the ip address changes. How can I amend my code to make it use the proxy?

Try to add a BackchannelHttpHandler:
.AddOpenIdConnect("aad", "Azure AD", options =>
{
options.BackchannelHttpHandler = new HttpClientHandler { Proxy = Proxy};
....

Related

How to implement Single Sign On in ASP.NET MVC application

We have developed 2 applications in ASP.NET MVC. We have used ASP.NET Identity in both applications for user authentication. Both applications use the same database. Also both apps are hosted on Azure Portal.
We would like to implement SSO in both applications, so when I log in to one application, the second application doesn't ask for login again and authenticates the already logged in user.
We have implemented to share authentication cookies among ASP.NET apps as per the Microsoft document (open the link shared below), but it's not working. I have posted code below.
https://learn.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-2.1#sharing-authentication-cookies-between-aspnet-4x-and-aspnet-core-applications
I have written this code in Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = ".AspNet.SharedCookie",
CookieDomain= ".azurewebsites.net",
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(120),
LoginPath = PathString.FromUriComponent("/Account/Login"),
LogoutPath = PathString.FromUriComponent("/Account/Logout"),
TicketDataFormat = new AspNetTicketDataFormat(
new DataProtectorShim(
DataProtectionProvider.Create(new DirectoryInfo("C:\\ApplicationData"),
(builder) =>
{
builder.SetApplicationName("SharedCookieApp");
})
.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies." +
"CookieAuthenticationMiddleware",
"Cookies.Application",
"v2"))),
CookieManager = new ChunkingCookieManager()
});
}
Also added claim when user logged in successfully in login method as below.
var user1 = await UserManager.FindByNameAsync(model.Email);
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user1.Id));
claims.Add(new Claim(ClaimTypes.Name, model.Email));
var id = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(30),
IssuedUtc = DateTime.UtcNow
}, id);
This works fine in localhost but when it is published in Azure portal, it doesn't work. It seems that the authentication cookie is not shared among the 2 apps on Azure Portal because Azure doesn't allow to access directory location hence it gives error like 'Access Denied' and I don't know how to use Azure Key vault or database to store cookie.
Can you please guide me if I have missed something or have did incorrectly. Your earlier response would be highly appreciated. Let me know if you need any other details.
Regards,
Kiran Shah

AADSTS50011 after creating CNAME

I had my IdenityServer4 oidc service running correctly as an AppService on Azure. Now I created a DNS entry in my hosting to create better names for all the services. For Azure-AD I keep getting this error:
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: '<my app id>'.
I have these two reply-urls setup in Azure AD portal:
https://account.mysite.com/signin-microsoft
https://myapp-oidc.azurewebsites.net/signin-microsoft
The second one works but the first does not, giving the error. Is there any way for me to debug this and see what reply url apparently is different that the one configured?
Here's the setup in startup.cs:
services
.AddAuthentication()
.AddMicrosoftAccount("Microsoft", options => {
options.SignInScheme = "Identity.External";
options.ClientId = "xxx";
options.ClientSecret = "xxx";
})
I did the same for google (https://account.mysite.com/signin-google) and that worked right away but I can't get Azure to work on the new address.

IdentityServer4 with ADFS as external Identity Provider

I'm having a ASP.NET MVC test app who should work as an implicit OIDC client having access and id tokens from an IdentityServer4 app (both are dotnet core 3.1). IdSvr has a couple of external OIDC IdPs configured: A KeyCloak instance, and a ADFS (4.0) ditto.
My IdSvr configuration of ADFS is as follows:
.AddOpenIdConnect("oidc_adfs", "ADFS", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SaveTokens = true;
options.Authority = "<<ADFS endpoint>>";
options.ClientId = "<<ADFS defined client id>>";
options.ClientSecret = "<<ADFS defined client secret>>";
options.Resource = "<<My resource identifier in ADFS>>";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
options.ResponseType = "id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
});
In the KeyCloak case, everything goes fine - the callback request to IdSvr's "/signin-oidc" goes fine and the front-channel user agent ends at the destination test app's post-auth endpoint and the tokens are available.
When I use ADFS, the flow stops with a HTTP 500 after the user is authenticated in ADFS, and the "/signin-oidc" endpoint is hit, and IdSvr log reads:
CORS request made for path: /signin-oidc from origin:
<<ADFS_endpoint>> but was ignored because path was not for an
allowed IdentityServer CORS endpoint 2020-09-20 12:34:01.157 +02:00
[INF] Error from RemoteAuthentication: Unable to unprotect the
message.State..
I've setup CORS according to the IdentityServer4 docs, so the problem might be something else?
When inspecting differences in KeyCloak and ADFS callback requests to "/signin-oicd", I can see that ADFS does add Referer/Origin to the request and KeyCloak does not. Apart from that, the two requests seem quite similar.
Hope someone can help.
If you see the Origin header from ADFS, then I guess you need to add the ADFS domain to the list of allowed CORS endpoints.
What error is shown in the ADFS event log?
The problem may also be that ADFS 4.0 does not support CORS?

SustainSys library is not including email claim from Azure AD?

I am using IdentityServer3 for authentication and i have also configured Azure AD as external provider in IdentityServer3. Since Azure AD is using SAML2 protocol i am using SustainSys library to configure Azure AD.
In Azure AD i have configure the payload as below. Notice the email is included in the payload
However, after user is authenticated in Azure AD, and request comes back to IdentityServer, SustainSys library is not including email claim.
Is there any configuration i need to do in SustainSys library to include email claim? In IdentityServer3 I am loading Azure AD provider using code
private void AddSAML2Idp(IAppBuilder app, SAML2Provider provider, string signInAsType)
{
var authenticationOptions = new Saml2AuthenticationOptions(false)
{
SPOptions = new SPOptions
{
EntityId = new EntityId(provider.AuduenceURI), // Auduence URI
MinIncomingSigningAlgorithm = provider.MinIncomingSigningAlgorithm,
ModulePath = string.Format("/{0}", provider.Idp)
},
SignInAsAuthenticationType = signInAsType,
AuthenticationType = provider.Idp,
Caption = provider.Caption
};
UseIdSrv3LogoutOnFederatedLogout(app, authenticationOptions);
authenticationOptions.SPOptions.ServiceCertificates.Add(LoadCertificateFromWindwosStore(ApplicationConfig.Saml2SigningCertificateSubjectName));
var identityProvider = new IdentityProvider(new EntityId(provider.EntityID), authenticationOptions.SPOptions)
{
MetadataLocation = provider.MetadataLocation,
LoadMetadata = true
};
authenticationOptions.IdentityProviders.Add(identityProvider);
app.UseSaml2Authentication(authenticationOptions);
}

Connection to Azure Vault using MSI

I am trying to connect to my azure vault from a console application with using MSI
For this vault i have added my user as the Selected Principle
the code i am using to connect is
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("https://<vaultname>.vault.azure.net/secrets/<SecretName>").ConfigureAwait(false);
I get the following exception
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException:
Parameters: Connectionstring: [No connection string specified],
Resource: https://vault.azure.net, Authority
Enable Managed Service Identity in the Configuration blade under your virtual machine.
Search for NameOfYourVM service principal and add it to your Key Vault under Access Policies. Add key/secret/certificate permissions.
On your Azure VM, run the console app.
class Program
{
// Target C# 7.1+ in your .csproj for async Main
static async Task Main()
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync(
"https://VAULT-NAME.vault.azure.net/secrets/SECRET-NAME");
Console.WriteLine(secret.Value);
Console.ReadLine();
}
}
To run locally, create your very own Azure AD application registration (Web App/Web API type to make it a confidential client), add it to Key Vault and use its client_id and client_secret when acquiring the access token —
https://learn.microsoft.com/en-us/azure/key-vault/key-vault-use-from-web-application#gettoken
As Varun mentioned in the comments, there's now a better way to get an access token when running locally without exposing a service principal —
https://learn.microsoft.com/en-us/azure/key-vault/service-to-service-authentication#local-development-authentication
To run locally.
install Azure Cli
Open Windows Powershell
write az login command (it will give an url and code )
Open Url and enter the code which is given with az login
then get the secret value like this
var secret = await keyVaultClient.GetSecretAsync("https://VAULT-NAME.vault.azure.net/secrets/SECRET-NAME");
secret.Value; //your secret.
a correct answer is already given above, here's an additional one :-)
Azure MSI applying with App Service & Vault
Enable System Assigned Managed Identity for your App Service, check Identity section under settings.
Add Policy under Vault
configure your code behind

Resources