TestServer and HttpClient get BadRequest for antiforgery token in .net core web api - httpclient

I have a problem to call default endpoint '/api/values' from xUnit test project. Web api is default .net core project. I always get bad request - 400 even I add header with value from AF cookie on each request.
First i setup antiforgery in Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(
opt =>
{
opt.Filters.Add(new ValidateAntiForgeryTokenAttribute());
}
).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
}
Then add separate controller and action to create AF cookie
[IgnoreAntiforgeryToken]
[AllowAnonymous]
[HttpGet("antiforgery")]
public IActionResult GenerateAntiForgeryTokens()
{
//generate the tokens/cookie values
//it modifies the response so that the Set-Cookie statement is added to it (that’s why it needs HttpContext as an argument).
var tokens = _antiForgery.GetAndStoreTokens(HttpContext);
Response.Cookies.Append("XSRF-REQUEST-TOKEN", tokens.RequestToken, new CookieOptions
{
HttpOnly = false,
});
return NoContent();
}
Then I setup test class
public UnitTest1()
{
_server = new TestServer(
WebHost.CreateDefaultBuilder()
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("appsettings.test.json", optional: false, reloadOnChange: true);
})
.UseStartup<Startup>()
.UseEnvironment("Development")
);
_client = _server.CreateClient();
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
and add method in test class to get value from AF cookie for AF header
protected async Task<string> EnsureAntiforgeryToken()
{
string _antiforgeryToken = string.Empty;
var response = await _client.GetAsync("/api/AntiForgery/antiforgery");
response.EnsureSuccessStatusCode();
if (response.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> values))
{
var _antiforgeryCookie = Microsoft.Net.Http.Headers.SetCookieHeaderValue.ParseList(values.ToList()).SingleOrDefault(c => c.Name.StartsWith(XSRF_TOKEN, StringComparison.InvariantCultureIgnoreCase));
_antiforgeryToken = _antiforgeryCookie.Value.ToString();
}
return await Task.FromResult<string>(_antiforgeryToken);
}
and in my test method I try to call endpoint
[Fact]
public async Task Test1Async()
{
_antiforgeryCookie = await EnsureAntiforgeryToken();
_client.DefaultRequestHeaders.Add("X-XSRF-TOKEN", _antiforgeryCookie);
var result = await _client.GetAsync("/api/values"); //always get error 400
Assert.True(true, "");
}

What's happening is that cookies in browsers or debugging tools like postman are automatically stored when received, then sent with every subsequent request to URLs with the same domain they were received from. This is not the case when you try to write and make requests in code.
So, you need to add the cookies, as cookies, to requests which hit an endpoint with anti-forgery validation.
When you get the response with the XSRF token, you have the cookies array which you are retrieving from a token generation response as such:
response.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> values)
And you're also parsing the XSRF-TOKEN cookie to get its value, which is great. But you also need both cookies unparsed as well.
So, you could introduce:
public class AntiForgeryToken
{
public string XsrfToken { get; set; }
public string[] Cookies { get; set; }
}
And modify EnsureAntiforgeryToken to populate it as such:
protected async Task<AntiForgeryToken> EnsureAntiforgeryToken()
{
var antiForgerytoken = new AntiForgeryToken();
var response = await _client.GetAsync("/api/AntiForgery/antiforgery");
response.EnsureSuccessStatusCode();
if (response.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> values))
{
var cookies = SetCookieHeaderValue.ParseList(values.ToList());
var _antiforgeryCookie = cookies.SingleOrDefault(c =>
c.Name.StartsWith(XSRF_TOKEN, StringComparison.OrdinalIgnoreCase));
// Value of XSRF token cookie
antiForgerytoken.XsrfToken = _antiforgeryCookie.Value.ToString();
// and the cookies unparsed (both XSRF-TOKEN and .AspNetCore.Antiforgery.{someId})
antiForgerytoken.Cookies = values.ToArray();
}
return antiForgerytoken;
}
We return both the XSRF Token that you are already parsing, in addition to cookies array which was returned with the response. The cookies are strings with their values and all the metadata that makes them cookies.
You then add the X-XSRF-TOKEN header and both cookies to your HttpClient, as such:
public async Task Test1Async()
{
_antiForgeryToken = await EnsureAntiforgeryToken();
// the bit you have and will still need
_client.DefaultRequestHeaders.Add("X-XSRF-TOKEN", _antiForgeryToken.XsrfToken);
// the bit you're missing
_client.DefaultRequestHeaders.Add("Cookie", _antiForgeryToken.Cookies[0]);
_client.DefaultRequestHeaders.Add("Cookie", _antiForgeryToken.Cookies[1]);
var result = await _client.GetAsync("/api/values"); // no more 400
Assert.True(result.IsSuccessStatusCode);
}
Which ends up mimicking the behaviour of a browser or debugging tool, where cookies received are stored and automatically sent back with every request to URLs with the same domain it was received from.

