The provided anti-forgery token was meant for a different claims-based user than the current user - Token Authentication - security

my current Authentication process looks like this. I have a Auth API that generates a token with UseOAuthBearerAuthentication. Once I generate the token inside GrantResourceOwnerCredentials I set the Identity.Name by identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName));
I want to store my token in a HttpOnly cookie, so in TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
I saved it to a cookie, but I also need to prevent XSRF so I generate a XSRF token there as well.
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
If I look at the current Identity context from OAuthTokenEndpointResponseContext context, Identity.Name is set, so it should be using this name for the XSRF token generation. But HttpContext.Current.User.Identity is null In my both my APIs I also set
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;
Now In my Resource API, I've already taken care of reading the auth token from the cookie and setting it to the Authorization header. That works fine. I have then created my own XSRF Attribute the verify the XSRF token.
public class ValidateAntiForgery : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
try
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (actionContext.Request.Headers.TryGetValues("X-XSRF-TOKEN", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
catch(Exception e)
{
actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Bad Request");
}
}
}
Checking the Identity in actionContext, everything is set and the user is authenticated. However, AntiForgery.Validate(cookieToken, formToken); throws an exception as shown below. I've looked at the many other examples, but I can't find a solution.
System.Web.Mvc.HttpAntiForgeryException: 'The provided anti-forgery
token was meant for a different claims-based user than the current
user.'
EDIT: So it seems where I generate my XSRF token in TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
context.Identity is set with the authenticated User, however HttpContext.Current.User is null. Even though the XSRF tokens generated here are technically valid, I think they are using null from the HttpContext. If I generate the XSRF token is a separate GET request with [Authorize] so that HttpContext.Current.User is not null, then the AntiForgery.Validate works fine.
I want the XSRF token to be returned with the Authentication token, but I'm not sure how to do that. How do I set HttpContext.Current.User.Identity?
EDIT 2: So I was able to fix the problem using a hacky way. When I want to generate the XSRF token I call the following function.
[Authorize]
public string generateXSRFToken(ClaimsIdentity identity)
{
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, new string[0]);
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
It works!, but it's ugly, I would like a more elegant way.

This should fix your problem:
var returnUrl = Request.QueryString["ReturnUrl"];
if (returnUrl.IsEmpty()) {
// Some external login providers always require a return URL value
returnUrl = Href("~/");
}
if (WebSecurity.Login(email, password, rememberMe))
{
Context.RedirectLocal(returnUrl);
return;
}
else
{
ModelState.AddFormError("The user name or password provided is incorrect.");
}

Related

Firebase Rest API for Token creation/verification does not have any result

