I want to add a new feature to my WebApp for events - build with .Net MVC - to send a magic link to each participant - after they register in the event - to access the WebApp and be able to participate in a Gamification challenge.
I am using Microsoft Owin for the backoffice access, and I would like to use it to create the magic link, but I cant find any solution for that.
I have searched a token login solution but no success.
Is it ASP.NET or ASP.NET Core application? It shouldn't matter if you're using OWIN or not. In a ASP.NET project I have used MachineKey's Protect and Unprotect methods. Set a static machine key using machineKey element in the web.config, because it keeps being regenerated by default. If it's a load-balancing environment, set identical machine key on each node.
For example, let's say you have some key identifying the participant, most likely the email address. Include ?user=key&token=token in the link. To generate the token
var unprotected = Encoding.UTF8.GetBytes(key);
var protected = MachineKey.Protect(unprotected);
var token = HttpServerUtility.UrlTokenEncode(protected);
To validate the token, when the user accesses the application:
bool Validate(string token, string expectedKey)
{
var protected = HttpServerUtility.UrlTokenDecode(token);
try
{
var unprotected = MachineKey.Unprotect(protected);
var key = Encoding.UTF8.GetString(unprotected);
return key == expectedKey;
}
catch (CryptographicException)
{
return false;
}
}
The MachineKey's successor in ASP.NET Core is Data Protection.
Related
I have a sharepoint site which has different authentication options available for users to login like Windows, Trusted SAML etc
How can i determine which is the authentication mode of the current request?
I have tried the "SPSecurity.AuthenticationMode" but its value is always forms.
You would need to get it via SPOriginalIssuerType Property
var localClaimManager = SPClaimProviderManager.Local;
if (localClaimManager != null)
{
var issuerType=SPOriginalIssuers.GetIssuerType(localClaimManager.DecodeClaim(SPContext.Current.Web.CurrentUser.LoginName).OriginalIssuer);
//Write your logic based on the issuerType received
//https://learn.microsoft.com/en-us/dotnet/api/microsoft.sharepoint.administration.claims.sporiginalissuertype?view=sharepoint-server
}
I am having a web application with web service and client will register their application using my web application.
Now client will have application of type SPA or mobile apps and they will consume my webservices from their apps.
So I would be implementing token based mechanism for securing access to my endpoints.
1) But here I am confused that shall I use any framework to generate access token or I can use any library which will generate any random string which i will send in response.for instance something like this :
TokenId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("+", "_")
So while registering application if client have enabled authentication for their application then user will be validated and then I will return access token and also save accesstoken in my database with that user id.
So my database table would be like below for storing validated accesstoken :
Id(autogenerated) accesstoken userid clientid createdat expiresat
So after user is authenticated and now if user want to access any protected resources then user need to pass this access token in subsequent call in header.
So what I will do I will get access token from header and then validate that accesstoken against that database and then allow access to my protected resource other wise user would get authorized.
I have seen lots of things related to this so basically this is oauth2 and I want to implement this.
I have seen Openid connect(this project doesnt even compile) which is on top of oauth2 and which is used for authentication and oauth2 will be used for authorization.
But here as I am storing access token in my database so here is my doubt related to that :
2) Now do I need openconnectid (but this project doesn't even compile) for validating access token or as I am having storing access token in my database I don't need openconnectid?
3) I want to implement asp.net identity but then I will receive dynamic database connection string and as i have seen asp.net identity mostly works with entity framework I couldn't find any source where I could use ado.net to validate username and password using SQL query. I know I can do something like this :
Make a custom user class which implements IUser as described here
Define a custom user store which implements
public class UserStoreService
: IUserStore<CustomUser>, IUserPasswordStore<CustomUser>
But I won't be having this information as I don't have fixed connection string.connection string again is stored in database with client registration.
4) We have given user a fixed endpoint through which client can create an admin so for that I will use my RSA algorithm for password hashing and then store it in database. So with this now do i need to use asp.net identity?
5) I have seen lots of following link with token based implementation but I am not getting where they are validating accesstoken in which part but now as I am having accesstoken stored in my database do I need to use any of the following implementation?
http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
6) Moreover if for any client if client don't want authentication for its respective application then what I will do is I will don't have that username password validation but I will simply generate accesstoken and then send in response so then in every subsequent request that access token will be pass to access protected resources.Do you think this make sense?
I have never seen any example where access token is store in database and problem with storing access token in database would be I have to make a call to database every time to validate access token for each endpoint.
Update :
Use case of my webservice engine would be:
1) Support multiple client application.
2) Manage user session in the form of token management for each client application. So here as most of the article is storing accesstoken in identity and that identity is validated inside [Authorize] attribute in which accesstoken is also validated and based on that user is allowed to access protected resources.This is what my understanding is up until now.
So if I also user identity and store user context inside identity supporting multiple client application is a good idea?
From “7.1. Access Token Representation” in “Full-Scratch Implementor of OAuth and OpenID Connect Talks About Findings” :
How should an access token be represented? There are two major ways.
As a meaningless random string. Information associated with an access
token is stored in a database table behind an authorization server.
As a self-contained string which is a result of encoding access token
information by base64url or something similar.
Pros and cons of these two ways are described in the blog.
If access tokens are random strings, pieces of information associated with the access tokens (user ID, client ID, scopes, lifetime, etc.) are stored in a database which is managed by the authorization server which have issued the access tokens.
Whenever a resource server which exposes APIs accepts an API call from a client application, the resource server has to get the information about the access token in some way or other.
If the resource server can access the database managed by the authorization server (in other words, if the resource server and the authorization server shares the database), the resource server can get the information about the access token from the database directly.
Otherwise, the resource server has to make an API call to the authorization server to get the information. In this case, it can be expected that the authorization server exposes an API which complies with RFC 7662 (OAuth 2.0 Token Introspection). Note that some implementations may provide a more developer-friendly API than RFC 7662 (e.g. “4. Introspection Access Token”).
Anyway, your resource server doesn't necessarily have to make a DB call (or an introspection API call to the authorization server) every time if the server caches information about access tokens in a memory cache or somewhere else appropriate.
BTW, what you need when you want to protect APIs is access tokens. Therefore, your system doesn't have to support OpenID Connect which is a specification as to how to request and issue ID tokens. You may be confused because a server which supports OpenID Connect can issue access tokens, too, in addition to ID tokens. See “Diagrams of All The OpenID Connect Flows” to understand what a server which supports OpenID Connect issues.
Finally, identity management, user authentication, and OAuth 2.0 & OpenID Connect don't necessarily have to be implemented in a monolithic way. See “New Architecture of OAuth 2.0 and OpenID Connect Implementation” for details.
No, you don't need to store the access_token on the database. You can decrypt the JWT and read the information as you are the one who encrypts it with a secret key. (By default it's the machine key.)
Identity has a off the self support for Oauth. You have to just configure it properly. You can set-up the configuration for OAuthAuthorizationServerOptions in the Startup.Auth.cs. Sample code as follows. I have tried to answer most of your question in comments in the code.
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void ConfigureOAuth(IAppBuilder app)
{
// Configure the application for OAuth based flow
PublicClientId = "theDragonIsAlive";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new YourOwnApplicationOAuthProvider(PublicClientId),
//AuthorizeEndpointPath = new PathString("/Access/Account"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(7)
//AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
// This where you are validating the username and password credentials.
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("Dragon Fire:", "The user name or password is incorrect. You shall be burnt.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(oAuthIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
// This method is where you will create the client access token.
// First you get the client, you can place values from the client record into the tokens claim collection.
// You then create a new ClaimsIdentity.
// You add some claims, in the example client name is added.
// Create an AuthenticationTicket using your claims identity.
// Validate the ticket (you do need to do this or the client will be considered unauthenticated)
//public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
//{
// var client = clientService.GetClient(context.ClientId);
// var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
// oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName));
// var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
// context.Validated(ticket);
// return base.GrantClientCredentials(context);
//}
// This method has to be implmented when you are maintaining a list of clients which you will allow.
// This method is for validating the input, you can used this method to verify the client id and secret are valid.
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//string clientId;
//string clientSecret;
//context.TryGetFormCredentials(out clientId, out clientSecret);
//if (clientId == "1234" && clientSecret == "12345")
//{
// context.Validated(clientId);
//}
//return base.ValidateClientAuthentication(context);
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
The sample code above does not have separate client classifications. It will treat all users as a single type of client. But I have given some example code in the comments which will guide you to get started in the right direction.
Disclaimer: I am not an expert on this(yet) and my setup is different. I had an existing MVC application with Owin and I had to build a webapi on top of it. This was my prototype code and it did the job. You will have to improve in it for your production code. Have fun and good luck.
I need to validate a Google ID token passed from a mobile device at my ASP.NET web api.
Google have some sample code here but it relies on a JWT NuGet package which is .Net 4.5 only (I am using C#/.Net 4.0). Is anyone aware of any samples which do this without these packages or has achieved this themselves? The use of the package makes it very difficult to work out what I need to do without it.
According to this github issue, you can now use GoogleJsonWebSignature.ValidateAsync method to validate a Google-signed JWT. Simply pass the idToken string to the method.
var validPayload = await GoogleJsonWebSignature.ValidateAsync(idToken);
Assert.NotNull(validPayload);
If it is not a valid one, it will return null.
Note that to use this method, you need to install Google.Apis.Auth nuget firsthand.
The challenge is validating the JWT certificate in the ID token. There is currently not a library I'm aware of that can do this that doesn't require .Net 4.5 and until there is a solution for JWT validation in .NET 4.0, there will not be an easy solution.
However, if you have an access token, you can look into performing validation using oauth2.tokeninfo. To perform basic validation using token info, you can do something like the following:
// Use Tokeninfo to validate the user and the client.
var tokeninfo_request = new Oauth2Service().Tokeninfo();
tokeninfo_request.Access_token = _authState.AccessToken;
var tokeninfo = tokeninfo_request.Fetch();
if (userid == tokeninfo.User_id
&& tokeninfo.Issued_to == CLIENT_ID)
{
// Basic validation succeeded
}
else
{
// The credentials did not match.
}
The information returned from the Google OAuth2 API tells you more information about a particular token such as the client id it was issued too as well as its expiration time.
Note You should not be passing around the access token but instead should be doing this check after exchanging a one-time code to retrieve an access token.
ClientId also needs to be passed, which should be set from Google API Console. If only pass TokenId, GoogleJsonWebSignature throws error. This answer is in addition to #edmundpie answer
var settings = new GoogleJsonWebSignature.ValidationSettings()
{
Audience = new List<string>() { "[Placeholder for Client Id].apps.googleusercontent.com" }
};
var validPayload = await GoogleJsonWebSignature.ValidateAsync(model.ExternalTokenId, settings);
I am using Windows Identity foundation to manage login to our site.
When a user logs in i am using some information in his request to put into the claims.
It is all working fine, but now I need to manage this scenario:
user is already logged in, athenticated and has a valid token.
But user decides to browses in again (via a redirect from another site)
So his information in his request is different.
I want to either
Sign him out - so that he naturally creates a new token with his new information
OR update his existing token.
So my question is:
How do i Sign out of Windows Identity foundation?
Or How do I update the existing claims?
I have tried this code:
public void ExpireClaims(HttpContextBase httpContextBase)
{
var module =
httpContextBase.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as
WSFederationAuthenticationModule;
if (module == null)
{
return;
}
module.SignOut(true);
}
But module is alway null.
and i tried this:
public void FederatedSignOut(string replyUrl)
{
WSFederationAuthenticationModule.FederatedSignOut(null, new Uri(replyUrl));
}
But i get a null reference execption when i do this.
Thanks very much.
Essentially sign-out is just deleting the cookie so:
FormsAuthentication.SignOut
or
FederatedAuthentication.SessionAuthenticationModule.SignOut
or
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie
will work.
Or use the FederatedPassiveSignInStatus (should be in your Toolbox). Set the property SignOutAction to FederatedSignOut and the control will clear out your STS session as well.
I have a WCF 4.0 REST service on server side (hosted in IIS) and an Android client. The Android client sends an encrypted security token in a custom HTTP header in order to authenticate the user. I have implemented a custom ServiceAuthorizationManager which extracts the security token from the header. The token contains the username which I can read from the token:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
var requestMessage = operationContext.RequestContext.RequestMessage;
var requestProperty = (HttpRequestMessageProperty)requestMessage
.Properties[HttpRequestMessageProperty.Name];
var token = requestProperty.Headers["X-MyCustomHeader"];
if (!string.IsNullOrEmpty(token))
{
var userName = GetUserNameFromToken(token);
if (!string.IsNullOrEmpty(userName))
{
// How to save userName now so that I can
// retrieve it in the service operations?
return true;
}
}
return false;
}
}
Now, my problem is that I also need the name of the authenticated user in various service operations (mainly to access user profile data) and I was planning to retrieve it this way:
public void MyServiceOperation()
{
string userName = OperationContext.Current
.ServiceSecurityContext.PrimaryIdentity.Name;
// check profile store for that userName and do something depending on
// profile settings
}
How can I set this username in CheckAccessCore?
A very naive trial like this...
operationContext.ServiceSecurityContext.PrimaryIdentity.Name = userName;
...doesn't work because PrimaryIdentity.Name is readonly. I assume that more sophisticated code is required.
After some research I didn't find a way to set the identity in ServiceAuthorizationManager.CheckAccessCore. This method seems to be called too late in the processing pipeline when the user's identity is already set (possibly to "Anonymous" (IsAuthenticated is false)) and cannot be changed anymore. The ServiceAuthorizationManager is made for authorization, not authentication, therefore it's the wrong place to implement a custom authentication.
I've finally found three possible ways for my problem:
As explained in the article linked in #TheCodeKing's answer, using the WCF REST Starter Kit provides the option to write a custom RequestInterceptor which hooks in early enough into the pipeline, allows access to the incoming request and allows to set the user's identity based on, for example, custom HTTP headers. Unfortunately the WCF REST Starter Kit is old (based on WCF 3.5) and the development has apparently been abandoned. Some of its features have been incorporated into WCF 4.0, but some have not, and the RequestInterceptor is among them. Nonetheless I've used this solution now and mixed the Microsoft.ServiceModel.Web assembly from the Starter Kit into my WCF 4.0 solution. It seems to work so far after a few simple tests.
If the identity is not really necessary but only the user name, a simple "trick"/"hack" to write the user name into a new request header works (also in CheckAccessCore):
// ...
var userName = GetUserNameFromToken(token);
if (!string.IsNullOrEmpty(userName))
{
requestProperty.Headers["X-UserName"] = userName;
return true;
}
// ...
And then in the service methods:
public void MyServiceOperation()
{
string userName = WebOperationContext.Current.IncomingRequest
.Headers["X-UserName"];
// ...
}
Another and more low level option would be to write a custom HttpModule which intercepts the incoming request and sets the identity. An example how this could look like is here from Microsoft Pattern & Practices team (see the "HTTP Module Code" example in the mid of the article).
Take a look at this article. It has examples of setting up the IAuthorizationPolicy instance. By creating your own implementation you can control the creation of the IPrincipal and IIdentity instances which are passed around in the context. It's all hooked in from a service interceptor.
internal class AuthorizationPolicyFactory
{
public virtual IAuthorizationPolicy Create(Credentials credentials)
{
var genericIdentity = new GenericIdentity(credentials.UserName);
var genericPrincipal = new GenericPrincipal(genericIdentity,
new string[] { });
return new PrincipalAuthorizationPolicy(genericPrincipal);
}
}