Showing posts with label owin. Show all posts
Showing posts with label owin. Show all posts

Thursday, September 13, 2018

Owin SelfHost WebApi - client closing the connection during response raises an exception?

Leave a Comment

I'm running an Owin Selfhost based WebApi where i've put in an API unhandled exception logger via

config.Services.Add(typeof(IExceptionLogger), _apiExceptionLogger); 

Relevant part of ApiExceptionLogger:

    public override void Log(ExceptionLoggerContext context)     {         if (context == null || context.ExceptionContext == null) return;          Logger.Error("Unhandled exception from Web API", context.ExceptionContext.Exception);     } 

The cases it's catching and logging regularly are ones where the client requests a dataset and then closes the connection while the results (JSON) are being sent back - people making a request in chrome, and then hitting the X button before all results come back :P

I've pasted a stacktrace below for completeness, just want to know two things:

  • Is this regular/expected behavior? AFAIK it is...I'm running a pretty default API and pipeline
  • Is there any way to handle this? Essentially stop request processing more gracefully in case of a cancellation (the cancellation tokens peppered throughout the request pipeline do come to mind, but doesn't look like they do much in this case, after all the tokens only support co-operative cancellation)

I haven't done any deep dive on the sequence of events happening at the socket level, so far this is only a logging nuisance.

System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException ---> System.Net.HttpListenerException: The I/O operation has been aborted because of either a thread exit or an application request    at System.Net.HttpResponseStream.EndWrite(IAsyncResult asyncResult)    at Microsoft.Owin.Host.HttpListener.RequestProcessing.ExceptionFilterStream.EndWrite(IAsyncResult asyncResult)    --- End of inner exception stack trace ---    at Microsoft.Owin.Host.HttpListener.RequestProcessing.ExceptionFilterStream.EndWrite(IAsyncResult asyncResult)    at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)    --- End of inner exception stack trace ---    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)    at System.Web.Http.Owin.HttpMessageHandlerAdapter.<SendResponseContentAsync>d__20.MoveNext()    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)    at System.Web.Http.Owin.HttpMessageHandlerAdapter.<SendResponseContentAsync>d__20.MoveNext() 

2 Answers

Answers 1

I had a similar issue with Owin host on Raspberry Pi. This may help https://stackoverflow.com/a/30583109/1786034

Answers 2

Its code issue

Read file async and check.At any time if you are doing an api call and it times out it will definitely throw exception.

using (StreamReader reader = new StreamReader(await selectedFile.OpenStreamForReadAsync()))             {                 while ((nextLine = await reader.ReadLineAsync()) != null)                 {                     contents.AppendFormat("{0}. ", lineCounter);                     contents.Append(nextLine);                     contents.AppendLine();                     lineCounter++;                     if (lineCounter > 3)                     {                         contents.AppendLine("Only first 3 lines shown.");                         break;                     }                 }             } 
Read More

Thursday, August 9, 2018

Asp.Net Identity - Updating Claims After Login

Leave a Comment

I am using asp.net identity (WebApi 2, MVC 5, not .net core) to add claims to my user's identity when she logs in from our singe page application. This looks like this (I have stripped out the checks for invalid names, locked accounts, etc)

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) {     var userManager = context.OwinContext.GetUserManager<CompWalkUserManager>();     var user = await userManager.FindByNameAsync(context.UserName);     var check = await userManager.CheckPasswordAsync(user, context.Password);     if (!check)     {         await userManager.AccessFailedAsync(user.Id);         context.SetError("invalid_grant", invalidUser);         return;     }      ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,         OAuthDefaults.AuthenticationType);     ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,         CookieAuthenticationDefaults.AuthenticationType);      //These claims are key/value pairs stored in the local database     var claims = GetClaimsForUser(user);     cookiesIdentity.AddClaims(claims);     oAuthIdentity.AddClaims(claims);       AuthenticationProperties properties = CreateProperties(user.UserName);     AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);     context.Validated(ticket);     context.Request.Context.Authentication.SignIn(cookiesIdentity); } 

At this point, everything is working as expected. I can check the user's claims via an AuthorizationFilterAttribute as methods on my api are called.

However, it is possible that an administrator might change the values of the claims while the user is logged in (our tokens are good for 14 days). As an example we have a claim named Locations with a value of EditAndDelete. The admin might change this value to NoAccess in the database, but the authentication will not know about about this.

I can see that at run-time I can add or remove claims from my identity, but these changes do not persist past the current request. Is there a way to update the auth ticket in the cookies on the fly? I would like to be able to update my Identity with the new value without having the user have to log out.

1 Answers

Answers 1

If you want to go the Identity way of doing that, you need to hit the db on every login. You set the SecurityStamp validation interval to 0:

app.UseCookieAuthentication(new CookieAuthenticationOptions     {         AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,         LoginPath = new PathString("/Account/Login"),         Provider = new CookieAuthenticationProvider         {              OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(                 validateInterval: TimeSpan.FromSeconds(0),                 regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))         }     }); 

When the permissions are changed for a user, you update their securitystamp:

UserManager.UpdateSecurityStamp(userId); 
Read More

Monday, April 16, 2018

Maximum concurrent requests in signalr self hosted in kestrel

Leave a Comment

I've encountered a strange problem with an application I've developed. The application is a windows service hosting AspNetCore 2.0 running on Kestrel. This application receives requests through an IIS site acting as a proxy.

In this application, I also use signal 2.2.2 integrated using Microsoft.AspNetCore.Owin. All worked well until I detected that the application was not responding to requests.

Other applications on the same machine and using the same IIS server as proxy were working fine. Restarting the application pool serving the site solved the problem temporarily.