We use Firebase for Authenticating our login process, at the backend we have a Rest API implementation in order to verify the token that is being passed.
I have modified the .json file and verified yet another time too in my code base. I have extracted the entire process of generating the token from the UID and this is how this looks:
public void initialization(){
try {
FileInputStream refreshToken = new FileInputStream("c02955c26b.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(refreshToken))
.setDatabaseUrl("https://164d0.firebaseio.com")
.build();
String uid = "Lp14BXL3xPVW7K8VZX28omynbWx1";
FirebaseAuth firebaseAuth= FirebaseAuth.getInstance(FirebaseApp.initializeApp(options));
System.out.println(" "+firebaseAuth); --> I see this on the console
String customToken = firebaseAuth.createCustomToken(uid);
System.out.println(" "+customToken);
FirebaseToken decodedToken = firebaseAuth.verifyIdToken(customToken);
String uidTranspose = decodedToken.getUid();
System.out.println(" the UID sent is"+uid+"Obtained after transpose is"+uidTranspose);
System.out.println(" the UID captured is this "+uid);
}
catch(Error e){
System.out.println(" "+e.getLocalizedMessage());
e.printStackTrace();
}
finally{
System.out.println("Finally comes here ");
}
}
Somewhere on hitting the token creation, the control flows directly to the finally block; without logging an error or an exception.
I am not sure if I am missing anything here.
Edit 1: Edited to add the complete code.
Edit 2: I am able to see the Token being created. but I am unable to verify the same; because it says this is a custom token and not the Id Token. I am not sure if I can access the Id Token or if there is a way to verify the custom token.
You cannot call verifyIdToken() with a custom token. See Verifying firebase custom token to get token ID fails when using jsonwebtoken

Does Keycloak allow obtaining id tokens via web interface

I am investigating how to possibly authenticate to a Kubernetes 1.13 cluster with OpenID Connect and Keycloak. I am new to this area.
This YouTube video ("Use Open ID Connect for Kubernetes API server") accomplishes part of what I want. An id token is initially obtained by making a HTTP request (with curl) to Keycloak citing grant type password. The resulting token is then subsequently used in further HTTP requests to the Kubernetes API. This works but has the disadvantage that clients directly handle users' permanent credentials.
Would it not be better if the token were issued by a secure web page that also required authentication via Keycloak (this time with grant type authorization code) and did nothing else but displaying a new token? Such tokens (transient credentials) could then e.g. be manually copied into kubeconfigs for further use?
Does Keycloak provide such interactive web pages (next to the REST endpoints for obtaining tokens programatically) or is this out of scope? If the second, are there other standard components for such tasks?
UPDATE This illustration from the Kubernetes documentation perhaps makes more clear what I am seeking. In step 1 a user should log into the Identity provider to obtain tokens which can then be configured into kubectl. Does Keycloak support this step, i.e. offer a web page where users could log in to obtain their tokens?
If I am able to understand your question ,so you want to get the accesstoken via Java code so here is code you can write and call
String obtainAccessToken = obtainAccessToken(username, password);
putRequest.addHeader("Authorization", "bearer " + obtainAccessToken);
putRequest.addHeader("content-type", MediaType.APPLICATION_JSON);
Here is the method you should call
public String obtainAccessToken(String UserName, String pwd)
{
AuthzClient authzClient = AuthzClient.create(configuration);
AccessTokenResponse accessTokenResponse = authzClient.obtainAccessToken(UserName, pwd);
String token = accessTokenResponse.getToken();
return token;
}
Here is the get realm method
public Response getAllRealms() {
ObjectMapper mapper = JacksonObjectMapperProvider.getObjectMapper();
CloseableHttpResponse response = null;
List<SureRealmRepresentation> realmList = new ArrayList<SureRealmRepresentation>();
int status;
try {
String urlGetAllRealms = URL + "/admin/realms";
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet getRequest = new HttpGet(urlGetAllRealms);
String obtainAccessToken = obtainAccessToken(username, password);
getRequest.addHeader("Authorization", "bearer " + obtainAccessToken);
getRequest.addHeader("content-type", MediaType.APPLICATION_JSON);
response = httpclient.execute(getRequest);
status = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (status == 200) {
RealmRepresentation[] realmArray = mapper.readValue(responseBody, RealmRepresentation[].class);
}
catch (Exception e) {
if (e instanceof Exception) {
throw (Exception) e;
} else {
throw ErrorHandler.wrap(new Exception("EroorType : "+ e.toString()));
}
}

External Login WebAPI2 MVC5

I need to use a 3rd party token as a way to authenticate. I'm getting the token in the home controller and need to be able to send it on to my WebAPI controllers (It's an SPA application using Backbone). Is there a way of doing this?
EDIT:
Relevant code:
public ActionResult Index(string projectId, int companyId, bool isCompanyAdmin)
{
// if not a valid user return error
var validate = new Validate().ValidateContext(HttpContext,
"Key", "Secret");
if (!validate.IsValidated) return View(Constants.ValidationFailed);
// The info validated, so now I can set it to authorized
// put code here for doing it
//Get the model for the user
try
{
var model = ConvertToVM(_smsRepository.GetCompany(companyId, projectId));
}
catch (ProviderIncompatibleException)
{
// connection string wrong
return View(Constants.ConnectionFailed);
}
catch (Exception e)
{
// catch all
return View(Constants.DatabaseError);
}
//create and send through the view model that determines what view the user will get
return View(model);
}
Ok I put in the index method on the Home Controller. Like I said, we make a call to a third party API passing in the context, the client key, and the client secret to verify our identity. Could I just add a Bearer token in the home controller? Or otherwise pass the http context to OWiN and use some custom logic to add the token if validate.IsValidated is true? It needs to be something that works with WebAPI.

oauth/check_token does not check for roles/scopes associated with endpoint

I have one Authorization server and one resource server. I am creating access token at authorization server and try to use it at Resource server using RemoteTokenServices in oauth2 which hits '/oauth/check_token' internally to authorization server, where it only checks for token existence and its expiry. But it does not check for roles/scopes against endpoint given vs roles/scopes against access_token.
#FrameworkEndpoint
public class CheckTokenEndpoint {
#RequestMapping(value = "/oauth/check_token")
#ResponseBody
public Map<String, ?> checkToken(#RequestParam("token") String value) {
OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
if (token == null) {
throw new InvalidTokenException("Token was not recognised");
}
if (token.isExpired()) {
throw new InvalidTokenException("Token has expired");
}
OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(token.getValue());
Map<String, ?> response = accessTokenConverter.convertAccessToken(token, authentication);
return response;
}
}
Above code snippet is from CheckTokenEndpoint.java.
Is there any way to achieve roles/scopes based authorization also?
If anyone else come across a similar issue with JWT token implementation using XML-based configuration, I have solved it the following way
Oh and my detailed post on how to implement Spring OAuth2 using XML-based configuration can be found here
Some assumptions
You are using JWT tokens that have custom claims
You have provided a custom implementation of JwtAccessTokenConvertor which in turn implements TokenEnhancer interface (feel free to implement AccessTokenConvertor & TokenEnhancer interfaces without having to use JwtAccessTokenConvertor)
You are using XML-based configuration
A closer look at the CheckTokenEndpoint source code reveals the follow
private AccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
And looking at the source code of DefaultAccessTokenConvertor, it is the default implementation of AccessTokenConvertor interface which basically have the following contracts
Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication);
OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map);
OAuth2Authentication extractAuthentication(Map<String, ?> map);
In my case, I used JWT tokens, meaning that the token value that I pass to the /oauth/token_check endpoint is a signed (with RSA keypair) JWT and the TokenCheckEndpoint will do a few checks such as
Checks if the token is in the db (oauth_access_token table), this does not apply to JWT implementation as they are not necessarily stored in db
Check that its valid JWT token in the first place
Check that the signature of the token is correct and it has not be tampered
Check that its not expired
Other checks that I don't know of
In addition to the above, I needed to check that the custom claim such as scope (i.e. basically role and its associated permissions) is same in the database (making sure that roles didn't change since token was issued).
Based on my debugging, when the /oauth/check_token endpoint is hit, the extractAccessToken followed by extractAuthentication methods is called respectively (at least with JWT implementation).
Since I have extended JwtAccessTokenConvertor (which in turn implements AccessTokenConvertor & TokenEnhancer interfaces) in order to enhance my JWT token to add custom claims (i.e. scope) to it by overriding the enhance method as shown below
#Component
public class MyJwtAccessTokenConvertor extends JwtAccessTokenConverter {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
//enhance the token with custom claims (i.e. user role scope)
//then return it
return result;
}
#Override
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
OAuth2AccessToken mytoken = tokenConverter.extractAccessToken(value, map);
/* validate the custom claims of token i.e. user role scopes
* and if any issue throw an exception
*/
return token;
}
}
I could easily validate that the JWT access token has the required user role scopes in the extractAccessToken method. If I detect any violation then I throw InvalidTokenException (can be custom exception too).

