NullReferenceException on Bootstraptoken (ACS authentication) - windows-8

I've been following the steps to make a Windows 8 Store app get an ACS token as described here:
Does the WebAuthenticationBroker work in Windows 8 Metro App post Release Candidate
Authentication method of Windows 8 client
private async void Authenticate()
{
WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.None,
new Uri("https://myACSnamespace.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http://localhost:12714/"),
new Uri("http://mypublicIPaddress:80/WebAppMVCAPI/api/federation/end"));
My controller on the web application is programmed as follows:
public class FederationController : ApiController
{
protected virtual string ExtractBootstrapToken()
{
return HttpContext.Current.User.BootstrapToken();
}
[HttpGet]
public string Get()
{
return "Hello Get World";
}
[HttpPost]
public HttpResponseMessage Post()
{
var response = this.Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Add("Location", "/WebAppMVCAPI/api/federation/end?acsToken=" + ExtractBootstrapToken());
return response;
}
}
}
The idea is to have the Windows 8 store app get a token from ACS with a Facebook login. When I launch the win8 client, the application shows a Facebook login page. However, the instruction return HttpContext.Current.User.Bootstraptoken() fails with the following exception:
NullReferenceException. Object reference not set to an instance of an object.
My web.config looks like this:
<microsoft.identityModel>
<service saveBootstrapTokens="true">
<audienceUris>
<add value="http://localhost:80" />
</audienceUris>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="https://bondsapp.accesscontrol.windows.net/v2/wsfederation" realm="http://localhost:80/" reply="http://localhost:80/" requireHttps="false" />
<cookieHandler requireSsl="false" path="/" />
</federatedAuthentication>
<issuerNameRegistry type="Microsoft.IdentityModel.Swt.SwtIssuerNameRegistry, Wif.Swt">
<trustedIssuers>
<add name="https://bondsapp.accesscontrol.windows.net/" thumbprint="xxxxx" />
</trustedIssuers>
</issuerNameRegistry>
<securityTokenHandlers>
<add type="Microsoft.IdentityModel.Swt.SwtSecurityTokenHandler, Wif.Swt" />
</securityTokenHandlers>
<issuerTokenResolver type="Microsoft.IdentityModel.Swt.SwtIssuerTokenResolver, Wif.Swt" />
</service>
Can somebody shed some light on how to use the Bootstraptoken method to get an ACS token?
Thanks
Luis

I don't believe that federated authentication sets HttpContext.User by default. Try
(Thread.CurrentPrincipal as IClaimsPrincipal).Identities[0].BootstrapToken
Assuming that you've gone through the token handler pipeline (WS-FAM) at your site, this should be populated. This will be a SecurityToken object, which you can then serialize using the proper SecurityTokenHandler class.

Did you try this :
BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
SecurityToken st = bootstrapContext.SecurityToken;
Take a look on Vittorio's post:
http://blogs.msdn.com/b/vbertocci/archive/2012/11/30/using-the-bootstrapcontext-property-in-net-4-5.aspx

Related

Serilog : creating Multiple log files when calling a wcf service

I have serilog parameters described in web.config as below:
<appSettings>
<add key="serilog:minimum-level" value="Debug" />
<add key="serilog:using:RollingFile" value="Serilog.Sinks.RollingFile" />
<add key="serilog:write-to:File.rollingInterval" value="Day"/>
<add key="serilog:write-to:RollingFile.pathFormat" value="c:\temp\log.txt" />
</appSettings>
In my wcf service, code is as below
public class CalculateService : ICalculateService
{
private Logger _logger;
public CalculateService()
{
_logger = new LoggerConfiguration()
.ReadFrom.AppSettings()
.CreateLogger();
_logger.Debug("calling constructor");
}
}
When I'm calling this service from the Console application, a separate log file is created each time. I want to initialize log only once and want to create a new log file each day.

Windows-authentication MVC app with Claims, Authenticate called multiple times and looses Security Token cookie

