ASP.NET Core Openiddict throws "An OpenID Connect response cannot be returned from this endpoint" - asp.net-core

I follow instruction in openiddict server example using password flow from https://github.com/openiddict/openiddict-samples/tree/master/samples/PasswordFlow
but have no success.
It throws InvalidOperationException: An OpenID Connect response cannot be returned from this endpoint at route /connect/token:
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
Postman params:
Content-Type: application/x-www-form-urlencoded
Params: username=..&password=...&grantType=password&scope=offline_access+profile+email
I spent my day for researching but there is no information about cannot be returned from this endpoint exception. And many people can run openiddict example except me.
Here is apart of Startup.cs:
services.AddEntityFrameworkSqlite()
.AddDbContext<MisapayContext>(options =>
{
options.UseOpenIddict<int>();
});
//....
services.AddOpenIddict<int>()
.AddEntityFrameworkCoreStores<MisapayContext>()
.DisableHttpsRequirement()
.EnableTokenEndpoint("/connect/token")
.EnableLogoutEndpoint("/connect/logout")
.EnableUserinfoEndpoint("/connect/userinfo")
.UseJsonWebTokens()
.AllowPasswordFlow()
.AllowRefreshTokenFlow()
.AddEphemeralSigningKey();
services.AddMvc(config =>
{
config.Filters.Add(new ApiExceptionFilter());
}).AddJsonOptions(options =>
{
options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
});
Edited: I think problem is OpenIdConnectRequest, it can not be binded if use:
OpenIddictBuiler.AddMvcBinders()
Will throws The OpenID Connect request cannot be retrieved from the ASP.NET context.`
Otherwise, remove it, OpenIdConnectRequest in AuthorizationController can get properly. And I can get request information such as username, password grantType etc... Strange... right?
Some other information:
Asp.net Core SDK 1.1
Project.json : https://gist.github.com/trinvh/47f29468887c209716098bc4c76181a7
Startup.cs: https://gist.github.com/trinvh/75b7a12fbee754d0ea8cf251f2da9fe9
AuthorizationController.cs: https://gist.github.com/trinvh/089015b2573cae550856631e72b81374
Any help will be appreciated!

Okay, here's what's happening:
You've configured OpenIddict to use /connect/token as the token endpoint address.
The token request you send via Postman points to /connect/token/, which is actually a totally different URL (/connect/token != /connect/token/).
Since the address differs from the registered endpoint path, OpenIddict doesn't handle the request and refuses to consider it as a token request.
For some reasons, MVC accepts to handle your /connect/token/ request and invokes the Exchange action, even though the route doesn't match the requested URL.
Since you haven't registered the OpenIddict MVC binder in the MVC options, MVC uses its default binder to construct the OpenIdConnectRequest object, which allows the OpenIdConnectRequest.GrantType parameter to be resolved from the invalid grantType parameter (it wouldn't happen with the dedicated OpenIddict binder).
Your token endpoint action ends up calling SignIn to return a token response.
Under the hood, OpenIddict detects that you called SignIn outside the normal token request processing - since it didn't consider the request as a token request, due to the paths difference - and aborts this unsafe operation by throwing an InvalidOperationException.
I'll ping the MVC folks to make sure they are aware of this bug.
Edit: after some research, it looks like this behavior is "by design" and was inherited from ASP.NET MVC. I opened a feature request in the aspnet/Mvc repository to add a new way to use "strict comparison" for routes matching.

Related

AXIOS url is case sensitive

I have worked on an Application that uses ASP.NET Core and VueJs. VueJs calls asp.net core controller using AXIOS. Everything is working fine. I was able to publish the site on IIS.
The problem starts when I type url of my web site in lower case.
The url of my web site is
http://10.131.XXX.XXX:94/MyWeb.
Internally axios calls the controller method on the same url.
for example internally in vue js component, I have written something like this
this.API_URL="http://10.131.XXX.XXX:94/MyWeb
axios.post(this.API_URL + '/UserManagement/GetAllUser', postData);
But if type the following url of my web site
http://10.131.XXX.XXX:94/myweb
then axios is not able to call the controller method and return status code 400 -Bad Request.
I am updating my question. because found a few more hint on issues.
[1] Bad Request error gone if I remove ValidateAntiForgeryToken attribute from asp.net core controller method.I add RequestVerificationToken in axios header. but If my request is to myweb this is not avaliable.
[2] My asp.net core controller calls Web API and I am using token authentication there. I keep token in Claim but that Claim is not available when i do request from axios to myweb instead of MyWeb.
Two things on web side using cookie based authentication and for web api using token authentication.
I FIGURE OUT THAT POST REQUEST IS FAILING FROM AXIOS JUST BECAUSE OF ANTIFORGERY TOKEN IN ASP.NET CORE. ALSO WHEN I LOGIN USING LOWERCASE WEBSITE NAME AUTHORIZE ATTRIBUTE REJECTS REQUEST.
I am setting correct token in axios
headers: {
'RequestVerificationToken': xshrfToken,
'Content-Type': 'application/json;charset=utf-8;'
}
so my question is that if I change the website name to lower case why POST request fails.
Any suggestion?
You could use axios interceptor as a hook:
axios.interceptors.request.use(function(response) {
response.url = response.url.toLowerCase();
return response;
});

SignalR Core JS Client not passing Authorisation headrs on "Upgrade " Request

I Have to implement a push notification service using ASP .Net Core. as obvious choice is to use SignalR Core.
Our platform setup is using Azure App gateway and it is configured to not allow unauthenticated requests.
We have setup WebSockets communication with SignalR.
Under the hood , SignalR Core follows these steps:
POS ../negociate -> OK with hub_token and supported transport
GET (sends Upgrade header and WebSockets token)../Hub?id={hub_token} -? fail
when investigating why the step 2 does not upgrade the connection to a WebSocket connection , I have noticed that the GET request is missing Authorization header. Obviously AG block this request and doesn't even get to the API.
I have tried manually to make a "handshake" with postman.
the above steps :
OK
included Authorization JWT header -> result 101 ,and Fiddler confirm the connection is opened.
I have researched the documentation and found that Authorization headers are not supported.
did anyone tried any workaround ? hen is the next release of the #aspnet/signalr client?
Did you specified the accessTokenFactory?
let connection = new signalR.HubConnectionBuilder()
.withUrl("/myhub", {
accessTokenFactory: () => {
// Get and return the access token.
// This function can return a JavaScript Promise if asynchronous
// logic is required to retrieve the access token.
}
})
.build();
More info here.
so the final resolution is:
that in browsers is a limitation for sending JWT header along with HTTP 101 UPGRADE

Web API, return 403 when /token call is not secure

We have a Web API 2 REST service. We're using the basic OWIN oAuth token authentication and we require https. We've added a RequireHttpsAttribute filter that checks and returns back a 403 HTTPS Required error when request is made with basic http.
The problem is our /token request. When we request our token we're NOT returning back the 403 error. In the Startup.Auth.cs config file we set AllowInsecureHttp=false. So this prevents users from requesting a token with an insecure call.
However, when this call is made we get a 404 Not Found error, not the 403 HTTPS Required that we want. Can anyone help me figure out how to fix this error?
I realize we're not using the RequireHttpsAttribute because this is happenign outside of the normal authentication, this is how we get the token FOR that authentication. So I'm not sure where I should be checking for the secure connection. I tried in the AuthenticationOAuthProviders class, in GrantResourceOwnersCredentials method. Before authenticating username and password I put in a check for https but I wasn't able to raise an HTTP Code error from there.
You could try using a simple Owin middle-ware at the beginning of your Owin pipeline, instead of a Web API filter. This way you'll catch every request made to your application.
Here is a small sample:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(async (ctx, next) =>
{
if (ctx.Request.Scheme.Equals(Uri.UriSchemeHttps))
await next.Invoke();
else
ctx.Response.StatusCode = 403;
});
//other middlewares
//app.UseWebApi(..)
}
}

NetworkCredentials and Authorization in WebApi

I am having a few problems trying to connect to a ASP.NET webapi service (which I am running myself) from a sample console app using WebClient. The webapi is the typical sample site from MVC4:
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK, new string[] { "value1", "value2" });
}
The Controller is decorated with a custom Authenticate attribute:
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.Add("WWW-Authenticate", "Basic realm=\"localhost\"");
actionContext.Response = response;
return;
}
}
The client code is the usual:
var wb = WebRequest.Create("http://localhost:64921/Values");
wb.Credentials = new NetworkCredential("xxx", "xxx");
var aaa = wb.GetResponse();
Console.WriteLine(aaa);
Console.ReadLine();
Now, I know that the WebClient or WebRequest are supposed to wait for a 401 before sending credentials and that is exactly what I am trying to do here.
Needless to say with the setup above nothing works. I have gone into the IIS express config and changed the following:
<basicAuthentication enabled="true" /> (in the security section)
<add name="BasicAuthenticationModule" lockItem="false" /> (in the modules section)
The problem that I am having is that the 401 gets returned even before the server code is actualy hit. I mean that if I stick a breakpoint into the Controller or the Attribute they are not hit. The details of the error are the usual long text about error 401.2 which I reckon is something to do with IIS configs, but using IIS express and not the nice IIS I do not have a nice GUI to fix this. Can anyone help?
Thanks a lot!
In the IIS config, you have enabled Basic auth processing, so IIS returns the 401 if there are no credentials or the credentials are invalid.
If you want your code to do the basic auth processing, then you need to tell IIS to allow anonymous access.
EDIT from comments
If you ask IIS to do basic auth it will check credentials against Windows accounts. This will act before the server code runs, so the Custom Auth Filter will not be hit. In this case the headers returned will be correct and you will see the WebClient performing the double request (one anonymous, one with credentials). If the WebClient does not use a computer or domain account (with read permissions on the folder where the site is located), the request will fail.
If you want to do authentication/authorization yourself, you need to tell IIS express not to do any auth and then do it all yourself... this basically means leaving everything as it is in the config (in your case reverting the pieces of config shown in the question) and sending the correct headers, which you already do. If you debug, you will see the Authenticate filter being hit twice, the first time it will be an anonymous that will go inside the if and generate your HTTP 401 Challenge response, the second time it will have credentials in the form of a standard Basic Authorization header: Basic <BASE64_ENCODED_CREDENTIALS>

how do you request a session from servicestack basic authentication, at /auth/basic?

I have set up a servicestack service with basic authentication using the first example, here:
https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization
This automatically sets up a route: /auth/basic
However, I cannot find any information or examples on how to format a request to this URL (Variables/GET/POST/Auth Header, etc.).
I am able to access a simple service using the basic authentication credentials, so they are active and correct.
I have no custom authentication plugged in, just basic authentication.
I have tried:
Using a JsonServiceClient to send UserName and Password variables by GET or Json POST to /auth/basic, with and without an Auth header also containing the user & pass.
Using a browser to send GET requests with URL parameters of the user/pass, or as http://user:pass#localhost:123/auth/basic
I always just get "HTTP/1.1 401 Invalid BasicAuth credentials".
The only examples I can find involve some kind of custom authentication, and then /auth/credentials is accessed, but I want to use /auth/basic
I have looked at the code and it looks like it reads an Auth header, but the service does not accept one.
I am actually trying to get this working so I can then disable it and verify it is disabled (I want to require basic authentication for every request).
Questions are:
What is the correct way to call the /auth/basic service? I will take a servicestack client API example, specifications or even a raw http request!
How do you disable the /auth services altogether?
Many thanks.
What is the correct way to call the /auth/basic service? I will take a servicestack client API example, specifications or even a raw http request!
var client = new JsonServiceClient("http://localhost:56006/api");
var resp = client.Post(new Auth() { UserName = "TestUser", Password = "Password" });
This assumes you have also registered an ICacheClient and IAuthUserRepository (and added a user account)
The JSON format looks like this if you call into /auth/basic?format=json
{
"UserName": "admin",
"Password": "test"
"RememberMe": true
}
How do you disable the /auth services altogether?
Don't add the AuthFeature plugin to configuration.
You can also remove plugins
Plugins.RemoveAll(x => x is AuthFeature);
Putting the following in apphost config seems to do the trick.
//Disable most things, including SOAP support, /auth and /metadata routes
SetConfig(new EndpointHostConfig()
{
EnableFeatures = Feature.Json | Feature.Xml
});
I am a little suspicious about what this does to /auth however, because it returns an empty response, while most routes return 404.
So, would this truly disable the /auth functionality? As in, if someone formed a correct request to /auth/credentials, will it still return an empty response?