OAuth and OWIN Authentication - Confusion - asp.net-mvc

I have been asked to create a 'Authentication/Authorization' Middle man or broker as an http,MVC web application, so that this can be used to multiple applications on our organization for authentication/Authorization purposes. Means, users will signup, Login on this broker application and once confirmed Authenticated, authorized user, he will get redirected to client applications accordingly. This is the use case.
I am choosing OAuth and OWIN to develop this broker in an MVC applicaiton, which means OAuth(Authorization) will issue access token + refresh token, once user is successfully authenticated. I use normal, simple, minimal authentication logic inside the Oauth Authorization Server's Login Controller as below :
public class AccountController : Controller
{
public ActionResult Login()
{
var authentication = HttpContext.GetOwinContext().Authentication;
if (Request.HttpMethod == "POST")
{
var isPersistent = !string.IsNullOrEmpty(Request.Form.Get("isPersistent"));
if (!string.IsNullOrEmpty(Request.Form.Get("submit.Signin")))
{
var user = Constants.Users.UserCollection.Where(u => u.Email.ToLower() == Request.Form["username"].ToLower().Trim() && u.Password == Request.Form["password"].Trim());
if (user.Count() > 0)
{
authentication.SignIn(
new AuthenticationProperties { IsPersistent = isPersistent },
new ClaimsIdentity(new[]
{ new Claim(ClaimsIdentity.DefaultNameClaimType, Request.Form["username"]),
new Claim("DisplayName", user.FirstOrDefault().DisplayName) } , "Application"));
}
}
}
return View();
}
This is the MSFT sample application I am following to develop this conceptual application.
https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server.
My question here is : I read in many articles like, its not good to use Oauth authentication, else use OPENID Connect handling authentication. To be frank, I am not used with OPENID Connect and I am not sure about the necessity of creating a OPENID Provider for my organization, Since this service will be used only by customers of our organization - less than 200,000 users. We hardly need a user signup and login, this account need to be used among different web applications of our organization. Please help me here with your inputs. Thanks in advance.

I think your question is about the benefits of OpenID Connect (OIDC) over OAuth 2.0.
OIDC builds upon OAuth 2.0 so you can use all of it's features. In a practical context, the question you should ask yourself is: Do other applications (clients, APIs), which use your "broker" (authorization server/security token service/OpenID provider) need to know something about the user, who just logged in? Do they need the ID, it's roles, username etc..? If the answer is no and you just need a signed token you are probably better of with OAuth.
If you start to include user claims (=attributes) in your access token you should at least have a look at OIDC. Also note, that even if you include claims in your access token, these are meant for the resource server (=API) and are normaly inaccessable for the client (unless you extract them and expose them on the API side - this is basically what the OIDC userinfo endpoint does).

Related

Broken AntiforgeryToken with Microsoft MSAL

I'm working with ASP.Net MVC and I have a problem using MSAL while authenticating a User. This is because, as we use AntiforgeryToken, when the user sign in in the page of Microsoft, the token breaks and we get an error related to the token.
My question is, is there a way to keep the token even after being redirected from Microsoft login page? Or can I recreate it?
I've search on other questions and google and found nothing.
Thank you.
Yes you can save the token in your application like this:
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Acquire the access token.
string[] scopes = new string[]{"user.read"};
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
context.Token = accessToken;
}
Alternatively, you can explicitly acquire tokens by using the acquire-token methods as described in the core MSAL library. The MSAL wrapper provides the HTTP interceptor, which will automatically acquire access tokens silently and attach them to the HTTP requests to APIs.

Securing Public APIs using Authorization Code flow in IdentityServer 4

I am stuck with one very basic requirement in my application. Here is my scenario. I am building a custom e-commerce portal using angular as a front end and rest API as a back end. I have a product listing API that is going to be called by my angular client application without the user's credentials as the product listing is a public page. However, I don't want anyone else to consume my product listing API. I know I can use client id and client secret to obtain token and make my API secure using Identityserver 4 but, how do I avoid exposing my client secret in an angular app?
Anyone can steal it very easily. Is there any way to use Authorization Code flow with PKCE for public my APIs such as product listing API where user id and password are not required?
To me best approach to answer this is to go back to definition of Authorization Code flow.Authorization code grant is a redirection-based flow used to obtain both access tokens and refresh tokens, the client initiates the flow by directing the resource owner's.
And pkce is just is an extension to the Authorization Code flow to prevent certain attacks.
Then the answer is no, we can not use Authorization Code flow with PKCE to secure a public API without user login.
There is some other ways to secure public APIs or at least make it less/harder accessible. CORS is an option, read more here, as its out of context for this question I wouldn't go further.
For scenario with login, Authorization code flow is supported on IdentityServer4. here is what we need to do to implement it:
On IdentityServer add the configuration entry for js client like:
new Client
{
ClientId = "jsclient",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
RequireClientSecret = false,
RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins =
{
"http://localhost:5003"
},
AllowedScopes = {"openid", "profile", "offline_access", "api1", "api2" },
}
On SPA app use oidc-client library, and also add the OIDC config to be like
var config = {
authority: "http://localhost:5000",
client_id: "js",
redirect_uri: "http://localhost:5003/callback.html",
response_type: "code",
scope:"openid profile api1",
post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);
Find full sample code here. I strongly suggest to read the quickstart doc to get a better understanding of implementation details.
You should implement Authorization Code Flow (PKCE) in your Angular App by plugging in the widely used OIDC Client library - its UserManager class will do the work for you.
For an example of how to use it, see these resources of mine:
Visual Tutorial Write Up
Code Sample
Authorization Code Flow PKCE Code

