Identity Server: redirect after logout with WS Federation - identityserver3

I try to redirect user after logout from Identity Server to my client app.
I use next code for identity server setup:
RelyingParties = (from RelyingPartyElement element in section.RelyingParties
select new RelyingParty()
{
PostLogoutRedirectUris = new List<string>()
{
"http://localhost:xxx"
},
Also, signOutReply param has been set to "http://localhost:xxx/" for ws federation section.
But it is not enough for redirect user after sign out.
What i need to do for achive goals, described above?

Did you try this? You would need to add Owin Extensions and point to signout
https://identityserver.github.io/Documentation/docsv2/advanced/federated-signout.html

Related

IdentityServer4 how to redirect the flow after login

I have installed an IdentityServer4 and a Client (Hybrid Mvc Client). All is ok. The following flow works:
1. User call secure page PageX (the controller is protected with Authorize attribute)
2. than system redirects the flow to Login page on IdentityServer
3. After authentication/authorization the IdentityServer redirect the user to url defined (redirect_uri) in the client configuration (page named Home) .
Now i don't know how to implement at the step 3 the redirection to PageX, the original page requested.
I have to create a custom AuthorizeAttribute to save on session storage the url of PageX and than using it in callback page? or is there any configuration on IdentityServer or client that could help me?
Thanks in advance
This is typically what you’d use the state parameter for. Your callback will receive the state value back unaltered and then you can verify the URL within is local and redirect to it automatically.
I’d recommend protecting the value from tampering using the DataProtection features in .net.
After successful login, by default the IdentityServer middleware tries to redirect to a consent page where to inform the user for the "allowed scopes". In this page are shown the claims that the client mvc site will receive access to: user identifier, user profile, email etc.
If you didn't setup such, you may set: "RequireConsent = false" when you define your MVC client. In such scenario the IdentityServer will redirect back to "RedirectUris" without showing consent page.
Example:
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "mvc",
ClientName = "mvc Client",
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
},
RequireConsent = false
}
};
}
The other thing that I've noticed in the IdentityServer4 demos and quick starts is that you need the following NuGet packages:
For client website:
IdentityModel,
Microsoft.AspNetCore.All
For IdentityServer Authentication app:
IdentityServer4,
IdentityServer4.AccessTokenValidation,
IdentityServer4.AspNetIdentity,
Microsoft.AspNetCore.All
You may install these packages just to get the demo working.

Keycloak - direct user link registration

I have set up a web application with Keycloak in my local machine. Since Im using Keycloak as SSO implementation, I want in my web app that whenever SIGNUP button is click, user is directed into the registration page, and not going through the LOGIN page.
This is the example URL directed to the registration form, however, it contains a tab_id that is generated randomly like a session id.
https://site.test/auth/realms/custom/login-actions/authenticate?client_id=test&tab_id=qIdW92Bvwmk
I read about this link
Yes, as long as you use the "registrations" instead of "auth" in the
end of login ( AuthorizationEndpoint ) URL
But my endpoint in https://site.test/auth/realms/custom/.well-known/openid-configuration cannot be modified.
You can change the button link to this format -
http://<domain.com>/auth/realms/<realm-name>/protocol/openid-connect/registrations?client_id=<client_id>&response_type=code&scope=openid email&redirect_uri=http://<domain.com>/<redirect-path>&kc_locale=<two-digit-lang-code>
The registration page is exposed via an openid-connect endpoint, accessible in the same way as the standard auth screen. To construct the correct URL you can simply replace openid-connect/auth in the URL with openid-connect/registrations from the .well-known auth endpoint.
authEndpoint.replace("openid-connect/auth","openid-connect/registrations");
Using this endpoint the user will be directed to the registration screen instead of the login screen.
It is not documented or exposed via .well-known/openid-configuration, but you can see it in the source code:
public static UriBuilder registrationsUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(OIDCLoginProtocolService.class, "registrations");
}
For Keycloak 17 this worked for me:
http://<mykeycloakdomain.com>/realms//protocol/openid-connect/registrations?client_id=<myclient_id>&response_type=code&scope=openid+email&redirect_uri=https%3A%2F%2Fmywebsiteurl.com&kc_locale=

IdentityServer SSO - Trusted application