The problem resurfaced again and digging through monitoring information the application seems to hang when there are 400 signalr SSE connections on the same machine. This seems plausible as I've found that by default OWIN limits the number of concurrent requests at 100 * number of cpus. (Note that a site on the same machine is serving 5000 requests per minute without a sweat but these are not a long-lived request like the SignalR ones)

The problem is that I seem unable to find the same option when hosting Owin inside AspNetCore. Does someone know if this can be the solution and what is the correct setting?

EDIT: I'm fairly certain that the issue is caused by the number of SignalR connections opened concurrently because by disabling it in Javascript the problem vanished.

2nd EDIT: signalr does not seem to be the cuplrit as load testing the site with crank both in test and in production worked until 5000 concurrent connections which is the default IIS limit and is fine by me

1 Answers

Answers 1

This could be the issue, but it's unlikely. When hosting in dotnet core you're probably using Kestrel as a webserver implementation, to switch these limits such as concurrent connections you can use KestrelServerLimits class as described in this Microsoft article.

KestrelServerLimits should not be causing you any problems since the default value for ConcurrentConnections is unlimited.

Read More

Tuesday, January 23, 2018

Use Nancy whit Owin and WebForms

Leave a Comment

There is a method for esclude aspx page from pipeline in the use nancy.Owin in a old webform site project not compiled?

When I configure nancy the post-back and the request is an aspx page the post-back is deleted because nancy delete it and recall the page.

public void NancyConfig(IAppBuilder app) {     app.UseNancy(options =>     {         options.Bootstrapper = new MyBootstrapper();         options.PerformPassThrough = (context => context.Response.StatusCode == HttpStatusCode.NotFound);     });      app.UseStageMarker(PipelineStage.MapHandler); } 

The options.PerformPassThrough wipe the post-back content and call the page. For not post-back is ok but in post-back elaboration this present an infinite loop.

How to configure NancyFx for not wipe post-back in passtrought option?

1 Answers

Answers 1

I'have modified the nancy official 1.4 sources to esclude from .aspx and other page from pipeline, returning the request postback whitouth delete it. You can try this modify here .

  • File modified: Nancy/src/Nancy/Owin/NancyMiddleware.cs
  • Here te code to apply at line 82:

                //Check if the webform is not present inthe path ".aspx"             //if present move to next             if (owinRequestPath.ToLowerInvariant().Contains(".aspx")             || owinRequestPath.ToLowerInvariant().Contains(".asmx")             || owinRequestPath.ToLowerInvariant().Contains(".ascx")             || owinRequestPath.ToLowerInvariant().Contains(".ashx")             || owinRequestPath.ToLowerInvariant().Contains(".asmx")             || owinRequestPath.ToLowerInvariant().Contains(".asax")             ) return next.Invoke(environment); 
Read More

Tuesday, August 1, 2017

How do I get the user's email when using Microsoft Account Authentication in an MVC project?

Leave a Comment

I have modified startup.Auth.cs so that I could add scopes. Here is what I have:

MicrosoftAccountAuthenticationOptions mo = new MicrosoftAccountAuthenticationOptions() {     ClientId = "My Client ID",     ClientSecret = "My Client Secret", }; app.UseMicrosoftAccountAuthentication(mo); 

This allows me to authenticate the user.

I have tried adding the scopes wl.signin, wl.emails and wl.contacts_emails. However, they cause the Microsoft login page to report the following error: AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope wl.signin, wl.emails, wl.contacts_emails is not valid. The scope combination of openid and email seems to work. However, the scope openid is overkill for what I am trying to do. That is, I think it is too much to ask from the user. The scope email all by it self doesn't work.

This is particularly weird because the template that Visual Studio sets up assumes that the external authentication provider will supply an email address.

How do I get only the user's email?

For context, I am using the following documents: https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference#openid-permissions which gives the impression that I want email and profile included in the scope. However, it goes on to state that they are included by default.

I am trying to implement external Authentication in my MVC project using the document: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/microsoft-logins.

3 Answers

Answers 1

You can use the following code to get the email address of a user.

 ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1]; 

Answers 2

Try to add scopes:

MicrosoftAccountAuthenticationOptions mo = new MicrosoftAccountAuthenticationOptions() {     ClientId = "My Client ID",     ClientSecret = "My Client Secret", }; mo.Scope.Add("openid"); mo.Scope.Add("email"); app.UseMicrosoftAccountAuthentication(mo); 

Answers 3

Looks like you have to use OpenID to get the email. However, If you have Microsoft.IdentityModel.Tokens v5.x you can't use OpenID. It only works with Microsoft.IdentityModel.Tokens v4.x. Made the mistake of loading the lates version.

Read More

Sunday, June 11, 2017

UrlHelper.Link returns undesired parameters

Leave a Comment

If I call UrlHelper.Link within an API call which has a parameter matching an optional parameter of the API endpoint I'm attempting to obtain an URL for, UrlHelper.Link returns a URL with values from the current request no matter how I try to exclude the optional parameter from the link.

e.g.

[HttpGet] [Route("api/Test/Stuff/{id}")] public async Task<IHttpActionResult> GetStuff(int id) // id = 78 {     string link = Url.Link("Mary", new     {         first = "Hello",         second = "World"     });      string link2 = Url.Link("Mary", new     {         first = "Hello",         second = "World",         id = (int?)null     });      string link3 = Url.Link("Mary", new     {         first = "Hello",         second = "World",         id = ""     });      return Ok(new     {         link,         link2,         link3     }); }  [HttpGet] [Route("api/Test/Another/{first}", Name = "Mary")] public async Task<IHttpActionResult> AnotherMethod( [FromUri]string first, [FromUri]string second = null, [FromUri]int? id = null) {     // Stuff     return Ok(); } 