Vulnerabilities when using client credentials and OWIN Middleware OAuth

I've implemented OAuth2 client_credentials flow in our MVC app. Our MVC app is actually the Resource in this scenario. I had much difficulty in securing a sample for this specific use case, since this flow is primarily used for API access, but I did it nonetheless.
I'd like to share some of the implementation details with you to ask for any information regarding vulnerabilities that I may be unaware of. I am in no way a security expert, which is what brought me here.
In .NET Framework 4.5.2 I used the Microsoft.Owin libraries v3.0.1. I know there are newer ways to set up this sort of thing, (.NET Core and IdentityServer4 for example), but as I said I was having difficulty finding a viable sample for this specific use case, so I did the best I could.
I implemented a Provider:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private ClientService clientService;
public ApplicationOAuthProvider()
{
this.clientService = new ClientService();
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
context.TryGetFormCredentials(out clientId, out clientSecret);
if (clientId == "XXXX" && clientSecret == "XXXXX")
{
context.Validated(clientId);
}
return base.ValidateClientAuthentication(context);
}
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);
//context.OwinContext.Response.Headers.Add("Access-Control-All‌​ow-Origin", new[] { "*" });
return base.GrantClientCredentials(context);
}
with the following startup code:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
static Startup()
{
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
//AllowInsecureHttp = true,
AuthenticationMode = AuthenticationMode.Active,
};
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll)
.UseOAuthBearerTokens(OAuthOptions);
//app.UseOAuthBearerTokens(OAuthOptions);
}
}
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureAuth(app);
}
}
and then created a Client app that is also a website and eventually gained access to the Resource (MVC app). The Resource has no users, therefore no login screen. The Resource (now) has a token endpoint. The Client app makes a request to the token endpoint with their credentials and, (after being authenticated), then uses that token in subsequent requests to the Resource.
I've found 2 different ways of using this token to gain access.
Include the access token in the request header. OR
Include the access token as a form parameter
My questions are concerning vulnerabilities to this scenario:
Assuming all communications between the client app and the server are happening over secure channels (https) and the client app is able to maintain the credentials in a secure fashion, what are the chances that an access token could be obtained or intercepted? Or, are there methods included in this flow (or perhaps another OAuth flow) that also include client verification? I realize that the client is already being authenticated via client_id/client_secret, but when I ask about verification, I'm asking about the origin of the request (assuming of course, that the method of verification does not include checking something that can be spoofed by a malicious user).
Is there an additional step of verification that I should be including that I may have missed - because there's alot of information out there and I did my best to scour, but I can't claim that I have a solid understanding of everything I've read so far.
If there is an additional verification step that I have missed, how does that fit into this (client_credentials) flow?
Thanks,
Carrie
I've found 2 different ways of using this token to gain access.
Include the access token in the request header. OR
Include the access token as a form parameter
This means that your access token is of type Bearer token (therefore, you can also use a third way to send the access token: using GET method with a query parameter).
what are the chances that an access token could be obtained or intercepted?
Or, are there methods included in this flow (or perhaps another OAuth flow)
that also include client verification?
You have a Bearer token, thus the RFC-6750 applies. The Threat Mitigation section answers your questions:
first, your access token may be disclosed if the version of TLS between your client app and the authorization server (to get the token), and between the client app and the resource server (to give the token), have a security flaw (excerpt: This requires that the communication interaction between the client and the authorization server, as well as the interaction between the client and the resource server, utilize confidentiality and integrity protection. Since TLS is mandatory to implement and to use with this specification, it is the preferred approach for preventing token disclosure via the communication channel.)
secondly, another way for your access token to be disclosed is when using a TLS accelerator. As said in the same section of the RFC: In some deployments, including those utilizing load balancers, the TLS connection to the resource server terminates prior to the actual server that provides the resource. This could leave the token unprotected between the front-end server where the TLS connection terminates and the back-end server that provides the resource.
There are other ways to get the access token disclosed.
The solution is not to implement another OAuth flow but to apply the recommandations in section 5.3 of the RFC. As a summary, the main recommandations are:
always use TLS,
validate TLS certificate chains,
use token encryption in addition to the usage of TLS protection: for instance, encrypt the token with a shared secret between the client app and the resource server,
don't store bearer tokens in cookies,
issue short-lived bearer tokens,
issue scoped bearer tokens (use audience restriction).
This is not in the RFC but I would add this recommandation: use mutual authentication. This means that the client app must have a X.509 certificate that must be verified by the resource server. This is possible in the specific Oauth2 flow you have chosen, because the client app is known by the resource server (with some alternative flows, it can not be done).