I'm developing Windows-authentication claims-based MVC application. I've implemented the IHttpModule (aka "ClaimsTransformation Module", which interceps the Identity) and custom ClaimsAuthenticationManager (which adds additional claims to this identity), as shown below. Page loads, and I can retrieve newly added claim, but there few serious issues...
The problems are:
Even on initial page load my custom RomesClaimsAuthenticationManager.Authenticate method gets called 27+ times (I assume some calls are parrallel/async).
The FedAuth (SessionToken) cookie check never returns true, even though right after SAM (SessionAuthenticationManager) writes SesstionToken to cookie - I can see it, but at the next call (still during original page load) it's gone - same thing happens if I open other pages.
public class RomesClaimsAuthorizationModule : IHttpModule, IDisposable
{
public void Init(System.Web.HttpApplication application)
{
// intercept PostAuthenticationRequest to add custom logic
application.PostAuthenticateRequest += TransformPrincipal;
}
private static void TransformPrincipal(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
// PROBLEM HERE - this is always false, even after cookie has been set
// check if cookie with auth info about curr user already exists
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
else
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// this will pick up our custom Romes.Adminn.Security.RomesClaimsAuthenticationManager
// it is specified in web.config, so our app will use it as default
// which will add our custom additional claims to our principal
var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
if (transformer != null)
{
var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);
// generate cookie
SessionSecurityToken sst = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
sst.IsReferenceMode = true; // used when there are a lot of claims - will be faster
sst.IsPersistent = true;
// write cookie to session
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sst);
// write to context
context.User = transformedPrincipal;
Thread.CurrentPrincipal = transformedPrincipal;
}
}
}
}
}
Custom ClaimsAuthenticationManager:
public class RomesClaimsAuthenticationManager : ClaimsAuthenticationManager
{
// PROBLEM - THIS GETS HIT 27+ times on original page load
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
{
((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Email, "myTestEmail#email.com"));
// i will be making a db call here to get add'l user info from DB, and then convert it into claims
}
return incomingPrincipal;
}
}
Web.config file:
<configSections>
<!--this is required for custom ClaimsAuthorizationManager-->
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<!--this will allow us to write ClaimsPrincipal to a cookie, saving from calls to db on each request-->
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
...
<system.identityModel>
<identityConfiguration>
<claimsAuthenticationManager type="ROMES.Admin.Security.RomesClaimsAuthenticationManager, ROMES.Admin" />
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler mode="Default" requireSsl="true" />
</federationConfiguration>
</system.identityModel.services>
<system.web>
<authentication mode="Windows"/>
...
<authorization>
<allow roles="WINDOWS\ROMES_Admins"/>
<deny users="*" />
</authorization>
<!--must be in both here and system.webServer/modules-->
<!--see here WHY: https://msdn.microsoft.com/en-us/library/gg638734.aspx-->
<httpModules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</httpModules>
</system.web>
<system.webServer>
<!-- same as in system.web/httpModules-->
<modules>
<add name="RomesClaimsAuthorizationModule" type="ROMES.Admin.Security.RomesClaimsAuthorizationModule"/>
<!--this module will handle reading and writing cookie for identity/claims - so that there will be no need to call db every request for user info-->
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</modules>
...
</system.webServer>
My main issues are:
(1) why is my Authenticate block gets called so many times and
(2) Why is Session Security Token cookie does not persist - seems like such a waste of resources.
In here
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies)
change to
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookie)
and see if the condition started to be true and your code returns.
EDITED after David's comment: context replaced with context.Request.Cookie

WebSecurity.InitializeDatabaseConnection fails with "The Role Manager feature has not been enabled." when called from console program

I have a MVC4 application using SimpleMembership to authenticate users.
I want to add users from a console program.
The console program that references a class library that has the method that will do the user creation.
It looks like this:
public class UserBuilder
{
private static readonly SimpleMembershipInitializer _membershipInitializer;
private static readonly bool _isInitialized;
private static readonly object _initializerLock = new object();
static UserBuilder()
{
LazyInitializer.EnsureInitialized(ref _membershipInitializer, ref _isInitialized, ref _initializerLock);
}
public void HandleEvent(UserAdded #event)
{
if (!WebSecurity.UserExists("ReportModels"))
{
WebSecurity.CreateUserAndAccount("ReportModels", "ReportModels");
};
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
}
}
When I start my console application I get System.Configuration.Provider.ProviderException {"The Role Manager feature has not been enabled."} at the line starting with WebSecurity.InitializeDatabaseConnection.
What do I need to do to accomplish this?
I've tried:
adding the nuget package Microsoft ASP.NET Web Pages 2 Web Data to both the console project and the class library project.
the answers listed in this post: SimpleMembershipProvider not working.
verified the connection string.
verified that the tables are in place in the database.
verified that creating users and authenticating them from the MVC4 project works.
Finally solved it thanks to information found in this blog post: http://insomniacgeek.com/to-call-this-method-the-membership-provider-property-must-be-an-instance-of-extendedmembershipprovider/ and some googling.
In essence I needed to add this to my app.config file:
<system.web>
<profile defaultProvider="SimpleProfileProvider">
<providers>
<add name="SimpleProfileProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData"
connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<roleManager defaultProvider="SimpleRoleProvider" enabled="true">
<providers>
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
</providers>
</roleManager>
</system.web>
Please note the enabled="true" on the roleManager element. Without that the same exception will be thrown.

User can successfully log in but log in page shows up instead of redirecting

I have a moved a project from asp.net mvc 2 to asp.net 4 and after a bit of fixing everything seemed to work.
EXCEPT for the parts of the app where you have to authorize. Without authorizing it is possible to view non-authorize pages but as soon as you try to log-in everything goes
bananas. When you log-in you get logged in (you see your name in the log-in partial) but not redirected and prompted to log-in again and you can not reach parts of the
app that is for non-authorized users. Everything works on localhost but not at deployed site.
At first i thought there was a problem with my machinekey and app-pool recykling, so i added one. Still same problem.
I know that MVC uses websecurity instead of membership but i've read that an Membership solution can exist in a mvc 4 project, and i would be glad to use my custom membershipprovider and roleprovider and save some time if it is possible.
Controller:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, true);
FormsAuthentication.SetAuthCookie(model.UserName, true);
var role = userRepo.usersInRoles.First(x => x.userMail == model.UserName);
if (role.roleName == "Business")
return RedirectToAction("Start", "Business");
if (role.roleName == "Admin")
return RedirectToAction("Index", "Admin");
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
return View(model);
}
Config settings for Membership & Role
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
<membership defaultProvider="AccountMembershipProvider">
<providers>
<clear />
<add name="AccountMembershipProvider" type="MyApp.UI.Infrastructure.AccountMembershipProvider" applicationName="/" />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="RoleMembershipProvider">
<providers>
<clear />
<add name="RoleMembershipProvider" type="MyApp.UI.Infrastructure.RoleMembershipProvider" />