Related

ASP.NET Core JWT and Claims

I have a question regarding JWT authentication in ASP.NET Core and Claims, because I don't know if I get everything correctly.
When I create a JWT token in ASP.NET I add some Claims, some of which can be custom. What happens when the request with JWT token is sent from the client to API. How is User.Claims filled ? Does it use the claims that are read from JWT?
I would like to create a custom Identity provider ( don't want to use this provided by ASP.NET), with my own tables for user data, roles etc. I don't want store all important data required to fulfill the policy in JWT token (the amount of information stored in token matters, as well as security matters). Is it possible to store only basic claims (like user id, name etc) in JWT token, and then re-fetch other required data DB/ Cache? Along with that, I would like to use the standard mechanism for [Authorize] and the Policy mechanism.
How to make this all work: Custom User Identity + JWT + Standard ASP.NET policy-based authorization + claims fetched from DB/Cache on every request? How to achieve this?
Asp Net Core
First step is write the method that configure Jwt authentication:
// Configure authentication with JWT (Json Web Token).
public void ConfigureJwtAuthService(IServiceCollection services)
{
// Enable the use of an [Authorize(AuthenticationSchemes =
// JwtBearerDefaults.AuthenticationScheme)]
// attribute on methods and classes to protect.
services.AddAuthentication().AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = JwtController.SecurityKey,
ValidAudience = JwtController.Audience,
ValidIssuer = JwtController.Issuer,
// When receiving a token, check that we've signed it.
ValidateIssuerSigningKey = true,
// When receiving a token, check that it is still valid.
ValidateLifetime = true,
// This defines the maximum allowable clock skew when validating
// the lifetime. As we're creating the tokens locally and validating
// them on the same machines which should have synchronised time,
// this can be set to zero.
ClockSkew = TimeSpan.FromMinutes(0)
};
});
}
Now inside the ConfigureServices() method of the Startup.cs, we can call ConfigureJwtAuthService() method to configure the Jwt authentication.
This is the complete Startup.cs:
using System;
using Autofac;
using ExpertCodeBlogWebApp.Controllers;
using ExpertCodeBlogWebApp.Domain;
using ExpertCodeBlogWebApp.Domain.Interfaces;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace ExpertCodeBlogWebApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add
// services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Configure jwt autenticazione
ConfigureJwtAuthService(services);
// Repositories
services.AddScoped<IUserRepository, UserRepository>();
// Create the Autofac container builder for dependency injection
var builder = new ContainerBuilder();
// Add any Autofac modules or registrations.
builder.RegisterModule(new AutofacModule());
// Return ServiceProvider
var serviceProvider = services.BuildServiceProvider();
return serviceProvider;
}
// Configure authentication with JWT (Json Web Token).
public void ConfigureJwtAuthService(IServiceCollection services)
{
// Enable the use of an [Authorize(AuthenticationSchemes =
// JwtBearerDefaults.AuthenticationScheme)]
// attribute on methods and classes to protect.
services.AddAuthentication().AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = JwtController.SecurityKey,
ValidAudience = JwtController.Audience,
ValidIssuer = JwtController.Issuer,
// When receiving a token, check that we've signed it.
ValidateIssuerSigningKey = true,
// When receiving a token, check that it is still valid.
ValidateLifetime = true,
// This defines the maximum allowable clock skew when validating
// the lifetime.
// As we're creating the tokens locally and validating them on the
// same machines which should have synchronised time, this can be
// set to zero.
ClockSkew = TimeSpan.FromMinutes(0)
};
});
}
// This method gets called by the runtime. Use this method to configure
// the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
// For dependency injection.
public class AutofacModule : Module
{
// Dependency Injection with Autofact
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<UserRepository>().As<IUserRepository>()
.SingleInstance();
}
}
}
The JwtController.cs
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using ExpertCodeBlogWebApp.Domain;
using ExpertCodeBlogWebApp.Domain.Interfaces;
using ExpertCodeBlogWebApp.Domain.Models;
using ExpertCodeBlogWebApp.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
namespace ExpertCodeBlogWebApp.Controllers
{
[Route("api/[controller]")]
public class JwtController : Controller
{
#region Private Members
// JWT-related members
private TimeSpan TokenExpiration;
private SigningCredentials SigningCredentials;
// EF and Identity members, available through DI
private MyDbContext DbContext;
private IUserRepository _userRepository;
private readonly ILogger _logger;
#endregion Private Members
#region Static Members
private static readonly string PrivateKey = "my_PrivateKey";
public static readonly SymmetricSecurityKey SecurityKey =
new SymmetricSecurityKey(Encoding.ASCII.GetBytes(PrivateKey));
public static readonly string Issuer = "my_Issuer";
public static readonly string Audience = "my_Audience";
#endregion Static Members
#region Constructor
// I have used Autofac in the Startup.cs for dependency injection)
public JwtController(
MyDbContext dbContext,
IUserRepository userRepository,
ILogger<JwtController> logger)
{
_logger = logger;
_userRepository = userRepository;
// Instantiate JWT-related members
TokenExpiration = TimeSpan.FromMinutes(10);
SigningCredentials = new SigningCredentials(SecurityKey,
SecurityAlgorithms.HmacSha256);
// Instantiate through Dependency Injection with Autofact
DbContext = dbContext;
}
#endregion Constructor
#region Public Methods
// Manages the request for a new authentication or the refresh of an
// already established one
[HttpPost("token")]
public async Task<IActionResult>
Authentication([FromBody]JwtRequestViewModel jwt)
{
if (ModelState.IsValid)
{
string grantType = jwt.GrantType;
if (grantType == "password")
{
string userName = jwt.UserName;
string password = jwt.Password;
// Password check required
var user = await
_userRepository.GetUserInfoWithCheckPwd(userName, password);
// Check if user is expired (check the ExpireDate property)
if (UserExpired(user))
return BadRequest($"Account of {user.Name} expired!");
if (UserEnabled(user))
return await GenerateToken(user);
else
return BadRequest("User name or password invalid.");
}
}
else if (grantType == "refresh_token")
{
string userName = jwt.UserName;
// Refresh token (no password check required)
var user = await _userRepository.GetUserInfoByName(userName);
// Check if user is expired (check the ExpireDate property)
if (UserExpired(user))
return BadRequest($"Account of {user.Name} expired!");
string token = jwt.Token;
if (token == user.Token)
{
// Generate token and send it via a json-formatted string
return await GenerateToken(user);
}
else
{
return BadRequest("User token invalid.");
}
}
else
return BadRequest("Authentication type invalid.");
}
else
return BadRequest("Request invalid.");
}
#endregion Public Methods
#region Private Methods
private bool UserExpired(Users utente)
{
if (utente != null)
return utente.ExpireDate.CompareTo(DateTime.Now) < 0;
return true;
}
private bool UserEnabled(Users utente)
{
if (utente != null)
return utente.Enabled == true;
return false;
}
private JsonSerializerSettings DefaultJsonSettings
{
get
{
return new JsonSerializerSettings()
{
Formatting = Formatting.Indented
};
}
}
private async Task<IActionResult> GenerateToken(Users user)
{
try
{
if (user != null)
{
var handler = new JwtSecurityTokenHandler();
DateTime newTokenExpiration = DateTime.Now.Add(TokenExpiration);
ClaimsIdentity identity = new ClaimsIdentity(
new GenericIdentity(user.Name, "TokenAuth"),
new[] { new Claim("ID", user.Id.ToString())}
);
var securityToken = handler.CreateToken(new SecurityTokenDescriptor
{
Issuer = JwtController.Issuer,
Audience = JwtController.Audience,
SigningCredentials = SigningCredentials,
Subject = identity,
Expires = newTokenExpiration
});
string encodedToken = handler.WriteToken(securityToken);
// Update token data on database
await _userRepository.UpdateTokenData(user.Name, encodedToken,
newTokenExpiration);
// Build the json response
// (I use Automapper to maps an object into another object)
var jwtResponse = Mapper.Map<JwtResponseViewModel>(user);
jwtResponse.AccessToken = encodedToken;
jwtResponse.Expiration = (int)TokenExpiration.TotalSeconds;
return Ok(jwtResponse);
}
return NotFound();
}
catch(Exception e)
{
return BadRequest(e.Message);
}
}
#endregion
}
}
On my project I use Angular. For call JwtController method by Angular:
login(userName: string, password: string)
{
return this.getLoginEndpoint(userName, password)
.map((response: Response) => this.processLoginResponse(response));
}
getLoginEndpoint(userName: string, password: string): Observable<Response>
{
// Body
// JwtRequest is a model class that I use to send info to the controller
let jwt = new JwtRequest();
jwt.GrantType = "password";
jwt.UserName = userName;
jwt.Password = password;
jwt.ClientId = "my_Issuer";
// Post requiest (I use getAuthHeader that attach to the header the
// authentication token, but it can also be omitted because it is ignored
// by the JwtController
return this.http.post(this.loginUrl, JSON.stringify(jwt),
this.getAuthHeader(true))
}
protected getAuthHeader(includeJsonContentType?: boolean): RequestOptions
{
// Hera I use this.authService.accessToken that is a my service where
// I have store the token received from the server
let headers = new Headers({
'Authorization': 'Bearer ' + this.authService.accessToken });
if (includeJsonContentType)
headers.append("Content-Type", "application/json");
headers.append("Accept", `application/vnd.iman.v01+json,
application/json, text/plain, */*`);
headers.append("App-Version", "01");
return new RequestOptions({ headers: headers });
}
private processLoginResponse(response: Response)
{
// process the response..
}
On the controllers classes (or methods) that you want to be accessible only by authenticated users (not on your JwtController because its method must be accessible by all users) you can set:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
To call from Angular the controller method that require authentication, you need to attach the token into the header with the getAuthHeader() method.
I hope this post can help you.
yes it uses the claim stored in jwt token
look at the httpcontext object for claims that are stored in token when you created the token
this link can also be helpfull https://joonasw.net/view/adding-custom-claims-aspnet-core-2

