Pass argument from Identity Provider back to Relying Party after WSFed login - acs

Is there a way to pass a value back to a relying party after login? e.g. on the querystring?
Background:
What we want to do is inform the relying party what action the user took, e.g. sign in or register, so that the relying party can display the appropriate confirmation message to the user. Because the relying party might link to a Sign Up page, but then instead of signing up the user signs in, so the relying party shouldn't display a "thanks for joining us" notification panel.
I tried adding &lastaction=signup to the returnUrl but that gets lost when the form is posted through Azure ACS.
Next attempt was to try to add lastaction to the wreply, like so:
WSFederationMessage message;
WSFederationMessage.TryCreateFromUri(uri, out message);
var signinMessage = wsFederationMessage as SignInRequestMessage;
if (signinMessage != null)
{
signinMessage.Reply += "?lastaction=hello";
...
In Fiddler I can see that the next POST to ACS posts to https://xxxxx.accesscontrol.windows.net/v2/wsfederation?lastaction=hello
But the lastaction is not passed on to my relying party.

We had a related problem: we wanted to let the RP know which authentication methods the user used when signing in. We solved this by creating a new "system" claim with our namespace, and put the information in there.
In our TokenService implementation, in the AddSecurityClaims method:
claimsIdentity.AddClaim(
new Claim(
String.Format("{0}/{1}", WellKnownConfiguration.TokenService.ClaimsNamespace,
ClaimsAuthenticationMethods), ((int) userAuthenticationMethods)));
Update
You mentioned you thought about using cookies. In that case, I would do the following. I would implement setting a cookie (e.g. when registration page) and then create one more "action" that would return the value of that cookie. When the app gets the POST request with the credentials, you'd perform a redirect (immediately) to that relaying action with a return url. That action would then append the value of the cookie and call the original RP, but a custom action, that would then properly display the view.
Think of it as a cookie proxy. To summarize, the process is as follows:
User hits the RP, action requires authentication
The RP redirects the user to the STS as per WS-Federation
STS issues a token, and also adds a cookie to its own domain
RP gets the authenticated user, redirects to STS Cookie Reader
STS redirects to RP's second screen that can handle the login properly
All in all, one more hop, but like I said, it's probably fast enough for the user to not notice and/or care.

Related

How to set custom authentication cookies?

I'm building a custom ASP.NET Identity 2.0 implementation that uses our own data model, another ORM, other business logic, etc. By default, a user is logged in by setting the ApplicationCookie, after which the AuthorizeAttribute recognizes the cookie and logs the user in. For our own implementation, I want to add more ways to log in. For example:
Impersonation
Password reset token
Google Authenticator (two-factor)
SMS (two-factor)
In all these scenarios the user must be logged in, but what actions the user is allowed to perform depends on the way he logged in. For example: when the user logged in using a 'password reset token', he may change his password but not do anything else. When the user logged in with 'username + password', he may do basically everything, except for the actions that need a higher permission level (where the two-factor methods come in play). In order to do this, I want to build a custom AuthorizeAttribute that checks what login method was used, and then decides whether the user may perform the action or not.
The problem I'm facing is that I can set other cookies than ApplicationCookie (e.g. the TwoFactorCookie that is being set by going through the SMS process), but those cookies are not recognized as authentication cookies. Thus, when I have a TwoFactorCookie, I can't use that cookie to log in. Only having an ApplicationCookie results in a log in.
The issues I'm struggling with:
Do I always need to use ApplicationCookie to log in or can I use custom cookies to log in as well (so for example I can log in using ApplicationCookie, TwoFactorCookie and XYZCookie?
Should I have different cookies for each authentication method or should I have only 1 cookie and store the authentication method/type in a different way (for example in a Claim)?
If I should use different cookies, should I also write custom authentication middleware for each authentication method/type or can I use the default CookieAuthenticationMiddleware? As far as I know, the only thing that has to be done is set a cookie, and flag it with the correct authentication method so I can see how the user was logged in.
Edit:
As per Hao Kung's suggestion I made a couple of extension methods that look like this:
public static void UseSmsSignInCookie(this IAppBuilder app, TimeSpan expires)
{
if (app == null)
throw new ArgumentNullException("app");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = ApplicationAuthenticationTypes.Sms,
AuthenticationMode = AuthenticationMode.Passive,
CookieName = CookiePrefix + ApplicationAuthenticationTypes.Sms,
ExpireTimeSpan = expires,
});
}
I try to log someone in by calling AuthenticationManager.SignIn with a custom ClaimsIdentity that has my custom AuthenticationType (SMS). This doesn't work though: after calling SignIn, the result of HttpContext.Current.User.Identity.AuthenticationType still equals ApplicationCookie. The cookie has been set as expected though.
Does anyone have an idea what I'm missing?
So each instance of a CookieMiddleware basically represents one auth cookie, if you want multiple cookies, you can add more than one CookieMiddleware and to retrieve the ClaimsIdentity mapping to your cookie, you just need to call Authenticate on the AuthenticationManager passing in the AuthenticationType for the cookie you want.

How to sign-in to WIF federation on the same page?