GET http://localhost:53172/api/Test/Stuff/8

returns

{   "link": "http://localhost:53172/api/Test/Another/Hello?second=World",   "link2": "http://localhost:53172/api/Test/Another/Hello?second=World&id=8",   "link3": "http://localhost:53172/api/Test/Another/Hello?second=World&id=8" } 

How do you get Url.Link to actually use the values you pass it rather than pull it from the current api request when they are not presented or assigned to null or empty string?

I believe the issue is very similar to ....

UrlHelper.Action includes undesired additional parameters

But this is Web API not MVC, not an action and the answers provided do not seem to yield an obvious solution to this issue.

EDIT: I've updated the code as the original code didn't actually replicate the issue. I've also included a request URL and the response returned, which I've tested. Whilst this code demonstrates the issue, the code I'm trying to find a fix for is not passing an anonymous type to UrlHelper, instead its a class which generates a timestamp and hash and has 4 optional parameters. If there's another solution which doesn't require omitting the optional parameters in the structure passed to UrlHelper I'd like to have it, as it'll save me from making a lot of changes to the code.

1 Answers

Answers 1

Do not include the id when passing the route values. In fact it should not allow you to compile as

Cannot assign <null> to anonymous type property

public async Task<IHttpActionResult> GetStuff(int id) // id = 78 {     string myUrl = Url.Link(         "Mary",          new          {              first = "Hello World"         });      //...other code } 

Tested with web api 2 and id was not included when linking to other action.

[RoutePrefix("api/urlhelper")] public class UrlHeplerController : ApiController {      [HttpGet]     [Route("")]     public IHttpActionResult GetStuff(int id) {         string myUrl = Url.Link(             "Mary",             new {                 first = "Hello World",            });         return Ok(myUrl);     }      [HttpGet]     [Route(Name = "Mary")]     public IHttpActionResult AnotherMethod(     [FromUri]string first,     [FromUri]string second = null,     [FromUri]int? id = null) {         // Stuff         return Ok();     } } 

Calling

client.GetAsync("/api/urlhelper?id=78") 

routed to the GetStuff action and the link generated

"http://localhost/api/urlhelper?first=Hello%20World" 

Even when tested with

string myUrl = Url.Link(     "Mary",     new {         first = "Hello World",         id = ""     }); 

id was not included in the generated link.

Read More

Tuesday, February 28, 2017

Jwt tokens authorization is not working

Leave a Comment

I'm trying to create Jwt token authorization. For this purpose I have issuer part with the code like that:

public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) {     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});     Users user;     using (var db = new UserStore())     {         user = Task.Run(()=> db.FindUser(context.UserName, context.Password, context.ClientId)).Result;     }     if (user == null)     {         context.SetError("invalid_grant", "The user name or password is incorrect");         return Task.FromResult<object>(null);     }     var identity = new ClaimsIdentity("JWT");     identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));     identity.AddClaim(new Claim("sub", context.UserName));     identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Name));      var props = new AuthenticationProperties(new Dictionary<string, string>     {         {             "audience", context.ClientId ?? string.Empty         }     });     var ticket = new AuthenticationTicket(identity, props);     context.Validated(ticket);     return Task.FromResult<object>(null); } 

And "resource" part that should accept bearer token:

public void ConfigureOAuth(IAppBuilder app) {     var issuer = SiteGlobal.Issuer;     var audience = SiteGlobal.Audience;     var secret = TextEncodings.Base64Url.Decode(SiteGlobal.Secret);     app.UseJwtBearerAuthentication(     new JwtBearerAuthenticationOptions     {         AuthenticationMode = AuthenticationMode.Active,         AllowedAudiences = new[] { audience },         IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]         {             new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)         }     }); } 

As far as I can see issued token are valid (I did validation on jwt.io), so the problem is somehwere else. When I'm sending token in Postman with the call to controller protected by [Authorize] attribute it always return 401 code. Could you please advise how to fix this?

P.S. This is how I implement custom Jwt fortmat:

public string Protect(AuthenticationTicket data) {     if (data == null)     {         throw new ArgumentNullException("data");     }     string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;     if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");     Audience audience;     using (var store = new AudienceStore())     {         audience = Task.Run(()=> store.FindAudience(audienceId)).Result;     }     var symmetricKeyAsBase64 = audience.Base64Secret;     var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64));     var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);     var issued = data.Properties.IssuedUtc;     var expires = data.Properties.ExpiresUtc;     var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials);     var handler = new JwtSecurityTokenHandler();     var jwt = handler.WriteToken(token);     return jwt; } 

P.S. Guys, I'm so sorry, but I forgot to explain that "issuer" part of code that's standalone application, meanwhile "audience" is protected web api. That's two different appliactions running independently.

2 Answers

Answers 1

In Postman ensure you are sending the authorization header using the following format:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

Postman Authorization Header

Ensure that you leave the Authorization tab set to Type: No Auth.

If you continue to have issues, set a breakpoint in your GrantResourceOwnerCredentials and see if it gets to that point. Also consider overriding the ValidateClientAuthentication method of OAuthAuthorizationServerProvider which should get called prior to GrantResourceOwnerCredentials if you want to debug earlier in the chain of events.

Answers 2

I have just tried to run demo project mentioned in SON Web Token in ASP.NET Web API 2 using Owin and all worked as expected.

I noticed that your implementation of Protect method differs quite a bit. I would suggest you to compare your implementation to an example given in the article. Try make that work first.

Also please make sure that issuer, audience and secret are same on both servers.

If you provide complete source code I can try to investigate more.

Read More

Tuesday, February 7, 2017

How to read MVC OWIN AuthenticationProperties?

Leave a Comment

I'm setting IsPersistent when signing the user in, how to read that value back?

var identity = await UserManager.CreateIdentityAsync(appUser, DefaultAuthenticationTypes.ApplicationCookie); HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties() { IsPersistent = false }, identity); 

