Closed nhumby closed 2 years ago
The request identity has an empty name claim and nothing further.
That doesn't mean you're not authenticated. Is the IsAuthenticated
true or false? If it's true, then name problem has to do with the claim mappings in your client app, and more specifically the NameClaimType setting buried somewhere on the OpenIdConnectAuthenticationOptions
.
Anyway, I land up in that annoying eternal ping pong between my RP and the demo IDP until the headers grow too big.
Hmm, maybe you're not getting the cookie in the client app? Not sure without knowing the result of the above question.
Hi Brock, thanks for the quick reply! On my actual app the Request.IsAuthenticated property is false. I can't share my employer's web app so I've loaded the empty web forms app I tried to secure to a private repo and added you as a collaborator. It's at https://github.com/nhumby/WebApplication4 and it should illustrate the same behaviour (prompted to log in, then bouncing between RP and IDP). It should look very similar to the Web Forms sample and I'd appreciate any tips on what steps I may have unknowingly missed here.
Also, though possibly unrelated I understand what you meant about claims mappings or not getting the cookie, but I'm not sure how to check or implement that (I'm still getting my head around Katana/OWIN).
On a side note, here's a video I did a very long time ago about the basics of OWIN/Katana: https://vimeo.com/97329189.
I tried to look for something where we showed setting up the OIDC middleware, but I can't find anything.
That video was really helpful, thank you. I've watched a few including on Pluralsight but this explained it far better than the others (it helps make more sense of Core too). So by trial and error I found the problem in my empty web project. When calling app.UseOpenIdConnectAuthentication if the RedirectUri does not end in a trailing slash / then I get the infinte ping pong between the RP and the IDP. As soon as I add a trailing slash it works fine. Any idea why that is? Unfortunately this didn't fix the issue for the app I'm paid to work on, I also had to change the app.UseCookieAuthentication call from this:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = Constants.AuthenticationType,
CookieName = OpenIdAuthenticator.CookieName,
CookiePath = OpenIdAuthenticator.CookiePath,
CookieSecure = CookieSecureOption.Always,
AuthenticationMode = AuthenticationMode.Active,
SlidingExpiration = true
});
to this:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = "cookies",
ExpireTimeSpan = TimeSpan.FromMinutes(10),
SlidingExpiration = true
});
I'm not sure what was the breaking setting in the former code block.
Hi Brock. I'm authenticating against demo.duendesoftware.com but not getting any user identifying claims from the Identity Server which is really weird. Below are the claims and authentication result's properties from the OWIN context, and none of them seem to identfy the user? There's no "name" scope and I'm using "openid profile offline_access", shouldn't profile return a username? I tried adding the "email" claim but no dice. I get the same from the Web Forms sample Duende published.
Claims: Type: iss, Value:https://demo.duendesoftware.com Type: nbf, Value:1663679600 Type: iat, Value:1663679600 Type: exp, Value:1663679900 Type: aud, Value:interactive.confidential Type: amr, Value:pwd Type: nonce, Value:637992763925340628.N2VhZjNjYTQtNzdjNC00ZWQ1LWFjMDctYTQ5MTBjMjJjMzM4YzAxZjNmNzItMTlkMC00NmE1LTk0ZDctYTEzYzg2MjUyMGI1 Type: at_hash, Value:bx439QrKEjiEZ_8DUbro0g Type: sid, Value:F3A3E53986E8512CF5C3FBA1B8CA9586 Type: sub, Value:2 Type: auth_time, Value:1663679600 Type: idp, Value:local
AuthDictionary: Key: .redirect, Value: https://localhost/Admin/ Key: OpenIdConnect.Code.RedirectUri, Value: https://localhost/Admin/ Key: access_token, Value: eyJhbGciOiJSUzI1NiIsImtpZCI6IkMxNkFDOUJERThBNUEwRTlFNUEwRTFFNUFGMzA2QUExIiwidHlwIjoiYXQrand0In0.eyJpc3MiOiJodHRwczovL2RlbW8uZHVlbmRlc29mdHdhcmUuY29tIiwibmJmIjoxNjYzNjc5NjAwLCJpYXQiOjE2NjM2Nzk2MDAsImV4cCI6MTY2MzY4MzIwMCwic2NvcGUiOlsib3BlbmlkIiwiZW1haWwiLCJwcm9maWxlIiwib2ZmbGluZV9hY2Nlc3MiXSwiYW1yIjpbInB3ZCJdLCJjbGllbnRfaWQiOiJpbnRlcmFjdGl2ZS5jb25maWRlbnRpYWwiLCJzdWIiOiIyIiwiYXV0aF90aW1lIjoxNjYzNjc5NjAwLCJpZHAiOiJsb2NhbCIsInNpZCI6IkYzQTNFNTM5ODZFODUxMkNGNUMzRkJBMUI4Q0E5NTg2IiwianRpIjoiQkM3MzUyQjI4NTMzMzMwMTk1OEVFNkFDRkZEMEY3MUMifQ.aoV-LlLX2KKyMcDVmuw5NyDBv_6Gm1nd14GffMhPLDs99ba4RVnJqdc7usiCKrMNvPlIzY5oZ04Pfn3togkozh2zib9wmOepMSYqOhNKZ83tvekwAys4FzBaM_1MA5SFObc9d5nwKmkySsE7gvUCtQmqslqXb9eIQYD0dOlHLTk_mI114T1ohJ2zNERzaNuEoAiZ6M3zrgKKlQSVENAiGOktcw0q_g4T1E54Q9m9WpFHpzjp9IXA5yyLE4AnMNLKDrgLLEmRMsIBOpPjEmTIWP8yGW8vDrMqEW3LyzQ8I1M_FQPBNURv1Dg19r9b27F7qge-vIQxwN-u5m8lKoTUPg Key: .sessionState, Value: LfaW6WWi_koxSb-ZAobm1lCbDBIATwJAxm50P3U-nVg.AC2800259A6E580AE363265ABDE98F5B Key: .checkSessionIFrame, Value: https://demo.duendesoftware.com/connect/checksession Key: id_token, Value: eyJhbGciOiJSUzI1NiIsImtpZCI6IkMxNkFDOUJERThBNUEwRTlFNUEwRTFFNUFGMzA2QUExIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2RlbW8uZHVlbmRlc29mdHdhcmUuY29tIiwibmJmIjoxNjYzNjc5NjAwLCJpYXQiOjE2NjM2Nzk2MDAsImV4cCI6MTY2MzY3OTkwMCwiYXVkIjoiaW50ZXJhY3RpdmUuY29uZmlkZW50aWFsIiwiYW1yIjpbInB3ZCJdLCJub25jZSI6IjYzNzk5Mjc2MzkyNTM0MDYyOC5OMlZoWmpOallUUXROemRqTkMwMFpXUTFMV0ZqTURjdFlUUTVNVEJqTWpKak16TTRZekF4WmpObU56SXRNVGxrTUMwME5tRTFMVGswWkRjdFlURXpZemcyTWpVeU1HSTEiLCJhdF9oYXNoIjoiYng0MzlRcktFamlFWl84RFVicm8wZyIsInNpZCI6IkYzQTNFNTM5ODZFODUxMkNGNUMzRkJBMUI4Q0E5NTg2Iiwic3ViIjoiMiIsImF1dGhfdGltZSI6MTY2MzY3OTYwMCwiaWRwIjoibG9jYWwifQ.rvcEybisne20UN5RGWCOXSVUt6g9YTiW2O7Bg5rbpJHkJfx5HAiOZW3X3wf3grUKzpbFV2i6BXFN_YTYLbwtWQvK9YqUVdU6WVojHVnNuQgDHiqg3nbJm_3Y4fG6n_D7e-5ArBFbrvrLWoubnGxeoGZNJKlY5WfcjBCl9bqLpIJUfYwTAW3_oydTrlpinSI52fbtFv2FzwvrzrtETBQL-g5tlezyoVaNZ2OzFgaUXrC3ZumAzmud4Y0_osxqA16HrQPm4Q1ftzARIPzvIPCiegiIwjmu6uCNJD_nWeFnzFLprsaEdbfpfslYcd9FOau7JAIkXmmENv0nhdEdJRASEw Key: refresh_token, Value: 3FA55D64F5CEE2B54E11641D99938D25AD0808E6DE6E7EADDE54CB852AA12AE2-1 Key: token_type, Value: Bearer Key: expires_at, Value: 2022-09-20T14:13:21.0338449Z Key: .issued, Value: Tue, 20 Sep 2022 13:13:21 GMT Key: .expires, Value: Tue, 20 Sep 2022 13:23:21 GMT
So by trial and error I found the problem in my empty web project. When calling app.UseOpenIdConnectAuthentication if the RedirectUri does not end in a trailing slash / then I get the infinte ping pong between the RP and the IDP. As soon as I add a trailing slash it works fine. Any idea why that is?
I've seen wonky issues in OWIN where the path on the set-cookie header either does or does not have the path, and then subsequent requests the browser won't send it... but not sure in your case.
Type: sub, Value:2
This is the user's unique id. The sub
claim is the most important one.
https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
Ok thanks. Looking at the discovery document I saw I needed to hit https://demo.duendesoftware.com/connect/userinfo with the bearer access token to get further information (since we offer multiple IDP options like AzureAD or SalesForce too we use email addresses as identifiers). Sorry, I know this is probably very basic stuff. I appreciate your time answering.
On a side note -- email address is bad identifier because it can be re-assigned to other people in the IdP without the app/APIs knowing.
That's a good point, I hadn't considered it. Do you recommend Identity Server users rely on the sub claim? It looks like a primary key field from a DB, is that correct and therefore it's also immutable?
If you're using ASP.NET Identity, then their ID column (IIRC) is a GUID, so yes -- that's a good value.
Hi Brock. With IdentityServer3 it seems we used the AuthorizationCodeReceived notification property to idenitfy the user and create some custom claims for use in our app. I'm doing the same for this however I can't find any user details in the AuthorizationCodeReceivedNotification object. I wired it up like so in my Startup.cs:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "cookies",
Authority = OpenIdAuthenticator.Authority,
ClientId = "interactive.confidential",
ClientSecret = "secret",
RedirectUri = OpenIdAuthenticator.RedirectUri,
ResponseType = "code",
Scope = "openid email profile offline_access",
UseTokenLifetime = false,
SaveTokens = true,
RedeemCode = true,
UsePkce = true,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async context =>
{
await duendeSofwareAuthenticator.AuthorizationCodeReceived(context);
},
RedirectToIdentityProvider = context => duendeSofwareAuthenticator.RedirectToIdentityProvider(context)
}
});
And in the code handling it I'm following the example from the Web Forms sample:
public override async Task AuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
{
foreach (var claim in notification.OwinContext.Authentication.AuthenticateAsync("cookies").Result.Identity.Claims)
{
string accessToken;
if (claim.Type.Equals("access_token"))
{
accessToken = claim.Value;
}
}
The problem is the Result is null and so it looks like the Task for notification.OwinContext.Authentication.AuthenticateAsync("cookies") has status RanToCompletion but the Result is a null object. The Exception field is null too. I'm at a bit of a loss, I know the same code works inside pages when they're being rendered, is this delegate too soon? If so, can you recommend where I should hook in with OWIN that is post authentication?
I'm not sure if this is it, but the async code is written incorrectly. It should be more like this:
public override async Task AuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
{
var result = await notification.OwinContext.Authentication.AuthenticateAsync("cookies");
foreach (var claim in result.Identity.Claims)
Oh yeah, thanks! I changed the code to do it this way instead:
public override async Task AuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
{
var result = await notification.OwinContext.Authentication.AuthenticateAsync("cookies");
but the result object is still null. I've included a screengrab of the state of the AuthorizationCodeReceivedNotification received from the IdP in case there's anything there that provides any clue why?
Doing the same thing in the sample Web Forms project's default.aspx it does work though, so I'm really confused why mine doesn't.
<dl>
<%
// hack
var result = Context.GetOwinContext().Authentication.AuthenticateAsync("cookies").Result;
foreach (var claim in result.Identity.Claims)
{
%>
<dt>
<%: claim.Type %>
</dt>
<dd>
<%: claim.Value %>
</dd>
<%
}
%>
<%
foreach (var item in result.Properties.Dictionary)
{
%>
<dt><%:item.Key %></dt>
<dd><%:item.Value %></dd>
<%
}
%>
</dl>
Hi @nhumby -- yea not sure either, to be honest.
Hi Brock. I finally have it working! However, it's not great code. Three pieces of data I need (access token, refresh token, expiry) are only available in the TokenResponseReceived delegate.
internal async Task TokenResponseReceived(TokenResponseReceivedNotification notification)
{
_accessToken = notification.TokenEndpointResponse.AccessToken;
_refreshToken = notification.TokenEndpointResponse.RefreshToken;
if (!long.TryParse(notification.TokenEndpointResponse.ExpiresIn, out var expiresIn))
expiresIn = 0;
_expiresAt = DateTime.UtcNow.AddSeconds(expiresIn).Ticks;
}
However, I can only create a new ClaimsIdentity and store those as claims in the SecurityTokenValidated delegate. This delegate isn't provided with the access token, refresh token, or expiry so I have to cache them somewhere in the earlier delegate. For my proof of concept I cache the data as properties on my OpenIdAuthenticator subclass but that doesn't feel right, and I suspect there's a better way of doing this:
internal async Task SecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var userInfoClient = new UserInfoClient(Authority + UserInfoEndpoint);
var userInfoResponse = await userInfoClient.GetAsync(_accessToken);
CreateClaims(notification, _accessToken, _refreshToken, _expiresAt.ToString(), userInfoResponse);
}
private static void CreateClaims(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification, string accessToken, string refreshToken, string expiresAt, UserInfoResponse userInfoResponse, string tokenType = "bearer")
{
var claimsIdentity = new ClaimsIdentity(notification.AuthenticationTicket.Identity.AuthenticationType);
claimsIdentity = new ClaimsIdentity(notification.AuthenticationTicket.Identity.AuthenticationType);
claimsIdentity.AddClaims(userInfoResponse.Claims);
claimsIdentity.AddClaim(new Claim(Constants.AccessToken, accessToken));
claimsIdentity.AddClaim(new Claim(Constants.ExpiresAt, expiresAt));
if (refreshToken != null) claimsIdentity.AddClaim(new Claim(Constants.RefreshToken, refreshToken));
// create authentication ticket
notification.AuthenticationTicket = new AuthenticationTicket(new ClaimsIdentity(claimsIdentity.Claims, notification.AuthenticationTicket.Identity.AuthenticationType, Constants.Name, Constants.Role), notification.AuthenticationTicket.Properties);
}
It works but it feels wonky. If there's a more appropriate forum for me to ask this please let me know where to go.
Is there not a ClaimsPrincipal on the TokenResponseReceivedNotification somewhere that will be carried over to the ultimate user when the cookie is created?
I found one at TokenResponseReceivedNotification.OwinContext.Authentication.User but it's null, and I couldn't find an AuthenticationTicket to wrap it in after modifying its claims.
The other place you can stash stuff is on the OwinContext.Items collection -- that's like the old HttpContext.Items collection. It's a per-request dictionary.
Thank you, I put it in the OwinContext Environment dictionary and it worked!
I'm getting a weird cryptographic exception when accessing a secured API. I suspect its causing the Owin process to crash out because I get an IIS HTTP error response rather than a .Net custard-coloured one, as if the .Net request handler module isn't even there. Works fine if I switch to another IDP. It's thrown from the Microsoft.Owin.Security.DataHandler.SecureDataFormat class' Unprotect method when it tries to unprotect the userData. It looks a lot like this issue except I'm getting it even with a fresh incognito browser and iisreset. https://github.com/IdentityServer/IdentityServer3/issues/992
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exception will be traced")]
public TData Unprotect(string protectedText)
{
try
{
if (protectedText == null)
{
return default(TData);
}
byte[] protectedData = _encoder.Decode(protectedText);
if (protectedData == null)
{
return default(TData);
}
byte[] userData = _protector.Unprotect(protectedData);
if (userData == null)
{
return default(TData);
}
TData model = _serializer.Deserialize(userData);
return model;
}
catch
{
// TODO trace exception, but do not leak other information
return default(TData);
}
}
Thank you, I put it in the OwinContext Environment dictionary and it worked!
It's been a while, but Environment (if I recall correctly) is global to the app, so be careful there. The pre-request "Items" might be on the request object.
Closing. If you still have issues, feel free to reopen.
Thanks Brock. I managed to repair the reference issues in the downloaded samples and I have it fully working. I tried securing my own apps against it but ran into too many issues with the certificates. It's a faff starting several projects without debugging so I publish the IdentityServerHost project to a local folder and aimed IIS at it. Everything work fines except the CallApi link on the top menu bar. If I click on CallApi it throws this:
If I switch back to running the IdentityServerHost project as a console app then CallApi works. It's the same code, the only difference is in the shared Constants.cs which has public class Urls, I change public const string IdentityServer = "https://localhost:5001"; to public const string IdentityServer = "https://localhost/IdentityServerHost";
Any idea why it works as a console app but not when hosted by IIS? My employer has just purchased a license so pressure's on for me to get this implemented, let me know if I should be using a different platform for support.
Unfortunately I can't see any way of changing the issue to open again.
Unfortunately I can't see any way of changing the issue to open again.
For new/unrleated things we prefer new issues. Smaller more focused issues help others when they're searching.
I think we'd need to see the logs in the API host to understand why it's failing. It's not clear if it's failing because the HTTPS/localhost of IdentityServer change, or something else. I'm going to guess it's unrelated to IdentityServer, and just cert issues and lack of trust configuration in your environment.
Is that the katana.trace.log file in the \bin\debug? I cleared it out and this was the only entry after hitting the CallApi:
Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.NullReferenceException: Object reference not set to an instance of an object.
at SimpleApi.Startup.LoadKeys(String token, SecurityToken securityToken, String kid, TokenValidationParameters validationParameters) in D:\Source\Learning\Samples2\Samples\various\clients\Owin\SimpleOwinApi\Startup.cs:line 49
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters) in C:\agent2_work\56\s\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 900
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken) in C:\agent2_work\56\s\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 718
at Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText) in /_/src/Microsoft.Owin.Security.Jwt/JwtFormat.cs:line 213
at Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationHandler.
Startup.cs line 49 is the second line of this method:
private IEnumerable<SecurityKey> LoadKeys(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)
{
var disco = _discoveryCache.GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
var keys = disco.KeySet.Keys
.Where(x => x.N != null && x.E != null)
.Select(x => {
var rsa = new RSAParameters
{
Exponent = Base64UrlEncoder.DecodeBytes(x.E),
Modulus = Base64UrlEncoder.DecodeBytes(x.N),
};
return new RsaSecurityKey(rsa)
{
KeyId = x.Kid
};
});
return keys;
}
It looks like its having trouble validating the signature of the Jwt token handler? I can't see anywhere that might be set. The URL http://localhost/identityserverhost/.well-known/openid-configuration returns the JSON below so that all seems fine. My localhost is secured with a self signed cert but it's trusted.
{"issuer":"http://localhost/identityserverhost","jwks_uri":"http://localhost/identityserverhost/.well-known/openid-configuration/jwks","authorization_endpoint":"http://localhost/identityserverhost/connect/authorize","token_endpoint":"http://localhost/identityserverhost/connect/token","userinfo_endpoint":"http://localhost/identityserverhost/connect/userinfo","end_session_endpoint":"http://localhost/identityserverhost/connect/endsession","check_session_iframe":"http://localhost/identityserverhost/connect/checksession","revocation_endpoint":"http://localhost/identityserverhost/connect/revocation","introspection_endpoint":"http://localhost/identityserverhost/connect/introspect","device_authorization_endpoint":"http://localhost/identityserverhost/connect/deviceauthorization","backchannel_authentication_endpoint":"http://localhost/identityserverhost/connect/ciba","frontchannel_logout_supported":true,"frontchannel_logout_session_supported":true,"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"scopes_supported":["openid","profile","scope1","offline_access"],"claims_supported":["sub","name","family_name","given_name","middle_name","nickname","preferred_username","profile","picture","website","gender","birthdate","zoneinfo","locale","updated_at"],"grant_types_supported":["authorization_code","client_credentials","refresh_token","implicit","password","urn:ietf:params:oauth:grant-type:device_code"],"response_types_supported":["code","token","id_token","id_token token","code id_token","code token","code id_token token"],"response_modes_supported":["form_post","query","fragment"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","private_key_jwt"],"id_token_signing_alg_values_supported":["RS256"],"subject_types_supported":["public"],"code_challenge_methods_supported":["plain","S256"],"request_parameter_supported":true,"request_object_signing_alg_values_supported":["RS256","RS384","RS512","PS256","PS384","PS512","ES256","ES384","ES512","HS256","HS384","HS512"],"authorization_response_iss_parameter_supported":true,"backchannel_token_delivery_modes_supported":["poll"],"backchannel_user_code_parameter_supported":true}
Sounds like putting a breakpoint in the LoadKeys to understand why it's not working properly would help?
I tried that at the time, unfortunately it won't let me launch the WebForms project without the debugger attached which means I can only run the API project without the debugger attached to it. I can try hosting WebForms in IIS instead, or fire up another instance of VS and split the sample solution up between them. If I wanted to add a line of debug logging instead how do I call the katana logger?
I ran them from two instances of VS in the end. The problem is the issuer of the digital signature is set to https://localhost:5001 and when LoadKeys runs there's a validation step that fails because I'm running it under IIS from https://localhost/IdentityServerHost. I can't find the issuer field specified anywhere so assume it's in the encrypted data in IdentityServerHost/keys/is-signing-key-CBC8DED96FE3A00C00EE32669F5F044A.json. One thing I couldn't confirm is how it gets this key when reading the discovery document, when I browse to http://localhost/identityserverhost/.well-known/openid-configuration I can't find any details on the key (other than the supported encryption algorithms). I'm presuming the IdentityServerHost is using this pre-packaged signing key rather than the keys included in the SSL certificate (though I can't find where this is done either).
We received an email with our licensing details but not sure how to proceed. I've cloned the code from https://github.com/DuendeSoftware/IdentityServer and run the build.cmd. There were errors in the first build run but second and third runs have gone fine without a problem. Is https://docs.duendesoftware.com/identityserver/v6/overview/ the documentation for the next steps? I'm coming from an existing ThinkTecture IdentityServer3 implementation and there seems to be a management tool included at identityserver/tools#/ which allowed us to create and manage the various clients and their settings like token type, expiry time, redirect uri's etc. Is there something similar in Identity Server 6 or is it purely middleware and we need to implement our own authentication server including login pages, token endpoints, and client management pages?
For your first issue, it really sounds like you just don't have your HTTPS certs setup correctly? It's hard to say over github issues. But that's something that needs to get sorted out once you start moving the hosting elsewhere (out of katana).
As for using IdentityServer, and the code on github -- you don't have a license to use the source code in production. So there's no need to clone the repo and try to build it. You'd only do this to test/debug/study the code, which the license does allow for.
The license allows the the binary loaded via NuGet to be used in production:
https://docs.duendesoftware.com/identityserver/v6/overview/packaging/#product
And then you configure the license key as described here:
https://docs.duendesoftware.com/identityserver/v6/fundamentals/license_key/
Yes, the old IdentityServer3 has an internal management tool, but we're now a generation (and perhaps almost a decade now?) since then. Here's the current thinking on admin tools:
(and perhaps almost a decade now?)
Oh gosh! Given that I said that, I had to go look and our last release was only 2018. But I will say, it feels like it's been 10 years :)
Hah yeah 2018 feels a lifetime ago! HTTP certs are good, I've been running multiple products including IdentityServer3 on them without a hitch for years. I meant it's the included key in the sample IdentityServerHost project that I concluded must be hardcoded to https://localhost/5001. It makes sense, that's where it runs from as a console app. I can't find anywhere to tell IdentityServer to use my server host cert, there's no mention of the included key anywhere in the solution for my to update it with. Thanks for the clarifications on the licensing.
The cert for HTTPS is a host config thing (so Kestrel or IIS or whatever). That cert is different than the cert you might us for signing credentials (but I don't think that's what you're asking). So, IOW, IdentityServer itself doesn't get involved with the HTTPS cert at all.
Oh gosh! Given that I said that, I had to go look and our last release was only 2018. But I will say, it feels like it's been 10 years :)
I looked yet again, and the last "real" release was 2016... so my memory was closer than I realized. That's 6 years (closer to 10) :)
The cert for HTTPS is a host config thing (so Kestrel or IIS or whatever). That cert is different than the cert you might us for signing credentials (but I don't think that's what you're asking). So, IOW, IdentityServer itself doesn't get involved with the HTTPS cert at all.
Yup it was complaining about the issuer property and in the LoadKeys method so it must be related to the signing cert rather than the host cert. I remember this concept of signing cert vs host cert from configuring AD FS a while back. Do you perhaps know where in the sample IdentityServerHost project it tells IdentityServer which cert to use for signing tokens with? Or is it a DI thing and it uses the first one it finds or looks by convention for a specific folder? I've had a look online but not found an explanation that works for this version. Given they expire I'm assuming there must be a way of specifying it by configuration so there's no need for recompiling.
Yes, the Issuer is the public host that the IdentityServer runs on, and that is normally determined dynamically when requests are made into IdentityServer (like the discovery document). So whatever host you've configure it to run on becomes that issuer. But if you have more than one IP or hostname mapped to the running app, then it could be different based on the request which is not how it should work (meaning all apps/APIs should be configure to trust your IdentityServer on whatever public hostname you intend it to run on).
If for some reason (for example you're offloading HTTPS or have a load balancer or whatever) and the information on the request doesn't carry thru to your IdentityServer, then you can manually configure the "Issuer" property in the IdentityServer options: https://docs.duendesoftware.com/identityserver/v6/reference/options/#main.
But if you do have the reverse proxy, then normally you can/should configure it to pass along the host info: https://docs.duendesoftware.com/identityserver/v6/deployment/proxies/
Closing. If you still have issues, feel free to reopen.
Thanks Brock, I'm working through the quickstarts and it's making things a lot clearer. I just wanted to double check my next steps, I understand the binaries are licenced but can I use what I build in the quickstarts as a base for production? Likewise for the the templates? Does that also apply to the QuickStartUI and QuickStartUI.AspNetIdentity? They're all mentioned on this page (https://docs.duendesoftware.com/identityserver/v6/overview/packaging/#product) but I just wanted to check if the licence requires us to start from scratch and only use those as a guide or if we can start our product with those and extend them as needed? Also, can we name our product for example "MyCompany.Security.IdentityServer" or is the term "IdentityServer" copyright/trademarked?
I just wanted to double check my next steps, I understand the binaries are licenced but can I use what I build in the quickstarts as a base for production?
Both are correct --- the IdentityServer binary fro NuGet is what is licensed, but the quickstart should be allowed (@leastprivilege?).
Which version of Duende IdentityServer are you using? The demo hosted at https://demo.duendesoftware.com
Which version of .NET are you using? Framework v4.8
Describe the bug My employer is planning to upgrade from IdentityServer3 to IdentityServer4. In preparation I have taken our oldest product which is a .Net aspx Web Forms project and using the published WebForms sample (https://github.com/duendesoftware/samples) as a guide tried to authenticate against the demo IdentityServer4. When I browse to our product I'm redirected to the demo.duendesoftware.com login in screen which is fine, but after logging in as bob/bob or alice/alice and being redirected back to my application .Net seems to think I'm still not authenticated. The request identity has an empty name claim and nothing further. Anyway, I land up in that annoying eternal ping pong between my RP and the demo IDP until the headers grow too big. Taking a few steps back, I've created a brand new empty Web Forms project and tried using what is in the published demo to make it authenticate against the demo IdentityServer4 but I get the exact same ping pong result. The actual Web Forms sample from https://github.com/duendesoftware/samples works fine though and I log in and the claims are displayed as expected. I've scanned through every file in the two folders using WinMerge but I cannot spot what I might have missed. I have the same code in my Startup.cs and nothing in the web.config or global.asax or .csproj would explain the different behaviour. Clearly I'm missing an important step in securing it but I don't know what that is. Could you possibly document and publish the individual steps you took to secure this Web Forms project against https://demo.duendesoftware.com? That would be very useful for customers like us with existing projects we want to secure against it.
To Reproduce
Please see above.
Expected behavior
I'd like to know what steps were taken to secure the Web Forms project rather than just have the result.
Log output/exception with stacktrace
Additional context