https://docs.developers.optimizely.com/content-management-system/docs/mixed-mode-authentication#synchronize-users-and-roles-from-an-external-authentication-provider
This legacy SSO, does it send a user to you as a token or how do you retreive it, headers?
OWIN is a standardized way to handle requests and responses in .net framework, there are many ways to implement middlewares that does the same thing in .net core. Assuming you can intercept the request and fetch the user in a middleware all you need to do is to ensure you can log that user in?
Thank you Eric for your response and inquiry. Our SSO does send a token via encrypted query string param, and with it w create an ApplicationUser object. Whether I use ApplicationUser or something else, I should have the user info I need. It is from there that I am unsure how to proceed.
I have looked at the mix-mode document Mark mentioned numerous times, and had previously settled on attempting to use the section he suggested. But there is certainly more to it. Is this your suggested approach as well?
From my understanding, there are two places I need to address: the Startup.ConfigureServices and the login/logout controller.
Regarding Startup: If I am using the example's AddOpenIdConnect(), the options definition are incomplete. What else will I need? Or do you have a different suggestion?
Regarding the controller: If using OIDC, I assume I add "[Authorize(AuthenticationSchemes = "oidc")]", but what do I need to complete the actual login? It is here I was using OWIN.
Thanks!
You cannot use OpenID, assuming I've understood your stack you'll need to implement ASP.NET Core Identity and find a way to sign in users using a middleware. The aspnet core identity serves as a backbone to handle your users, you will also need to sync the users to opti cms using the ISynchronizingUserService.
I'll dig a bit in my projects and see if I can find something useful.
To just sign in a user you don't have to do much:
var claims = new List<Claim>
{
new Claim("name", "user@example.com")
};
var identity = new ClaimsIdentity(claims, "yada", "name", "role");
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync("your-scheme", principal);
But you probably would want to implement this as a RemoteAuthenticationHandler<TOptions>
or AuthenticationHandler<TOptions>
.
Thanks Johan for the info. When I take what you suggested and combine it with what was already in our project, I arrived at the following
Startup.cs:
services
.AddAuthentication()
.AddCookie("opti-scheme")
.AddCookie("sso-scheme");
The code where I am authenticating looks like:
// use SSO data to identify/create an ApplicationUser
var appUser = GetAppUser(ssoUser);
if (appUser != null)
{
AddClaim(appUser, "user_id", ssoUser.CustomerId);
AddClaim(appUser, "firstname", ssoUser.FirstName);
AddClaim(appUser, "lastname", ssoUser.LastName);
AddClaim(appUser, "email", ssoUser.Email);
if (ssoUser.MemberGroups != null && ssoUser.MemberGroups.Length > 0)
{
SyncRoles(ssoUser.CustomerId, ssoUser.MemberGroups);
SyncVisitorGroups(ssoUser.MemberGroups.ToArray());
}
var claims = _userManager.GetClaimsAsync(appUser).GetAwaiter().GetResult();
var claimsIdentity = new ClaimsIdentity(claims, "ApplicationCookie");
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
var authProps = new AuthenticationProperties { IsPersistent = false };
_httpContext.SignInAsync("sso-scheme", claimsPrincipal, authProps).GetAwaiter().GetResult();
}
private void AddClaim(ApplicationUser appUser, string claimName, string claimVal)
{
var claim = _userManager.GetClaimsAsync(appUser).GetAwaiter().GetResult().FirstOrDefault(x => x.Type == claimName);
if (claim != null)
_userManager.RemoveClaimAsync(appUser, claim).GetAwaiter().GetResult();
_userManager.AddClaimAsync(appUser, new Claim(claimName, claimVal)).GetAwaiter().GetResult();
}
Since SignInAsync() doesn't seem to return any value, how do I know if the user is authenticated? Does PrincipalInfo.CurrentPrincipal come into play at all? For reference, in CMS-11 we used AuthenticationManager with Owin:
// sign-in code from CMS-11
public void SignIn(ApplicationUser user, bool isPersistent = false)
{
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = _userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, identity);
}
I am still missing something. Any help would be greatly appreciated!
Thanks, Kevin
Since SignInAsync() doesn't seem to return any value, how do I know if the user is authenticated?
When you're calling "SignInAsync" it means the user has already been authenticated, and the method just creates authenticate ticket along side the cookie. What value do you expect to return from this method?
If I understand your current situation correctly, you have a legacy app (auth server) that allows to user to be authenticated then redirect to your opti site with a encrypted token in querystring contains user info. The code snippet your shared above with GetAppUser function, at this step, since you have received token, I assume it means the user is already authenticated. If that's not the case, how does your business want to handle the next step? E.g. redirect user to an error page?
Doesn't following code check if the user is authenticated?
var appUser = GetAppUser(ssoUser);
if (appUser != null) { }
Sign in, as Vincent wrote, creates an authentication ticket and persists it in a cookie (the 'sso-scheme' cookie), to keep the user signed in between page loads.
Hello all,
I am in the progress of migration from CMS11 to 12. Our customer-facing site login utilizes a custom-built legacy site as a SSO, which we need to keep to authenticate. The CMS11 site uses Owin to take the resulting auth info to login to our Opti-based site. If the user doesn't exist in Opti, it creates it. The login is primarily used for Opti personalization and wields no power.
In CMS12, since Owin is no longer available, I need to come up with another solution for login. I will shamefully admit that I am green in OAuth, and auth in general. After much research, I cannot find a simple solution to this. I see many complex examples with OpenID Connect, but it typically describes connecting with Azure AD or some other 3rd party systems, but nothing custom.
Keeping in mind that our need is Opti personalization, can anyone point me to a tutorial/example/code for CMS12?
Help me Obi-Wan, you're my only hope!
Thanks!