Generating a JWT token using AuthenticateAsync

I am trying to login using ClaimsPrincipal and then fetch a JWT in .net core 2.0. With my current code, I get the error from the result of the SignInAsync function:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"
Here is the controller I am currently using:
[Route("Login/{username}")]
public async Task<IActionResult> Login(string username)
{
var userClaims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
};
var principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
var sign = HttpContext.SignInAsync(principal);
await sign;
var res = await HttpContext.AuthenticateAsync();
var token = await HttpContext.GetTokenAsync("access_token");
return Json(token);
}
The login portion was tested and works well with cookies. However when I use the following code with JwtBearerDefaults.AuthenticationScheme in my startup.cs:
services.AddAuthentication(config => {
config.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
config.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(config =>
{
config.TokenValidationParameters = Token.tokenValidationParameters;
config.RequireHttpsMetadata = false;
config.SaveToken = true;
});
I get the error from the result of the SignInAsync function:
"No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"
My Token class was created with the help of a code I found online (at JWT on .NET Core 2.0) and is defined as follows:
public static class Token
{
public static TokenValidationParameters tokenValidationParameters {
get
{
return new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = GetSignInKey(),
ValidateIssuer = true,
ValidIssuer = GetIssuer(),
ValidateAudience = true,
ValidAudience = GetAudience(),
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
}
}
static private SymmetricSecurityKey GetSignInKey()
{
const string secretKey = "very_long_very_secret_secret";
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
return signingKey;
}
static private string GetIssuer()
{
return "issuer";
}
static private string GetAudience()
{
return "audience";
}
}
If I understand it correctly from looking at the source code for JwtBearerHandler, it does not implement IAuthenticationSignInHandler, which is why you are getting this error. Call to SignInAsync is designed to persist authentication information, such as created auth cookie which, for instance, is exactly what CookieAuthenticationHandler does. But for JWT there is no single well-known place to store the token, hence no reason to call SignInAsync at all. Instead of that, grab the token and pass it back to the browser. Assuming you are redirecting, you can tuck it into a query string. Assuming browser application is an SPA (i.e. Angular-based) and you need tokens for AJAX calls, you should store token in the SPA and send it with every API request. There are some good tutorials on how to use JWT with SPAs of different types, such as this: https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f
Keep in mind that JwtBearerHandler expects to find Authentication header with Bearer in it, so if your AJAX calls are placing token in query string, you will need to supply JwtBearerEvents.OnMessageReceived implementation that will take token from query string and put it in the header.
A signed token can be created using the JwtSecurityTokenHandler.
var handler = new JwtSecurityTokenHandler();
var jwt = handler.CreateJwtSecurityToken(new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.Add(Expiary),
Subject = new ClaimsIdentity(claims, "local"),
SigningCredentials = new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256)
});
return handler.WriteToken(jwt);