I have this scenario.
RP with passive federation to 2.
Custom STS for user/password authentication
Everything is working fine. So far the user would press login link, which would go to a restricted area, thus the federation security was triggered, and login screen appeared. It would prompt him to write the credentials, the request was then processed, etc.
Now I'm required to create login (user/password) text-boxes on the same page (default page). How can I achieve federation sign-in operation without redirecting to a login page? Should (or can) I use FederatedPassiveSignIn control? If so, how?
You could show the login boxes on the unprotected landing page if IsAutheticated is false and then send a message to the custom STS login page with the credentials encrypted or whatever which then logs in behind the scenes and redirects back to your app. with the token in the normal manner.
However, if the user is not authenticated and bookmarks a page behind the landing page, they'll be redirected to the STS.
For anyone interested (I doubt someone actually is), I've solved it through - basically - simulating what login page does.
// makes credentials validation, and creates IClaimsPrincipal with the acquired claims
IClaimsPrincipal principal = LoginHelper.SignIn(editEmail.Value, editPassword.Value);
// retrieves the instance of the STS (in this case my custom STS)
TrustedSecurityTokenService service = (TrustedSecurityTokenService) TrustedSecurityTokenServiceConfiguration.Current.CreateSecurityTokenService();
// creates the request manually to point to my original page (or whatever page you desire)
SignInRequestMessage request = FederatedAuthentication.WSFederationAuthenticationModule.CreateSignInRequest(Guid.NewGuid().ToString(), "http://page/i/want/to/go/after/the/validation.aspx", true);
// processes first the request...
SignInResponseMessage response = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(request, principal, service);
// ...then the response is processed, and redirected to URL above
FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse(response, Response);
This created cookies, and principal is not IsAuthenticated. As if it were process by login page (at least it seems to work so far as expected).

User.Identity.IsAuthenticated use in generic asp.net handler

I've set up an STS with WIF and want to expose whether a user is signed in so that an RP can determine if the user is signed in without requiring the user to redirect to the STS and return. If the user is signed in, a different process flow will occur on the RP so it's important to know but not to force the sign-in at this point in the process.
My plan was to create a simple generic handler on the STS which, when hit via an HttpWebRequest, returns the output of context.User.Identity.IsAuthenticated (where context is the HttpContext passed into the ProcessRequest method:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
if (context.User != null && context.User.Identity.IsAuthenticated)
context.Response.Write("True");
else
context.Response.Write("False");
}
My problem is, if the user is signed in and I hit this handler directly, it returns True but if I programmatically hit the handler from the RP, it returns False (in fact the Identity is null).
Am I just completely wrong in doing this and hitting the handler from the RP will return the status of the User on the RP or could I be doing something wrong?
This handler will only work (return true), if you send the STS authentication cookies with the request. Only your web browser may have these cookies. Therefore it can't be done via HttpWebRequest. Also this is why it works, when you call the handler directly from the browser.
I know this is a bit old thread, but the answer may help others who land on this page.
The thing that does the magic behind the authentication is the session and authentication cookies which are sent to the user's client (e.g. browser) from your STS app. I'm not sure how your STS and RP apps are designed and communicate, so I will keep the answer generic. To notify your RP app of the authentication status, you need to:
1) either somehow share both cookies between the user's client and the your RP app. In this scenario, I'm afraid you will have to build your own client and make your users use it to visit the STS app. This is because you cannot get the cookies from the standard browsers. The client you build sends the cookies somewhere where your RP app can get them and place them in HttpWebRequest.CookieContainer which then can successfully get the result of your handler. I'm only explaining this method to say that it is doable and show how complex and twisted it is.
2) or you will have to track the login status of your users. Instead of checking the context.User, your handler must get the user ID from the calling RP app and then check if that user is logged in (that is there is an active session for that user). For example, you can track or store your sessions in the database, or have a look at the following thread for some methods of accessing active sessions:
List all active ASP.NET Sessions

ASP.Net and Facebook: Logging-in via ASP.Net

I want to enable Facebook authentication and the FB-Graph in my website, which already has forms authentication. Using http://multitiered.wordpress.com/2010/08/05/getting-started-with-the-facebook-c-sharp-sdk/, I was able to figure out how to login server-side.
However, the problem with this approach is that a secure cookie will not be created, since the call returns the authentication code in the querystring via a callback. This means that the user will have to login every time.
I can see two ways around this:
Store the access token in a secure cookie manually
Instead of the above approach, use the FB JS API to login - this stores a secure cookie with the access token automatically
I would prefer not to use the second approach, as I would like the login code to be server-side.
Which would be the better approach? Am I missing something?
I use the JavaScript method to first authenticate the user, the JS SDK then writes an encrypted cookie (called "fbs_[YourAppID]") when a connected user hits your page; using one of the many Facebook c# SDKs, this cookie can be decoded using your application secret giving you the user ID, oAuth token, expiry date etc.
Then I hook into the AuthenticateRequest event of my .NET application, check the presence of the cookie, decode if it found, and then find a user who has been assigned this facebook ID (your user table must have a extra field for storing the ID of their facebook account).
If a match is found, I write a normal forms authentication cookie for this user, then .NET will recognise them for all future requests. If no user is found, then this is a brand new user who has just connected. Use the SDK again to query the graph API using their oAuth token, get things like their name/email etc and create a new account, then issue a authentication token as normal.
By writing a normal authetication cookie, the user will stay logged into to your site for all requests, just as if they were a normal user.
One side point, when using email address, check for duplicates, and check for the facebook cookie in all requests. For example, an existing registered logged in user may have just connected.

impersonation via token stored in a cookie

I want to know more about win32 LogonUser api function. The last parameter is a token which can be used to impersonate a windows identity to execute code on a person's behalf. Say I have a login page where I enter my username, password and domain. When the user submits the page I validate the user by making a call to LogonUser() and get a token reference.
I am thinking why not store the token in a cookie and use it at a later stage (perhaps in another page). I just don't know what issues I might have to face upfront...
Can the token expire even if we don't close it properly using the CloseHandle() win32 call? Is there any article related with this particular requirement?

Resources