2
votes

I am trying to create an ASP.NET MVC site that has specific areas protected by Windows Azure ACS. I want the default area to be unprotected (i.e. allow anonymous users) but only the sub areas to be protected.

I have made this happen by removing the authorization element from the system.web section in my Web.config.

<authorization>
     <deny users="?" />
</authorization>

Then adding a protected location for the desired MVC3 area.

<location path="MyArea">
    <system.web>
        <authorization>
            <deny users="?" />
        </authorization>
    </system.web>
</location>

However, my old code that used to access the IClaimsIdentity and pull attributes off it for processing used to live in Session_Start event of my Global.asax. Now that the site does not require authentication to access the default area, Session_Start happens without authentication taking place.

What event can I wire up to handle the authentication event of WIF?

I have implemented a sliding session timeout using SessionAuthenticationModule_SessionSecurityTokenReceived and have tried adding my user analysis logic on the OnPostAuthenticationRequest event to no avail.

I was able to get the user after first wiring up to the following event:

FederatedAuthentication.ServiceConfigurationCreated

Then within this event I wire up to this event:

FederatedAuthentication.WSFederationAuthenticationModule.SignedIn

However, within this event the session is null and session_start is never called again. So it appears the session is getting crushed when redirecting to the identity provider.

anon -> Application_start
anon -> Session_start
anon -> Navigate to /MyArea
anon -> Redirected to ACS -> Redirected to idP
anon -> Log in
auth -> Redirected to /MyArea
auth -> FederatedAuthentication.WSFederationAuthenticationModule.SignedIn occurs, but session is null!

UPDATE: I still have not found a place where both Session and Authentication exist. I am using Unity to detect the user on demand. I'd love it if there was an event that does it as it happens but my work around still works.

2

2 Answers

3
votes

You've got a few options depending on when and how you want to execute your logic (after login, when creating the session token, after receiving it). The SessionAuthenticationModule_SessionSecurityTokenReceived event should work correctly, but subscribing to it can be tricky. This is how you can do it:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        FederatedAuthentication.FederationConfigurationCreated += (s, e) =>
        {
            FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenCreated += SessionAuthenticationModule_SessionSecurityTokenCreated;
            FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += SessionAuthenticationModule_SessionSecurityTokenReceived;
            FederatedAuthentication.WSFederationAuthenticationModule.SessionSecurityTokenCreated += WSFederationAuthenticationModule_SessionSecurityTokenCreated;
            FederatedAuthentication.WSFederationAuthenticationModule.SecurityTokenValidated += WSFederationAuthenticationModule_SecurityTokenValidated;
            FederatedAuthentication.WSFederationAuthenticationModule.SecurityTokenReceived += WSFederationAuthenticationModule_SecurityTokenReceived;
            FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += WSFederationAuthenticationModule_SignedIn;
        };
    }

    void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
    {
        Debugger.Break();
    }

    void SessionAuthenticationModule_SessionSecurityTokenCreated(object sender, SessionSecurityTokenCreatedEventArgs e)
    {
        Debugger.Break();            
    }

    void WSFederationAuthenticationModule_SessionSecurityTokenCreated(object sender, SessionSecurityTokenCreatedEventArgs e)
    {
        Debugger.Break();            
    }

    void WSFederationAuthenticationModule_SecurityTokenValidated(object sender, SecurityTokenValidatedEventArgs e)
    {
        Debugger.Break();            
    }

    void WSFederationAuthenticationModule_SecurityTokenReceived(object sender, SecurityTokenReceivedEventArgs e)
    {
        Debugger.Break();            
    }

    void WSFederationAuthenticationModule_SignedIn(object sender, EventArgs e)
    {
        Debugger.Break();     
    }
}

All of this code goes in the Global.asax file, and you want to set up the events after the FederationConfigurationCreated event raises (this is when the SessionAuthenticationModule and WSFederationAuthenticationModule will be available). I've added a Debugger.Break in each event handler. Leave them there and debug your application to see when each event is being triggered. This will allow you to decide when and where you want to add your logic.

0
votes

use the [Authorize] attribute on the controllers/actions that you want to secure:

[Authorize]
public ActionResult Index()
{
    return View();
}