ServiceStack Authenticates both iOS Apps when one is logged in

I'm using the awesome ServiceStack to implement my REST backend which serves two iPhone apps written in Xamarin. Everything works great but i'm struggling in getting sessions to work correctly when the two apps are installed on the same device !
The issue is that if I login in one of the apps the second app gets authenticated and doesn't require me to login as a result of 'isCurrentUserAuthenticated()' method below.
I pass cookies with my requests to mimic the browser and to make sure user doesn't have to pass his credentials every time but I guess the problem is that maybe ServiceStack sees two authentication requests from the same IP so it authenticated them both using the first authentication requests succeeds.
Note : The two apps accesses the same database and UserAuth table but every app supports a user role different than the other.
The only way to fix it is to logout from the second app so the user can login again with his credentials to make everything work.
Can you please help with this ?
Here is the code so far :
public static class BLL
{
public static JsonServiceClient ServiceClient { get; set; }
public static string HostUri = "http://test.elasticbeanstalk.com";
public static string HostDomain = "test.elasticbeanstalk.com";
static BLL ()
{
string ss_id = ConfigRepository.GetConfigString ("ss-id");
string ss_pid = ConfigRepository.GetConfigString ("ss-pid");
ServiceClient = new JsonServiceClient (HostUri);
ServiceClient.CookieContainer.Add (new Cookie ("ss-id", ss_id, "/", HostDomain));
ServiceClient.CookieContainer.Add (new Cookie ("ss-pid", ss_pid, "/", HostDomain));
}
public static async Task<bool> isCurrentUserAuthenticated ()
{
bool result = false;
try {
Authenticate authRequest = new Authenticate ();
// Restore the cookie
var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);
NSUserDefaults.StandardUserDefaults.SetString (response.UserId, "UserId");
NSUserDefaults.StandardUserDefaults.Synchronize ();
result = true;
} catch (Exception Ex) {
result = false;
}
return result;
}
public static async Task<AuthenticateResponse> Login (string userName, string password)
{
Authenticate authRequest = new Authenticate () {
provider = "credentials",
UserName = userName,
Password = password,
RememberMe = true,
};
var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);
var cookies = ServiceClient.CookieContainer.GetCookies (new Uri (HostUri));
if (cookies != null) {
var ss_id = cookies ["ss-id"].Value;
var ss_pid = cookies ["ss-pid"].Value;
if (!ss_id.IsNullOrEmpty ()) {
int r = ConfigRepository.AddConfigKey ("ss-id", ss_id);
System.Diagnostics.Debug.WriteLine ("ss-id " + ss_id.ToString ());
}
if (!ss_pid.IsNullOrEmpty ()) {
int r = ConfigRepository.AddConfigKey ("ss-pid", ss_pid);
System.Diagnostics.Debug.WriteLine ("ss-pid " + ss_pid.ToString ());
}
}
NSUserDefaults.StandardUserDefaults.SetString (response.UserId, "UserId");
NSUserDefaults.StandardUserDefaults.Synchronize ();
return response;
}
public static async Task<AuthenticateResponse> Logout ()
{
Authenticate authRequest = new Authenticate () {
provider = "logout"
};
var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);
return response;
}
}
The issue is because you're using the same Session Cookies with a shared ServiceClient instance which ends up referencing the same Authenticated Users Session.
ServiceStack Sessions are only based on the session identifiers (ss-id/ss-pid) specified by the clients cookies, if you use the same cookies you will be referencing the same Authenticated Users Session, they're not affected by IP Address or anything else.
If you want to authenticate as another user, use a new instance of the ServiceClient (so it's not using an existing Sessions Cookies).

How to send the authentication cookie WebRequest and receive the response in JIRA through REST api?

all
I am working on JIRA, i am sending the authentication request from saparate code and i am getting the response, later i need to fetch all issues from the JIRA than i am sending the request that time i am getting the 401 (Unauthorized) while i am sending the same username and password with gZip compression.
my first request code is following where from i am getting the proper response as authenticated.
string urll = ConfigurationManager.AppSettings["globalUrlForLP"];
HttpWebRequest request;
WebResponse response;
String uri;
LpResponse lp_response;
uri = urll + url;
request = WebRequest.Create(uri) as HttpWebRequest;
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = verb;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(this.Username + ":" + this._password)));
if (null != data)
{
request.ContentType = "application/json";
String jsonPayload = JsonConvert.SerializeObject(data);
byte[] jsonPayloadByteArray = Encoding.ASCII.GetBytes(jsonPayload.ToCharArray());
request.GetRequestStream().Write(jsonPayloadByteArray, 0, jsonPayloadByteArray.Length);
}
lp_response = new LpResponse();
try
{
response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
lp_response.response = reader.ReadToEnd();
}
catch (Exception e)
{
lp_response.error = e;
}
return lp_response;
}
from it i am getting response as following.
{
"session": {
"name": "JSESSIONID",
"value": "12345678901234567890"
},
"loginInfo": {
"failedLoginCount": 10,
"loginCount": 127,
"lastFailedLoginTime": "2014-10-28T06:52:52.211+0000",
"previousLoginTime": "2014-10-28T06:52:52.211+0000"
}
}
Now come to the point, I want to get all projects from the JIRA for that i written following code and i am getting here 401 Unathorized. After getting this i read the JIRA REST Api documentation and there i found following.
"Returns information about the caller's session if the caller is authenticated.
Note that the response contains the Set-Cookie HTTP headers that must be honoured by the caller. If you are using a cookie-aware
HTTP client then it will handle all Set-Cookie headers automatically. This is important because setting the JSESSIONID cookie alone may
not be sufficient for the authentication to work."
so please suggest me what i need to do more with following code ?
my Failure code is following.
string url = ConfigurationManager.AppSettings["urlAllJiraProject"];
LpResponse res = new LpResponse();
HttpWebRequest request;
WebResponse response;
List<AllJiraProject> jiraproject = new List<AllJiraProject>();
request = WebRequest.Create(url) as HttpWebRequest;
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "GET";
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(userNamejira + ":" + passwordjira)));
LpResponse lp_response = new LpResponse();
try
{
response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
lp_response.response = reader.ReadToEnd();
jiraproject = (List<AllJiraProject>)JsonConvert.DeserializeObject<List<AllJiraProject>>(lp_response.response.ToString());
}
catch (Exception e)
{
lp_response.error = e;
}
return jiraproject;
The accepted answer uses basic authentication and not a cookie. When requesting the cookie you don't need add any authorization to the headers. This method will accept a json string with the user name and password and the URL. It will return the cookie values.
public async Task<JiraCookie> GetCookieAsync(string myJsonPass, string JiraCookieEndpointUrl)
{
using (var client = new HttpClient())
{
var response = await client.PostAsync(
JiraCookieEndpointUrl,
new StringContent(myJsonPass, Encoding.UTF8, "application/json"));
var json = response.Content.ReadAsStringAsync().Result;
var jiraCookie= JsonConvert.DeserializeObject<JiraCookie>(json);
return jArr;
}
}
public class JiraCookie
{
public Session session { get; set; }
}
public class Session
{
public string name { get; set; }
public string value { get; set; }
}
When I call it using url: http://[baseJiraUrl]/rest/auth/1/session it returns the following JSON response:
{
"session" : -{
"name" : JSESSIONID,
"value" : cookieValue
}
Keep in mind the URL above is valid in the version of JIRA I'm using and may vary depending on which version you're using.
Read the JIRA API documentation for the correct URL for the version you are using.
Check out this answer on how add cookies to your HttpClient request.
How do I set a cookie on HttpClient's HttpRequestMessage
I got it, my code does not have Basic authentication into the header, while API demands the Basic authentication, so i replaced my one line with following two lines.
Replaced line
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(userNamejira + ":" + passwordjira)));
Replaced By
byte[] authBytes = Encoding.UTF8.GetBytes("user:password".ToCharArray());
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(authBytes);
Jira has three type of authentications, this one from Basic authentication, it is easy to implement, but i had no idea how to implement authentication from cookie.

