I've built a web application. When I built it I ticked 'Organizational Accounts'
It works well - I log in with my Office 365 account and User.Identity.Name
contains the email address
This application is a replacement front end for an older ASP Classic app. The App has an existing security table that I need to use.
I want to use the email address to look up a record in this table to get
The internal database key for the user (so I can use it in database calls)
The security level (authorisation) for the user
I want to look this up as soon as I am authenticated and save these two values to Session
to refer to later
I have an existing method that does all of this lookup and caching. I actually got it working by calling it from the _LoginPartial.cshtml
view but clearly it is incorrect to be triggering this kind of thing from a view
Here's the code to look up and cache user info. For now this is in AccountController.cs
but it doesn't have to be
private Boolean GetAdditionalUserInfo()
{
// if authentication info is saved, don't go find it
if (Session["UID"] != null) return true;
// get the db employee id from the database and save it to the session
var r = (
from e in db.Employees
where e.Email == User.Identity.Name
select new
{
e.Emp_ID,
e.Group_ID
}
).SingleOrDefault();
if ((r == null) || (r.Group_ID == (int)Role.Inactive))
{
// couldn't find record or inactive
return false;
}
// Update last login datetime
Employee ell = db.Employees.Find(r.Emp_ID);
ell.LastLogin = DateTime.Now;
db.SaveChangesAsync();
// Save user details to the session
Session["UID"] = r.Emp_ID;
// TBD: Investigate "CLAIMS" - this should probably be a claim
Session["Role"] = r.Group_ID;
return true;
}
I think the reference to User.Identity.Name
triggers the login process so I could either just try and call this at startup (I don't know the correct way to do this), or I think the proper thing to do is to call this using the OnAuthentication
method, and to link it up I should pass the name of my function to the OnAuthenticated
property. Here's two links to the method and property:
https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.onauthentication(v=vs.118).aspx
https://msdn.microsoft.com/en-us/library/microsoft.owin.security.microsoftaccount.microsoftaccountauthenticationprovider.onauthenticated(v=vs.113).aspx
But I have to say that OO programming is not my thing and I can't work out from these pages how to use them or which class to put them into.
This page implies it needs to go into Startup.Auth.cs
but my Startup.Auth.cs
looks nothing like that one. Here is most of my Startup.Auth.cs
which was mostly autogenerated when I ticked 'organisational' at the start. (On a side note, app.UseKentorOwinCookieSaver();
is my next challenge because apparently organisational login doesn't work with Session
can you believe it!!!)
Can anyone help me add required code to call GetAdditionalUserInfo()
? after login? Or alternatively confirm that I can just call this at startup, and suggest the correct way to do it.
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
//private static string authority = aadInstance + tenantId;
// to make this multi tenant, use common endpoint, not the tenant specific endpoint
private static string authority = aadInstance + "common";
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(
CookieAuthenticationDefaults.AuthenticationType);
// https://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(
new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
TokenValidationParameters = new TokenValidationParameters
{
// If you don't add this, you get IDX10205
// from here http://charliedigital.com/2015/03/14/adding-support-for-azure-ad-login-o365-to-mvc-apps/
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = ctx =>
{
bool isAjaxRequest = (ctx.Request.Headers != null && ctx.Request.Headers["X-Requested-With"] == "XMLHttpRequest");
if (isAjaxRequest)
{
ctx.Response.Headers.Remove("Set-Cookie");
ctx.State = NotificationResultState.HandledResponse;
}
return System.Threading.Tasks.Task.FromResult(0);
}
}
});
}
}
In article The OWIN OpenID Connect Middleware you can find detailed explanation how you could use Notifications
. In you case you should subscribe to SecurityTokenValidated
:
RedirectToIdentityProvider = ctx => {...},
SecurityTokenValidated = (context) =>
{
string userID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
// Here you can retrieve information from Database. Let's say you get r.Group_ID.
var role = r.Group_ID;
// You can now add it to Identity and no need to use session.
Claim roleClaim = new Claim(
"http://nomatterwhatyouput/role",
role,
ClaimValueTypes.[RoleType],
"LocalAuthority");
context.AuthenticationTicket.Identity.AddClaim(roleClaim);
// Do same for all values you have. Remember to set unique claim URL for each value.
return Task.CompletedTask;
},
And then you can retrieve those values in you actions as mentioned in that article:
public ActionResult Index()
{
var role = ClaimsPrincipal.Current.FindFirst("http://nomatterwhatyouput/role");
return View();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With