I need to SSO (single sign on) a user coming from an application of mine (identity provider using ASPNET Session State) and redirect them to another application of mine (service provider) that is configured to use implicit flow with IdentityServer4. I need to achieve this without requiring the user to log back in and without providing the user's password.
My initial thought was that I could use a client secret for the identity provider to redirect the user to the IdentityServer4 authentication end point with the access token as a query parameter and then use a custom validator or extension grant to issue an identity token for use with the service provider application without needing to also provide the user's password.
I've managed to issue an access token to the identity provider and then redirect the user to IdentityServer4, but issuing an identity token has proven difficult for me. I've poured over the samples and documentation and I'm confused to say the least.
I'm looking for direction on the appropriate approach to this scenario and perhaps a comprehensive example in C#. I've come to understand I can use a hybrid flow to issue an access token as well as an identity token. I think my biggest struggle is how to redirect the user and, based on the access token, issue the user an identity token (and if this is even an acceptable approach).
Simply put: I'd like to redirect the user from Application A to IdentityServer4 to Application B based on trust with the identity provider (via client secret?).
Note: I understand this could be considered an opinion-based question, but based on my research I believe there is one single best practice and that's what I'm asking for.
I managed to get this working by the following flow:
Authorize the user in Application A (Identity Provider)
Obtain Access Token from Identity Server 4 via Token Endpoint and shared secret.
Add access token as a query string parameter since headers are not preserved on redirect.
Redirect the user to an Account controller method that accepts identifying information such as username. This method is protected by a custom middleware class that checks the query string for an access token parameter. If the token exists, it is added to the authentication header; this authorizes the user to hit this controller method.
The controller method will then sign the user in and redirect them to the /connect/authorize/login endpoint.
Finally, the login endpoint sets the cookie and redirects the user to Application B (Service Provider), whose URL is specified via the redirect_uri query parameter.
Configuration for shared secret:
Add appropriate grant type, secret and new scope name to the client. The new scope will help in debugging Access token issues in your logs (especially if you have multiple applications hitting your ID4 server). Also make sure to add the Service Provider's URL to the client RedirectUris, otherwise you'll receive an "invalid redirect" error.
AllowedGrantTypes = new List<string> { GrantType.Implicit, GrantType.ClientCredentials },
ClientSecrets = new List<Secret> {
new Secret(_clientSecrets.ExternalIdpSecret.Sha256(), clientID)
},
AllowedScopes = new List<string>
{
"newScopeName"
},
RedirectUris = new List<string>
{
$"http://localhost:<portnumber>"
}
Next, add your custom middleware.
public class QueryStringOAuthBearerMiddleware
{
private readonly RequestDelegate next;
public QueryStringOAuthBearerMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
this.BeginInvoke(context);
await this.next.Invoke(context);
this.EndInvoke(context);
}
private void BeginInvoke(HttpContext context)
{
if (context.Request.Query.ContainsKey("accesstokenparametername"))
{
var accessToken = context.Request.Query.First(p => p.Key == "accesstokenparametername");
if (!string.IsNullOrEmpty(accessToken.Value))
{
context.Request.Headers.Add("Authorization", "Bearer " + accessToken.Value);
}
}
}
private void EndInvoke(HttpContext context)
{
}
}
And add the middleware to your configuration.
app.UseMiddleware<QueryStringOAuthBearerMiddleware>();
Create your login method.
[HttpGet]
[Authorize]
public async Task<IActionResult> Login2(string userName, string returnURL)
{
await _httpContextWrapper.SignInAsync(userName);
return Redirect(returnURL);
}
Configuration for Client application (IDP):
Your client side code should look like this:
var disco = await DiscoveryClient.GetAsync("http://localhost:<portnumber>");
var tokenClient = new TokenClient(disco.TokenEndpoint, "clientIdentifier", "IUsedAGuidHere");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("newScopeName");
var redirectURL = string.Format("http://localhost:2228/account/Login2?userName=<UserIDValue>&returnURL={1}&accesstokenparametername={0}",
tokenResponse.AccessToken,
Server.UrlEncode(
string.Format("/connect/authorize/login?client_id={3}&redirect_uri={2}&response_type=id_token%20token&scope=<ImplicitFlowScopes>&state={0}&nonce={1}",
CryptoRandom.CreateUniqueId(),
CryptoRandom.CreateUniqueId(),
Server.UrlEncode("http://localhost:<PortNumber>"),
"ClientIdentifier")));
Response.Redirect(redirectURL, false);
Note: Please understand you won't be able to take this code AS-IS and make it work. I've heavily modified it to protect the security of my resources.
I think I might take care of the Authentication with Application A first, then forward on to the next app...
Application A --> IdentityServer --> Application A --> Application B.
You could include some custom parameters in your returnUrl which Application A could read upon return from IdentityServer that would trigger the redirect to Application B.

Where to handle app initialization in SSO situation?