1 Answers

Answers 1

Since there isn't much description, I am not sure about the context. Anyway, you can get all the AuthenticationProperties that were provided with the sign in call when you perform authentication on the current request. Code would be..

AuthenticateResult authenticateResult = await HttpContext.GetOwinContext().Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ApplicationCookie);  AuthenticationProperties yourAuthenticationProperties = authenticateResult.Properties; 
Read More

Friday, February 3, 2017

Websockets using OWIN

Leave a Comment

All the examples using Microsoft WebSockets over a web-api that I've seen so far use IIS, the implementation is on the get method the HTTP connection is upgraded to a websocket and an instance of websocket handler is passed to the HTTPContext

public HttpResponseMessage Get() {   if (HttpContext.Current.IsWebSocketRequest) {      var noteHandler = new NoteSocketHandler();      HttpContext.Current.AcceptWebSocketRequest(noteHandler);   }   return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols); } 

What am trying to achieve is to do the same on an OWIN pipeline. The problem am facing is the connection is being upgraded to use Websockets but it is not utilizing my websocket handler. Where am I going wrong? Please suggest.

Controller utilizing OwinContext (Followed the example WebSockets in Nancy using OWIN),

public HttpResponseMessage Get() {    IOwinContext owinContext = Request.GetOwinContext();     WebSocketAccept acceptToken = owinContext.Get<WebSocketAccept>("websocket.Accept");    if (acceptToken != null) {       var requestHeaders = GetValue<IDictionary<string, string[]>>(owinContext.Environment, "owin.RequestHeaders");        Dictionary<string, object> acceptOptions = null;       string[] subProtocols;       if (requestHeaders.TryGetValue("Sec-WebSocket-Protocol", out subProtocols) && subProtocols.Length > 0) {          acceptOptions = new Dictionary<string, object>();          // Select the first one from the client          acceptOptions.Add("websocket.SubProtocol", subProtocols[0].Split(',').First().Trim());       }        acceptToken(acceptOptions, async wsEnv => {          var wsSendAsync = (WebSocketSendAsync)wsEnv["websocket.SendAsync"];          var wsRecieveAsync = (WebSocketReceiveAsync)wsEnv["websocket.ReceiveAsync"];          var wsCloseAsync = (WebSocketCloseAsync)wsEnv["websocket.CloseAsync"];          var wsCallCancelled = (CancellationToken)wsEnv["websocket.CallCancelled"];           //should I pass the handler to an event?          var handler = new NoteSocketHAndler();                      });     } else {       return new HttpResponseMessage(HttpStatusCode.BadRequest);    }    return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols); } 

Handler Code:

using System; using Socket = Microsoft.Web.WebSockets; using Newtonsoft.Json;  public class NoteSocketHandler : Socket.WebSocketHandler {    private static Socket.WebSocketCollection connections = new Socket.WebSocketCollection();     public NoteSocketHandler() {    }     public override void OnOpen() {       connections.Add(this);    }     public override void OnClose() {       connections.Remove(this);    }     public override void OnMessage(string message) {       ChatMessage chatMessage = JsonConvert.DeserializeObject<ChatMessage>(message);       foreach (var connection in connections) {          connection.Send(message);       }    } } 

0 Answers

Read More

Wednesday, September 14, 2016

How to save new record with hashed password in my custom table instead of aspnet user?

1 comment

I am using asp.net identity to create new user but getting error:

Cannot insert the value NULL into column 'Id', table 'Mydb.dbo.AspNetUsers'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated

But here i dont have any such table like AspNetUsers but instead i have my own table that is Users.

Code: Web.config: 2 conection strings

 <add name="myEntities" connectionString="metadata=res://*/DataModel.csdl|res://*/DataModel.ssdl|res://*/DataModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=;initial catalog=mydb;user id=sa;password=sdfsdfsdf;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />  <add name="MyConnString" connectionString="data source=;initial catalog=Mydb;user id=sa;password=sdfsdfsdf;" providerName="System.Data.SqlClient" /> 

IdentityModel.cs:

public class ApplicationUser : IdentityUser     {         public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)         {             // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType             this.SecurityStamp = Guid.NewGuid().ToString();             var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);             // Add custom user claims here             return userIdentity;         }          public string Id { get; set; }         public string FirstName { get; set; }         public string LastName { get; set; }         public virtual string Email { get; set; }         public string Password { get; set; }         public string Role { get; set; }         public Nullable<bool> IsActive { get; set; }         public Nullable<int> CreatedBy { get; set; }         public Nullable<System.DateTime> CreatedDate { get; set; }         public Nullable<System.DateTime> LastLogin { get; set; }          public ApplicationUser()         {          }          public ApplicationUser(string email, string firstName, string lastName, string designation, bool isActive)         {             Email = email;             FirstName = firstName;             LastName = lastName;             Designation = designation;             IsActive = isActive;         }     }   public class ApplicationDbContext : IdentityDbContext<ApplicationUser>     {         public ApplicationDbContext()             : base("MyConnString", throwIfV1Schema: false)         {         }          public static ApplicationDbContext Create()         {             return new ApplicationDbContext();         }     } 

UserStore1.cs:

public class UserStore1 : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>     {         private readonly HttpContext _httpContext;         UserStore<IdentityUser> userStore = new UserStore<IdentityUser>(new ApplicationDbContext());          public System.Threading.Tasks.Task CreateAsync(ApplicationUser user)         {             HttpContext.Current = _httpContext ?? HttpContext.Current;             var context = userStore.Context as ApplicationDbContext;            context.Users.Add(user);            context.Configuration.ValidateOnSaveEnabled = false;            context.SaveChanges();             return Task.FromResult(true);         }      } 

Controller:

     [Authorize]     public class AccountController : Controller     {         public AccountController()             : this(new UserManager<ApplicationUser>(new UserStore1()))         {         }          public AccountController(UserManager<ApplicationUser> userManager)         {             UserManager = userManager;         }         public UserManager<ApplicationUser> UserManager { get; private set; } [HttpPost]         [AllowAnonymous]         [ValidateAntiForgeryToken]         public async Task<ActionResult> Login(string email, string password, bool rememberMe = false, string returnUrl = null)         {             if (ModelState.IsValid)             {                 var user = new ApplicationUser                 {                     FirstName= "Abc",                     LastName= "Pqr",                     UserName="Abc@yahoo.com",                     SecurityStamp = Guid.NewGuid().ToString()                 };                  var result= await UserManager.CreateAsync(user,"123456");             }             return View();         }     } 

Note:I have autogenerated Id in my database table field and that Id is Int

Update:I am using database first(edmx) and the table that i am using are custom tables for inserting new records(for eg:**Users)

At first i have implemented microsoft asp.net identity as shown in below question but 1 user pointed out that i am not using ApplicationUser class which is respossible for handling sign in,cookies etc so i am now trying to use ApplicationUser class:

How to give custom implementation of UpdateAsync method of asp.net identity?

I am really now regretting over my decision to choose microsoft identity framework for Authentication purpose as because i am really finding it complex but now as i have move forward i have to go with it.

Can anybody please help me??

1 Answers

Answers 1

The inconsistency i found, in ApplicationUser class you are declaring property Idand Email which is wrong because the IdentityUser class already have those properties. This may arise the issue. But you can override them if necessary. Also the constructor you are using isn't necessary. The ApplicationUser class should be:

public class ApplicationUser : IdentityUser {     public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)     {         // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType         this.SecurityStamp = Guid.NewGuid().ToString();         var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);         // Add custom user claims here         return userIdentity;     }      public string FirstName { get; set; }     public string LastName { get; set; }         public string Password { get; set; }     public string Role { get; set; }     public bool? IsActive { get; set; }     public int? CreatedBy { get; set; }     public DateTime? CreatedDate { get; set; }     public DateTime? LastLogin { get; set; }  } 

Second thing, you are creating the user inside Login action which is also not valid. you should do it inside Register action. Following in an example:

 public async Task<ActionResult> Register(RegisterViewModel model)     {         if (ModelState.IsValid)         {           var user = new ApplicationUser             {                 FirstName = "Abc",                 LastName = "Pqr",                 UserName = "Abc@yahoo.com",                 Email= model.Email,                 Password= model.Password,                 PasswordHash = UserManager.PasswordHasher.HashPassword(model.Password),                 SecurityStamp = Guid.NewGuid().ToString()             };              var result = await UserManager.CreateAsync(user);         if (result.Succeeded)             {                 await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);                                     return RedirectToAction("Index", "Home");             }             AddErrors(result);         }          return View(model);     } 

Hope this will help :)

Read More

Wednesday, April 13, 2016

Generate and validate OWIN user tokens across domains

Leave a Comment

I would like to know whether it's possible to validate ASP.NET Identity user tokens on website 1, generated on website 2.

In my case, both websites actually use the same UserManager, which is defined in an assembly that both sites use. Startup.Auth.cs is identitical for the two sites. However, a token generated on the first site fails to validate on the other one.

Code used on first website to generate token:

string userId = User.Identity.GetUserId(); var manager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); string token = await manager.GenerateUserTokenAsync("SomePurpose", userId); 

Then passed as query parameters to the other website:

var manager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();  if (await manager.VerifyUserTokenAsync(userId, "SomePurpose", token))  {     // Do something } 

Validation always fails in this scenario. If I validate the token on the same site where it was generated, it passes.

Here's how the token provider is assigned in ApplicationUserManager (options.DataProtectionProvider is of type CallDataProtectionProvider at runtime):

var dataProtectionProvider = options.DataProtectionProvider;  if (dataProtectionProvider != null) {     manager.UserTokenProvider =         new DataProtectorTokenProvider<UserProfile>(dataProtectionProvider.Create("SomeName")); } 

Is this behavior intentional or am I doing something wrong?

1 Answers

Answers 1

It turns out token generation and verification use the machine key. To generate/verify, the websites need to have the same machineKey configured.

Read More

Wednesday, March 30, 2016

Where does OAuthAuthorizationServerProvider check Refresh Token Expiry?

Leave a Comment

I have implemented an authorization server following the article

http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

I've implemented it almost exactly like the article, but I dont see how the auth server knows the refresh token is expired. Indeed I've tested and the server does not grant access tokens when presented expired refresh tokens, but I dont see the logic for this in my auth server. Further, when I request an access token using an expired refresh token the my OAuthAuthorizationServerProvider sub class is never called at all, actually none of my methods in my OAuthAuthorizationServerProvider derived class or my IAuthenticationTokenProvider implementation are called when I request a new access token using an expired refresh token. Any help is appreciated. Here is what I have

public class SmartCardOAuthAuthenticationTokenProvider : IAuthenticationTokenProvider {     private IDataAccessFactoryFactory _producesFactoryThatProducesIAuthenticateDataAccess;     public SmartCardOAuthAuthenticationTokenProvider(IDataAccessFactoryFactory producesFactoryThatProducesIAuthenticateDataAccess)     {         _producesFactoryThatProducesIAuthenticateDataAccess = producesFactoryThatProducesIAuthenticateDataAccess;      }     public async Task CreateAsync(AuthenticationTokenCreateContext context)     {         var clientid = context.Ticket.Properties.Dictionary["as:client_id"];          if (string.IsNullOrEmpty(clientid))         {             return;         }          var refreshTokenId = Guid.NewGuid().ToString("n");          using(IDataAccessFactory producesIAuthenticateDataAccess = _producesFactoryThatProducesIAuthenticateDataAccess.GetDataAccessFactory())//using (IAuthorizationDataAccess _repo = new AuthRepository())         {             IAuthorizationDataAccess _repo = producesIAuthenticateDataAccess.GetDataAccess<IAuthorizationDataAccess>();              var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");              var token = new RefreshToken()             {                 RefreshTokenId = Helper.GetHash(refreshTokenId),                 ClientId = clientid,                 Subject = context.Ticket.Identity.Name,                 IssuedUtc = DateTime.UtcNow,                 ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))             };              context.Ticket.Properties.IssuedUtc = token.IssuedUtc;             context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;              token.ProtectedTicket = context.SerializeTicket();              var result = await _repo.AddRefreshTokenAsync(token);              if (result)             {                 context.SetToken(refreshTokenId);             }          }     }      public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)     {          var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");         context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });          string hashedTokenId = Helper.GetHash(context.Token);          //using (IAuthorizationDataAccess _repo = new AuthRepository())         //{         using (IDataAccessFactory producesIAuthenticateDataAccess = _producesFactoryThatProducesIAuthenticateDataAccess.GetDataAccessFactory()) //using (AuthRepository _repo = new AuthRepository())         {             IAuthorizationDataAccess _repo = producesIAuthenticateDataAccess.GetDataAccess<IAuthorizationDataAccess>();              var refreshToken = await _repo.FindRefreshTokenAsync(hashedTokenId);              if (refreshToken != null)             {                 //Get protectedTicket from refreshToken class                 context.DeserializeTicket(refreshToken.ProtectedTicket);                 var result = await _repo.RemoveRefreshTokenAsync(hashedTokenId);             }         }     }      public void Create(AuthenticationTokenCreateContext context)     {         throw new NotImplementedException();     }      public void Receive(AuthenticationTokenReceiveContext context)     {         throw new NotImplementedException();     } }  public class SmartCardOAuthAuthorizationProvider : OAuthAuthorizationServerProvider {     private IDataAccessFactoryFactory _producesFactoryThatProducesIAuthenticateDataAccess;     public SmartCardOAuthAuthorizationProvider(IDataAccessFactoryFactory producesFactoryThatProducesIAuthenticateDataAccess)     {         _producesFactoryThatProducesIAuthenticateDataAccess = producesFactoryThatProducesIAuthenticateDataAccess;      }     public override System.Threading.Tasks.Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)     {         var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");          if (allowedOrigin == null) allowedOrigin = "*";          context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });          if (context.UserName != "onlyOneHardCodedUserForSakeOfExploration" && context.Password!="thePassword")         {             context.SetError("invalid_grant", "the user name or password is incorrect");             return Task.FromResult<object>(null); ;         }         ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType);         identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));         identity.AddClaim(new Claim("sub", context.UserName));         identity.AddClaim(new Claim(ClaimTypes.Role, "PostVSDebugBreakModeEnterEventArgs"));         identity.AddClaim(new Claim(DatawareClaimTypes.SmartCardUserId.ToString(), 1.ToString()));          var props = new AuthenticationProperties(new Dictionary<string, string>             {                 {                      "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId                 },                 {                      "userName", context.UserName                 }             });          var ticket = new AuthenticationTicket(identity, props);         //ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddDays(2));         context.Validated(ticket);          return Task.FromResult<object>(null);     }      public override System.Threading.Tasks.Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)     {          string clientId = string.Empty;         string clientSecret = string.Empty;         Client client = null;          if (!context.TryGetBasicCredentials(out clientId, out clientSecret))         {             context.TryGetFormCredentials(out clientId, out clientSecret);         }          if (context.ClientId == null)         {             //Remove the comments from the below line context.SetError, and invalidate context              //if you want to force sending clientId/secrects once obtain access tokens.              //context.Validated();             context.SetError("invalid_clientId", "ClientId should be sent.");             return Task.FromResult<object>(null);         }          string[] clientIdClientUnique = context.ClientId.Split(':');          if (clientIdClientUnique == null || clientIdClientUnique.Length <= 1)         {             context.SetError("invalid_client_unique");             return Task.FromResult<object>(null);         }          clientId = clientIdClientUnique[0];         string clientUnique = clientIdClientUnique[1];          using (IDataAccessFactory producesIAuthenticateDataAccess = _producesFactoryThatProducesIAuthenticateDataAccess.GetDataAccessFactory()) //using (AuthRepository _repo = new AuthRepository())         {             IAuthorizationDataAccess _repo = producesIAuthenticateDataAccess.GetDataAccess<IAuthorizationDataAccess>();               client = _repo.FindClient(clientId);//new Client { Active = true, AllowedOrigin = "*", ApplicationType = ApplicationTypes.DesktopClient, ClientId = context.ClientId, Name = "Visual Studio Event Source", RefreshTokenLifeTimeInMinutes = 14400, Secret = Helper.GetHash(clientSecret) };//_repo.FindClient(context.ClientId);         }          if (client == null)         {             //context.SetError("invalid_client_unique");             context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId));             return Task.FromResult<object>(null);         }          if (string.IsNullOrWhiteSpace(clientSecret))         {             context.SetError("invalid_clientId", "Client secret should be sent.");             return Task.FromResult<object>(null);         }         else         {             if (client.Secret != Helper.GetHash(clientSecret))             {                 context.SetError("invalid_clientId", "Client secret is invalid.");                 return Task.FromResult<object>(null);             }         }          if (!client.Active)         {             context.SetError("invalid_clientId", "Client is inactive.");             return Task.FromResult<object>(null);         }          context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);         context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTimeInMinutes.ToString());          context.Validated();         return Task.FromResult<object>(null);     }      public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)     {         var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];         var currentClient = context.ClientId;          if (originalClient != currentClient)         {             context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");             return Task.FromResult<object>(null);         }          // Change auth ticket for refresh token requests         var newIdentity = new ClaimsIdentity(context.Ticket.Identity);         newIdentity.AddClaim(new Claim("newClaim", "newValue"));          var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);         context.Validated(newTicket);          return Task.FromResult<object>(null);     }      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);     }  } 

Again, when I make a request

request with expired refresh and the refresh token is expired, NONE of the above classes\methods get hit. Further, the refresh token passed to the API is nothing more than the GUID I generated in the SmartCardOAuthAuthenticationTokenProvider.CreateAsync it contains no information about expiry. If none of the above methods are hit when requesting access by refresh and the request passes nothing(it looks like nothing) when requesting a new access token by refresh then how does the server know the refresh token is expired?

Looks like magic to me.

UPDATE 1 - Add Startup code

public static class OwinStartUpConfig {     public static void Configure(HttpConfiguration configFromOwinStartup)     {         configFromOwinStartup.MapHttpAttributeRoutes();         configFromOwinStartup.Routes.MapHttpRoute("Default", "{controller}/{id}", new { id = RouteParameter.Optional });          var jsonFormatter = configFromOwinStartup.Formatters.OfType<JsonMediaTypeFormatter>().First();         jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();          RegiserDependencies(configFromOwinStartup);      }      public static void RegiserDependencies(HttpConfiguration configFromOwinStartup)     {         string connectionStringForSmartCardDbCntx = System.Configuration.ConfigurationManager.ConnectionStrings["SmartCardDataContext"].ConnectionString;         string projectNameWhenNewProjectCreatedDueToNoMatch = System.Configuration.ConfigurationManager.AppSettings["ProjectNameWhenNewProjectCreatedDueToNoMatch"];          Autofac.ContainerBuilder builderUsedToRegisterDependencies = new Autofac.ContainerBuilder();          builderUsedToRegisterDependencies.RegisterType<DataAccessFactoryFactoryEf>()             .As<IDataAccessFactoryFactory>()             .WithParameter(new TypedParameter(typeof(string), connectionStringForSmartCardDbCntx));          builderUsedToRegisterDependencies.Register(             c =>                     new List<IProjectActivityMatch<VSDebugBreakModeEnterActivity>>             {                 new MatchVSProjectWithMostRecentActivity<VSDebugBreakModeEnterActivity>(),                 new MatchVSSolutionWithMostRecentActivityActivityMatch<VSDebugBreakModeEnterActivity>(),                 new MatchMostRecentActivityMatch<VSDebugBreakModeEnterActivity>(),                 new MatchToNewProjectActivityMatch<VSDebugBreakModeEnterActivity>(projectNameWhenNewProjectCreatedDueToNoMatch)             }         ).As<IEnumerable<IProjectActivityMatch<VSDebugBreakModeEnterActivity>>>();          builderUsedToRegisterDependencies             .RegisterType<MatchDontGiveUpActivityMatch<VSDebugBreakModeEnterActivity>>()             //.WithParameter(Autofac.Core.ResolvedParameter.ForNamed<IEnumerable<IProjectActivityMatch<VSDebugBreakModeEnterActivity>>>("VSDebugBreakModeEnterActivityMatchers"))             .As<IProjectActivityMatch<VSDebugBreakModeEnterActivity>>();          builderUsedToRegisterDependencies             .RegisterType<VSDebugBreakModeEnterEventArgsEventSaver>()             .Named<ISaveVisualStudioEvents>("VSDebugBreakModeEnterSaver");          builderUsedToRegisterDependencies             .RegisterType<VSDebugBreakModeEnterEventArgsController>()             .WithParameter(Autofac.Core.ResolvedParameter.ForNamed<ISaveVisualStudioEvents>("VSDebugBreakModeEnterSaver"));          var container = builderUsedToRegisterDependencies.Build();          configFromOwinStartup.DependencyResolver = new AutofacWebApiDependencyResolver(container);      } }     public static class OAuthStartupConfig {     internal static void Configure(IAppBuilder app)     {         OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions         {             AllowInsecureHttp = false,             TokenEndpointPath = new PathString("/token"),             AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), //TimeSpan.FromDays(1),             Provider = new SmartCardOAuthAuthorizationProvider(new AuthorizationDataAccessFactoryFactory()),             RefreshTokenProvider = new SmartCardOAuthAuthenticationTokenProvider(new AuthorizationDataAccessFactoryFactory())         };         app.UseOAuthAuthorizationServer(oAuthServerOptions);         app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());     } } 

UPDATE - In response to comments

request for access token by pass returns access and refresh token

The access token in the above response contains claims information and the expiry information for the access token. All that info is serialized by the server into the access token above. So, I can see how the access token's expiry is checked. However, what about the refresh token? When a request for an access token is make using the refresh token:

enter image description here

In the request above the refresh token is good and so the request for the access token by refresh token is granted, but if the refresh token were expired how would OAuthAuthorizationServerProvider check the refresh token for expiry?

Again, I have checked that the code provided above does indeed check for expired refresh tokens and does not grant an access token if the refresh token is expired, but HOW does it know? I didnt write anything for checking refresh token expiry into my OAuthAuthorizationServerProvider derived class. So then how????

UPDATE

The magic happens in the ReceiveAsync method of the IAuthenticationTokenProvider implementation.

public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)     {          var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");         context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });          string hashedTokenId = Helper.GetHash(context.Token);          //using (IAuthorizationDataAccess _repo = new AuthRepository())         //{         using (IDataAccessFactory producesIAuthenticateDataAccess = _producesFactoryThatProducesIAuthenticateDataAccess.GetDataAccessFactory()) //using (AuthRepository _repo = new AuthRepository())         {             IAuthorizationDataAccess _repo = producesIAuthenticateDataAccess.GetDataAccess<IAuthorizationDataAccess>();              var refreshToken = await _repo.FindRefreshTokenAsync(hashedTokenId);              if (refreshToken != null)             {                 //Get protectedTicket from refreshToken class                 context.DeserializeTicket(refreshToken.ProtectedTicket);                 var result = await _repo.RemoveRefreshTokenAsync(hashedTokenId);             }         }     } 

Particularly the line context.DeserializeTicket(refreshToken.ProtectedTicket); is the magic. That will set the context.Ticket property. After the method ReceiveAsync has completed its done. No need to manually check anything OWIN, somewhere behind the scenes, knows the ticket is expired.

2 Answers

Answers 1

I've implemented it almost exactly like the article, but I dont see how the auth server knows the refresh token is expired.

You have to save that information somewhere, for example in a sql table. When you receive a request to emit a new token with a refresh token, there you have to check if the submitted refresh token is still valid, based on the information you have on you local source of truth.

For example, this is the I implemented it:

    public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)     {         var allowedOrigin = context.OwinContext.Get<string>(Constants.PublicAuth.CLIENT_ALLOWED_ORIGIN);         context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {allowedOrigin});          RefreshTokenModel refreshToken = await _mediator.SendAsync(new VerifyRefreshToken(context.Token));          if (refreshToken != null)         {             context.DeserializeTicket(refreshToken.ProtectedTicket);         }     } 

And this is the query handler:

public async Task<RefreshTokenModel> Handle(VerifyRefreshToken query)         {             RefreshToken refreshToken = await Context.RefreshTokens                 .Where(rt => rt.Token == query.Token)                 .FirstOrDefaultAsync();              if (refreshToken == null || refreshToken.ExpiresUtc < DateTimeOffset.UtcNow) return null;              User user = await Context.Users.Where(u => u.Email == refreshToken.Subject).SingleOrDefaultAsync();             if (user == null || (user.LockoutEnabled && user.LockoutEndUtc > DateTimeOffset.UtcNow)) return null;              return new RefreshTokenModel             {                 ProtectedTicket = new UTF8Encoding(true).GetString(refreshToken.ProtectedTicket)             };         } 

As you can see, if the doesn't exists, or the token expiration point has passed, I return null; null means no token, so the ReceiveAsync(AuthenticationTokenReceiveContext context) will return nothing, and a 401 Unauthorized will be emitted.

Answers 2

The magic happens in the ReceiveAsync method of the IAuthenticationTokenProvider implementation.

Particularly the line context.DeserializeTicket(refreshToken.ProtectedTicket); is the magic I was missing. That will set the context.Ticket property. After the method ReceiveAsync has completed its done. No need to manually check anything OWIN, somewhere behind the scenes, knows the ticket is expired.

Read More

Tuesday, March 29, 2016

Why does Owin.Hosting.StartOptions require admin permissions?

Leave a Comment

I have an application that is making use of Owin's self host functionality.

The application doesn't need administrator permissions but when I use the following code if it's not run as admin I get an exception thrown due to 'access denied'

var options = new StartOptions {     ServerFactory = "Microsoft.Owin.Host.HttpListener" }; options.Urls.Add("http://+:3579/");  using (WebApp.Start<Startup>(options)) { // ..  }  

I need to provide the start options otherwise I get HTTP 503 error (See here)

Here is the exception when run as regular user (non-admin)

at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.Owin.Hosting.ServerFactory.ServerFactoryAdapter.Create(IAppBuilder builder) at Microsoft.Owin.Hosting.Engine.HostingEngine.StartServer(StartContext context) at Microsoft.Owin.Hosting.Engine.HostingEngine.Start(StartContext context) at Microsoft.Owin.Hosting.Starter.DirectHostingStarter.Start(StartOptions options) at Microsoft.Owin.Hosting.Starter.HostingStarter.Start(StartOptions options) at Microsoft.Owin.Hosting.WebApp.StartImplementation(IServiceProvider services, StartOptions options) at Microsoft.Owin.Hosting.WebApp.Start(StartOptions options) at Microsoft.Owin.Hosting.WebApp.Start[TStartup](StartOptions options) at PlexRequests.UI.Program.Main(String[] args) in C:\Users\Jamie\Documents\GitHubVisualStudio\PlexRequests.Net\PlexRequests.UI\Program.cs:line 93 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() 

Inner exception:Access is Denied

0 Answers

Read More