Secure 2 different web applications with one identify service

Secure 2 different web applications with one identify service
Identity Service: Thinktecture Identity Service V2
Application 1: Asp.net MVC 5 application
Application 2: Asp.net Web API application
The above Applcation 1 and Application 2 are different projects and hosted in different servers. Now my scenarios are
1. Want to secure Application 1 with Identity Service.
2. Want to secure Application 2 with Identity Service.
Use case 1: If user access Application 1 it should redirect to identity service login page, once I entered the credentials and login in to application 1, the same token allow me to access Application 2.
Use case 2: If user try to access any API from Application 2 without login into Identity service, the request should reject.
I found a way to do this using pure SAML tokens. The trick is you need to create a delegation account in Identity Server to allow your web app to delegate identity to a specific realm (where your service lives). Then in the web app you make a service call using the the token that the user already has to get a new token which you use to access your service.
I asked a very similar question and answered it myself here.
Ok. I did eactly the same thing just now. Everything required to get that done is written here. If you're using IdentityServer, you need to configure the Token Type of your RP to be JWT:
this allows you to later extract the token from your authenticated MVC 5 application (see the link above to see how to do this) and then send that token to your Web API. You then need to tell you web api to accept that token, using Microsoft's JwtSecurityTokenHandler class. This class has a ValidateToken() method which accepts 2 parameters, the first being the access token that you put into your auth headers of the requests to the Web API, and the second, the validation parameters are basically what you've defined in IdentityServer's config:
validationParams = new TokenValidationParameters
{
AllowedAudiences = _allowedAudiencesAndSigningKeys.Select(x => x.Key),
ValidIssuer = ConfigurationManager.AppSettings["IssuerIdentity"],
ValidateIssuer = true,
SigningTokens = _allowedAudiencesAndSigningKeys.Select(x => new BinarySecretSecurityToken(Convert.FromBase64String(x.Value)))
};
The Audience(s)/Realm(s) you want to allow access to, the issuer name (your Identity Server name) and the signing symmetric key(s) of the applications you have defined in Identity Server and want to grand access to. The ValidateToken() method returns an ClaimsPrincipal with a list of the claims extracted from the token. The code to do all this can be put in a message handler:
public static void Configure(HttpConfiguration config)
{
var authNConfig = new AuthenticationConfiguration();
config.MessageHandlers.Add(new MyTokenValidationHandler());
}

ASPNet Identity Authentication MVC5 Client web site->Auth Server-> Web API server

I'm a newbie for ASPnet identity services and we require a following requirement.
Following is the architecture setup
1. Appserver
Appsever having
a. Entity Framework
b. ASP.Net Web API2 Odata services
c. Authorization server
2. Webserver
ASP.Net MVC 5 application (Client which access the App server)
The flow needs to be
MVC5 Cleint application having a login / Register form
While register / login the information needs to send to the authorization server int he app server, Authorize and creating the claims using Identity Services.
Once the Identity has been created in the Authorization server, the client application should logged in
I'm aware of getting bearer token from authentication server and that will be used as header information to access the API service
All we are lacking is the MVC client application should use the same identity claims that have created in the Authorization server.
Is there any way to access the claims which are created in the auth server.
I have got some samples about how to authenticate in the auth server and receiving token though OWIN and from this token we can access the API securely but I need of the client web application needs to sign in based on the token
I have gone through the following links
http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx
Also, I require to add claims when ever it requires after login as well
I have resolve this issue as follows, but I'm not sure this is the effective method
Once log-in and retrieve the bearer token (this token should assigned with claims identity already such as username, role .. etc)
In the web api AccountController, need to create a method to retrieve the default claims which requires for client web application. Please check the follows
[Authorize]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
var firstname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("FirstName")).SingleOrDefault();
var lastname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("LastName")).SingleOrDefault();
var IsApproved = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("IsApproved")).SingleOrDefault();
var userinfo = new UserInfoViewModel
{
UserName = User.Identity.GetUserName(),
FirstName = firstname.Value.ToString(),
LastName = lastname.Value.ToString(),
UserApproved = Convert.ToBoolean(IsApproved.Value.ToString()),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
return userinfo;
}
From the client, this actin will be called through the token as a header.
Once we have got the information (is in Json string format) needs to serialize with the UserInfoViewModel class (user defined viewmodel is based on the info we require and send from webapi account) with javascript serializer
Using these viewmodel information, assign them to local storage and using (cookies for my case) as a identity at local
keep logout webapi too when ever you logs out from web app.
Please let me know if you need more info or code

Resources