How to propage WebSphere security tokens when calling HTTP from EJB

I have an EJB which makes a call to another server in the cell using HTTP (REST api).
At the EJB context the user is already authenticated and authorized, how can I propagate the security tokens to the other server avoiding the need to provide credentials in the request ?
It is possible to obtain WebSphere's Ltpa token from the security subject and pass it as a cookie for the HTTP call:
public static SingleSignonToken getSSOTokenFromSubject(final Subject subject) {
if (subject == null) {
return null;
}
return AccessController.doPrivileged(new PrivilegedAction<SingleSignonToken>() {
public SingleSignonToken run() {
Set<SingleSignonToken> ssoTokens = subject.getPrivateCredentials(SingleSignonToken.class);
for (SingleSignonToken ssoToken : ssoTokens) {
if (ssoToken.getName().equals("LtpaToken")) {
return ssoToken;
}
}
return null;
}
});
}
// Get cookie to add to outgoing HTTP requests
SingleSignonToken ssoToken = getSSOTokenFromSubject(subject);
String ssoTokenStr = null;
if (ssoToken != null) {
byte[] ssoTokenBytes = ssoToken.getBytes();
ssoTokenStr = com.ibm.ws.util.Base64.encode(ssoTokenBytes);
}
String ssoTokenCookie = "LtpaToken2=" + ssoTokenStr;
By adding the ssoTokenCookie to the request cookies there is no need to provider user credentials.
Cookie ltpaCookie = WebSecurityHelper.getSSOCookieFromSSOToken();
Extracts the SSO token from the subject of current thread and builds an SSO cookie out of it for use on downstream web invocations. Basically what the whole code in the post below does. This method is accessible from WAS 8.x I believe.
Following Jar is needed as compile reference:
com.ibm.ws.admin.client-8.5.0.jar
(I'm using WAS 8.5.5.11 for this example)

Resources