Accessing Authentication variable from LogoutHandler or LogoutFilter in Spring security

In one of my project I have configured Spring Security to handle user authentication.
My config file looks like this:
<http use-expressions="true">
<intercept-url pattern="/" access="permitAll()" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login default-target-url="/main" login-page="/" always-use-default-target="true" username-parameter="userId" password-parameter="password" />
<custom-filter ref="customLogoutFilter" position="LOGOUT_FILTER"/-->
<session-management invalid-session-url="/" session-authentication-strategy-ref="sas" />
</http>
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
<beans:bean id="customLogoutHandler" class="com.somepack.CustomLogoutHandler"/>
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg index="0" ref="customLogoutHandler"/>
<beans:constructor-arg index="1" ref="customLogoutFilter"/>
<beans:property name="filterProcessesUrl" value="/"/>
</beans:bean>
<beans:bean id="customLogoutFilter" class="com.somepack.CustomLogoutFilter">
<beans:property name="reportDir" value="/tmp/reports"/>
</beans:bean>
My CustomLogoutFilter class looks like
public class CustomLogoutFilter implements LogoutHandler {
private String reportDir;
public String getReportDir() {
return reportDir;
}
public void setReportDir(String reportDir) {
this.reportDir = reportDir;
}
#Override
public void logout(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) {
String userName = authentication.getName();
File folder = new File(reportDir, userName);
deleteDir(folder); //delete function to delete Logged User specific directory
logService.info("Logout", userName, EventCode.LOGOUT,
String.format("User %s logged out successfully", userName));
for (Cookie cookie : request.getCookies()) {
printcookies(cookie);
if (cookie.equals("JSESSIONID")) {
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
request.getSession().invalidate();
}
}
But this piece of code is not working as the filter is getting called at the very first request for the Login page (even it may would get called in every request) and I am getting an NullPointerException in the
String userName = authentication.getName() line.
In fact instead of Using LogoutFilter if I use Logouthandler, I get the same error:
My handler looks like this:
public class CustomLogoutHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler{
private String reportDir;
public String getReportDir() {
return reportDir;
}
public void setReportDir(String reportDir) {
this.reportDir = reportDir;
}
#Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
String userName = authentication.getName();
File folder = new File(reportDir, userName);
deleteDir(folder);
logService.info("Logout", userName, EventCode.LOGOUT, String.format("User %s logged out successfully", userName));
super.handle(request, response, authentication);
}
and config file changed to:
<http use-expressions="true">
<intercept-url pattern="/" access="permitAll()" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login default-target-url="/main" login-page="/" always-use-default-target="true" username-parameter="userId" password-parameter="password" />
<logout delete-cookies="JSESSIONID" invalidate-session="true" success-handler-ref="customLogoutHandler" logout-url="/logout" />
<session-management invalid-session-url="/" session-authentication-strategy-ref="sas" />
</http>
<beans:bean id="customLogoutHandler" class="sequent.ui.security.CustomLogoutHandler">
<beans:property name="reportDir" value="/tmp/reports" />
</beans:bean>
Not sure how can I resolve this issue.
Please help.
In short my basic requirement is that, I need to access the User Principal in the Logout mechanism which triggered when either User clicks on the Logout button or the session expires. I need the User information because the application creates temporary folder in the name of logged user which I need to delete at the time when he log off.
Appreciate your help please!!
-Raul
You have set the filerProcessesUrl of the LogoutFilter to "/" which means that every time a user browses to the domain root, the filter will attempt to logout the user. Use a specific logout URL (or the default value) and check whether the user is actually authenticated before you try to do a logout (make sure the Authentication instance isn't null).
If you need to deal with session timeouts, where the user fails to logout, then you will also have to implement an HttpSessionListener which identifies the user from the session and performs whatever clean-up you need. This would be added to your web.xml file. Note that this class isn't invoked during a user request, so you can't use the SecurityContext to obtain information about the user, you must get it from the session object which is passed to the listener before the session is invalidated.