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

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?

Related

Why do we need to use the front-channel for an OAuth authorization request?

I've been struggling with this and would love to see if any OAuth experts here have an answer.
For context, I'm trying to integrate OAuth into an existing first-party (internal) front-end client that lives on a subdomain. It's a single-page application. I have an authorization server that has an /oauth2/authorize and oauth2/token endpoint and I'm working with the OAuth 2 with PKCE authorization flow.
In all the examples I've seen externally, it seems like the recommendation is to make a top-level redirect to the authorization URL initial login . And for silently re-authenticating a user (if they were already logged in), using an invisible iFrame set to the authorization URL (and postMessaging the code back to the parent window).
I'm trying to understand what prevents me from making a front-channel request to my /authorize endpoint via Javascript. Something simple like...
const { state, code } = await fetch(authorizationUrl)
For the login case, I can handle a 403 error back from the AS and then redirect them to login from the client-side. For the re-authenticating case (i.e. client has an expired refresh token but is still logged in), this is great because I just get a 200 response and the code back directly in the JSON body and I can use it immediately. There is no top-level redirect, no hassle of saving app state, etc.
It seems like as long as the AS is willing to return the { state, code } via JSON, this should work. This means that
The AS authorize endpoint must be configured to allow CORS on select origins. This seems okay in a first-party context since I know which origins I should allow.
The AS must be sent client credentials (session cookies) with the request (otherwise the AS would have no idea how to determine if the user is logged in). In JS, this would be as simple as adding credentials: true. As long as the cookie credentials have Same-Site: None and the cookie is part of the same domain (cross-domain would not work since some browsers disable cross-site cookie sharing nowadays!)
I feel like I'm missing something crucial here. But at the same time, my prototype is working, so I'd love to get some input from experienced folks here.

Login user via GET (basic auth header) or POST

I've been doing some HTTP methods and header research recently if we should use GET with basic authorization instead of POST when submitting?
HTTP Methods
The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
The POST method submits an entity to the specified resource, often causing a change in state or side effects on the server.
As we see here, the POST method normally changes the state of the server. If sending out JWTs/HTTP cookies, we are not modifying the state of the server. Nor are we creating a new resource in the server.
I understand that we should not not send the username and password as a GET parameter but should we use the authorization header instead?
Basic authentication
For "Basic" authentication the credentials are constructed by first combining the username and the password with a colon (aladdin:opensesame), and then by encoding the resulting string in base64 (YWxhZGRpbjpvcGVuc2VzYW1l).
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
The only advantage I see to using POST over GET is that we need no extra code in the HTML/JS on the client side to send headers via the fetch API. To send headers, we would need an onsubmit and then check if status code is 200. If 200, we will need to redirect to the page after the login screen. Then again, if using the fetch API, this means the server does not need to send a new HTML page to the client all the time either.
Should we use GET with basic auth or POST when logging in since we don't create a resource/modify the server state?
Would this change if say we enable 2FA since we would need to generate a code for that user?
Doing basic authentication in the browser and using GET is not that recommended.
To do your own login form it is better to always do it using HTTPS and POST. Do post the username/password in the body of the request and secure it with proper CSRF protection.
If you want to level up, you can always look at the OpenIDConnect approach, but that is more advanced depending on your needs.
Also, a good approach is to explore how existing site implement a login form and look at the HTTP(s) traffic in a tool like Fiddler.

how to skip Preflight Requset in vue with content-type:application/json

error :"405 not allowed Method" in post method type call in request command vue
i need call api function with content-type:application/json and post Method type with request command in vue ,but browser add preflight request with options method type and it causes this error :"405 not allowed Method"
var options = {
method: "POST",
url: "http://api.sample.com/login",
headers: {
"Access-Control-Request-Method":"POST",
"cache-control": "no-cache",
"content-type": "application/json",
},
body: '{ Username: "demo", Password: "demo", Domain: "test" }'
};
request(options, function(error, response, body) {
if (error) throw new Error(error);
body.data;
alert("ok");
});
The OPTIONS call is done whenever you do a cross-origin request. This means the domain your application is running on is different from the domain where the api is. A pre-flight request is mandatory for these requests, because the browser needs to figure out if you are allowed to do these requests. A 405 error means that the server thinks you are not allowed to make that request.
To solve this problem you can move your api to the same domain as your frontend. Please note that it cannot be on a subdomain.
A different way of solving this, is by sending back the correct headers. In your case you seem to at least miss the Access-Control-Allow-Methods response header. Make sure to send this header and either dynamically figure out which methods are allowed, or do something like the following. That would allow the most common methods to work.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
In the comments you said that you do not have control over the api, and as such cannot change the response header. In that case your best bet is to contact whoever maintains the api and ask how to best use their api.
In the comments you said that this worked fine when you did the same thing in ASP.NET. ASP.NET is a server-side language, which means that requests in that context do not have a concept of "cross-origin". Cross-origin only comes into play in the browser, where the application runs on an actual domain.
Assuming you can set up a proxy on your application domain, you can also create a proxy that proxies all requests to the api you actually want to communicate with. You would deploy your domain on https://example.com and do your requests to https://example.com/api/endpoint. Your proxy will listen for requests that begin with https://example.com/api and proxy it to https://whatever.the.api.is/ with the appropriate endpoint and data.
Please keep in mind that while some api's might just be configured incorrectly, a lack of cross-origin response headers might just mean that the api is nog meant to be consumed through the browser. Part of this could be that the request contains a secret that should not be exposed to users that use your application, but should instead only be on the server. Using a proxy in that case would set you up for impersonation attacks, because you would expose the secret to your application, but defeat the cross-origin headers by making it appear to the application that the api is on the same domain.

Ember.js REST Auth Headers

I've been struggling with this for too long now. I have an Expressjs server that provides an endpoint to login. The response I get has a JWT token, expiring in an hour. All good.
On the Emberjs side, I can successfully authenticate and get the token (using ember-simple-auth and ember-simple-auth-token). This works well for protecting my routes. But I can't for the life of me update the RESTAdapter headers to include my new authorization token.
I've tried:
using $.ajaxPrefilter to set the Authorization header. Didn't work
accessing "this.get('session.secure.token')" from the RESTAdapter. Thats undefined.
Please, if someone could point me in the right direction, I'd be eternally grateful. All I need to do is attach the value in "session.secure.token" to the header for all RESTAdapter requests.
Thanks
You should be able to set the simple-auth config property authorizer to simple-auth-authorizer:token - in the simple-auth code it looks for this config property, looks up simple-auth-authorizer:token and uses this in combination with ajaxPrefilter.
// config/environment.js
ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:token'
};

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>