I have App1 and App2, doing SSO using IdentityServer3 with Active Directory.
Each app has its own users and roles. I created a ClaimsTransformation OWIN middleware, get user/roles, serialize into cookie, then bring back on subsequent calls. That works well.
But where do I handle initial user enroll? I can't do it in authentication, because if an App1 user logon, then go to App2 as new, he will skip authentication.
If I do this in the middleware, when I try redirect user to enroll/profile page, that redirect is hit by the middleware again, causing a redirect loop.
Any suggestions? Thanks.
Never mind, did it all wrong. For .NET using Owin.Security.OpenIdConnect, App initialization should be done in SecurityTokenValidated. The skipping authentication issue was because I didn't set cookie name.
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOption
{
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotification
{
SecurityTokenValidated = n => { ... }

Thinktecture IdentityServer3 Facebook Login Button Issue

I am using "IdentityServer3 - IdentityManager - MembershipReboot" in my project for User Management, Authentication & Resources Authorization.
I started from below sample and have gone good for creating users, authenticating them via /connect/token api and authorizing resources.
https://github.com/thinktecture/Thinktecture.IdentityServer.v3.Samples/tree/master/source/MembershipReboot
A brief architecture for my solution is
MySql as database. Communication via MembershipReboot.EF to MembershipReboot.
The client project is developed using html + angularjs.
Resources APIs are developed using Nancy & hosted on Owin+Katana in a seperate project.
Authentication Services(IdSvr+IdMgr+MR) are hosted in a seperate project.
Now I want to create a simple button/link clicking on which leads me to facebook login. The functionality of this button should be same as defined in IDSvr default login page's(https://localhost:44333/core/login?signin=4f909a877cc465afd26d72f60ec08f51) "Facebook button".
I have tried googled internet a lot but none of cases are matching my scenario.
I even tried to replicate the request-response behaviour of default IdSvr facebook login but that does not work as cookies are not being saved on end client.
Also i tried to hit "https://localhost:44333/core/signin-facebook" and getting response as HTTP/1.1 500 Internal Server Error from server. So i think might be I am somewhere wrong in setting facebook options in IdSrv project.
So if someone can just provide me a single IdSvr API to connect or tell me how to config Id Svr so that mapping a url can redirect it to facebook login. Or can tell me that where I am wrong in setting facebook authentication options in IdSrv.
A short and simple answer for my question is that I was looking for url.
https://localhost:44333/connect/authorize?client_id=implicitclient&response_type=token&scope=read&redirect_uri=http://localhost:8088/login/auth&nonce=random_nonce&acr_values=idp%3AFacebook&response_mode=form_post
Read further if you want to get better idea about this url
After lots of Hit&Trial & Study efforts, I have got solution for this. Well I think root cause for this problem was that sudden new technical things(Owin, Katana, OAuth, IdentityServer, IdentityManagement, MembershipReboot, Owin Facebook) and a meager time to understand them all.
I would advice folks that whoever is in same situation as me then first get an idea about OAuth. I found below link as a short and good one.
http://tutorials.jenkov.com/oauth2/index.html
After this I learnt that in our scenario we are dealing with two applications and hence two authentication.
For connecting User to Facebook. We created an app on developers.facebook.com
For connecting User to IdentityServer. We created a client in Clients.cs file on AuthenticationServices project.
So now here is the final solution.
localhost:44333 where AuthenticationService is running
locahost:8088 where FrontEnd services are running which iscalling AuthenticationService .
1. Create client app in AuthenticationServices as below
new Client
{
ClientName = "Implicit Clients",
Enabled = true,
ClientId = "implicitclient",
ClientSecrets = new List<ClientSecret>{
new ClientSecret("secret".Sha256())
},
Flow = Flows.Implicit,
RequireConsent = true,
AllowRememberConsent = true,
RedirectUris = new List<string>
{
"http://localhost:8088/login/auth" //This should be redirect url you want to hit after your app(not facebook app) redirects.
},
ScopeRestrictions = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
"read",
"write",
},
//SubjectType = SubjectTypes.Global,
AccessTokenType = AccessTokenType.Jwt,
IdentityTokenLifetime = 360,
AccessTokenLifetime = 360,
},
2 Create Authorize URL as below
var client = new OAuth2Client(new Uri("https://localhost:44333/core/connect/authorize"));
var startUrl = client.CreateAuthorizeUrl(
clientId: "implicitclient",
responseType: "token",
scope: "read",
redirectUri: "http://localhost:8088/login/auth",
nonce: "random_nonce",
responseMode: "form_post",
acrValues: "idp:Facebook");
The facebook app after successful authorization will redirect default to http://localhost:44333/signin-facebook. So no need to do any changes there.
Finally on http://localhost:8088/login/auth you will get access_token(+ few other parameters) after successful authentication. Here onwards you can use this token to access resources from Resources server.