DotNetOpenAuth Claimed Identifier from Facebook is never the same

I'm using DotNetOpenAuth v3.5.0.10357 and each time a user authenticates against Facebook I get a different claimed identifier back. The token looks to be encrypted so I assume DNOA is somehow encrypting the token along with the expiry. Can anyone confirm this? Or am I using it wrong:
public ActionResult FacebookLogOn(string returnUrl)
{
IAuthorizationState authorization = m_FacebookClient.ProcessUserAuthorization();
if (authorization == null)
{
// Kick off authorization request
return new FacebookAuthenticationResult(m_FacebookClient, returnUrl);
}
else
{
// TODO: can we check response status codes to see if request was successful?
var baseTokenUrl = "https://graph.facebook.com/me?access_token=";
var requestUrl = String.Format("{0}{1}", baseTokenUrl, Uri.EscapeDataString(authorization.AccessToken));
var claimedIdentifier = String.Format("{0}{1}", baseTokenUrl, authorization.AccessToken.Split('|')[0]);
var request = WebRequest.Create(requestUrl);
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var graph = FacebookGraph.Deserialize(responseStream);
var token = RelyingPartyLogic.User.ProcessUserLogin(graph, claimedIdentifier);
this.FormsAuth.SignIn(token.ClaimedIdentifier, false);
}
}
return RedirectAfterLogin(returnUrl);
}
}
Here's the code for FacebookAuthenticationResult:
public class FacebookAuthenticationResult : ActionResult
{
private FacebookClient m_Client;
private OutgoingWebResponse m_Response;
public FacebookAuthenticationResult(FacebookClient client, string returnUrl)
{
m_Client = client;
var authorizationState = new AuthorizationState(new String[] { "email" });
if (!String.IsNullOrEmpty(returnUrl))
{
var currentUri = HttpContext.Current.Request.Url;
var path = HttpUtility.UrlDecode(returnUrl);
authorizationState.Callback = new Uri(String.Format("{0}?returnUrl={1}", currentUri.AbsoluteUri, path));
}
m_Response = m_Client.PrepareRequestUserAuthorization(authorizationState);
}
public FacebookAuthenticationResult(FacebookClient client) : this(client, null) { }
public override void ExecuteResult(ControllerContext context)
{
m_Response.Send();
}
}
Also, I am using the RelyingPartyLogic project included in the DNOA samples, but I added an overload for ProcessUserLogin that's specific to facebook:
public static AuthenticationToken ProcessUserLogin(FacebookGraph claim, string claimedIdentifier)
{
string name = claim.Name;
string email = claim.Email;
if (String.IsNullOrEmpty(name))
name = String.Format("{0} {1}", claim.FirstName, claim.LastName).TrimEnd();
return ProcessUserLogin(claimedIdentifier, "http://facebook.com", email, name, claim.Verified);
}
It looks as though FacebookClient inherits from WebServerClient but I looked for the source on GitHub and I don't see a branch or a tag related (or at least not labeled) with the corresponding v3.5 version.
Facebook does not support OpenID. Claimed Identifier is an OpenID term. Facebook uses OAuth 2.0, so you're mixing up OpenID and OAuth.
Facebook sends a different access token every time, which is normal for the OAuth protocol. You have to use the access token to query Facebook for the user id that is consistent on every visit.
I think you need to add the offline_access permission in the token request as well, see https://developers.facebook.com/docs/reference/api/permissions/