HTTP Authentication in Restlet, authenticating child URL - restlet

I am using HTTP Digest authentication mechanism in the server side and client is firefox.
This is the server side code
Application application = new Vehicle();
component.getDefaultHost().attachDefault(application);
component.getDefaultHost().attach("/home",new Home());
DigestAuthenticator guard = new DigestAuthenticator(null, "TestRealm","mySecretServerKey");
Instantiates a Verifier of identifier/secret couples based on a simple Map.
MapVerifier mapVerifier = new MapVerifier();
Load a single static login/secret pair.
mapVerifier.getLocalSecrets().put("login", "secret".toCharArray());
guard.setWrappedVerifier(mapVerifier);
Guard the restlet
guard.setNext(application);
component.getDefaultHost().attachDefault(guard);
component.start();
In home class
Router router = new Router(getContext());
router.attach("/People", People.class);
router.attach("/categories/",Categories.class);
return router;
if i request http://localhost:8182/ Http authentication is working but http://localhost:8182/home/categories/ is not asking for any http authentication if first we try for /home/categories/ instead of http://localhost:8182/ it will give out the result with out any authentication mechanism. How to solve this ?

You are attaching the guard only to the default route, so the routes that are not matching any other routes. See the javadoc for attachDefault :
* Attaches a Resource class to this router as the default target to invoke
* when no route matches. It actually sets a default route that scores all
* calls to 1.0.
Your other routes are not the default routes and so they are not guarded
router.attach("/People", People.class);
router.attach("/categories/",Categories.class);
You must wire the guard between each route that you want to protect like this :
DigestAuthenticator peopleGuard = new DigestAuthenticator(null, "TestRealm","mySecretServerKey");
peopleGuard.setNext(People.class);
router.attach("/People", peopleGuard);

Related

ASP.NET Core Endpoint - route all calls to specific route first

What do I need to change this to route all requests to /api/ShibAuth?
endpoints.MapGet("/", async context =>
{
context.Response.Redirect("/api/ShibAuth");
});
The code above obviously routes any calls to root URL and I've already tried what I though was appropriate wildcard.
What do I need to change this to route all requests to /api/ShibAuth?
Well, if I correctly understand the requirement, you would like all of your request to redirect to this /api/ShibAuth route at the begining.
Certainly, we can implement above scenario using UriBuilder class which provides the functionality to modify HttpRequest.Path. Finally, rebuild the request URI and redirect to your expected path. You can do as following
Solution:
app.MapGet("/", async context =>
{
var originalUrl = context.Request.GetDisplayUrl();
var routeToCallFirst = "api/ShibAuth";
var updatedUrl = (new UriBuilder(originalUrl) { Host = context.Request.Host.Host, Path = routeToCallFirst }).Uri;
context.Response.Redirect(updatedUrl.AbsoluteUri);
});
Output:
Note: Here, I am redirecting the all landing request to /api/ShibAuth controller from the middleware.

Can traefik's forwardAuth middleware be used to secure a browser page (not an api)?

I need to secure a web page with a token stored in a cookie or url param. All examples I can find for using forwardAuth middleware seems to be for securing an API, as it's easy to supply headers in an API request. Sending custom headers isn't an option w/ the browser, so I need to used cookies.
I would like to have the auth token passed in through a query string arg, eg ?token=ABCDEFG, then stored in a cookie for future requests. Here's what the workflow looks like:
I've tried experimenting with forwardAuth to see how I can do this. The auth endpoint reads the Authorization header, but I need something that reads the cookie in the request and transforms that to an Authorization header.
Is there any way this can be done with Traefik?
It looks like the answer is yes. Originally I had thought traefik wouldn't forward cookies, but it does in fact appear to forward cookies.
I ended up creating a "sidecar" auth container on the same host as traefik so that auth requests would be faster.
The auth function looks like this (node/express):
app.get('/auth', (req, res) => {
logger.info('CHECKING AUTH');
const url = new URL(`${req.headers['x-forwarded-proto']}://` +
`${req.headers['x-forwarded-host']}` +
`${req.headers['x-forwarded-uri']}`);
const urlAuthToken = url.searchParams.get('token');
if (urlAuthToken) {
url.searchParams.delete('token');
const domain = BASE_DOMAIN;
const sameSite = false;
const secure = url.protocol === 'https:';
return res
.cookie('auth-token', urlAuthToken, {domain, sameSite, secure})
.redirect(url.toString());
}
// Simulate credentials check
if (req.cookies['auth-token'] === 'my-little-secret') {
return res.status(200).send();
}
return res.status(401).send('<h1>401: Unauthorized</h1>');
});

How to handle redirects to auth provider from the backend in Fable Elmish SPA

I have an AspNetCore backend api (in F# with Giraffe) that uses AzureAD authentication with Microsoft.AspNetCore.Authentication.AzureAD.UI, with stateful session store, and https only cookies.
The frontend is an Elmish SPA compiled to js with Fable.
If I just type into the url bar a protected endpoint of my backend, everything works correctly, if not already signed in, I get redirected to the login.microsoft endpoint, with the clientID and so on, where upon successful signin, the original request completes and I get the response of my protected endpoint.
But if I try to access the same endpoint from the SPA code, eg.: with fetch, or with Fable.Remoting, if not logged in, the backend still redirects but the redirected request to login.microsoft no longer works.
With Fable.Remoting there is a CORS header, that the login endpoint refuses. If I send fetch with nocors, there is a 200 OK response from the login endpoint BUT no response body (eg no html code for the login page) and seemingly nothing happens.
I just have no idea how this should be handled on the SPA side, and could not really find anything about it. Why does the backend include a CORS header in the redirect if initiated from Fable.Remoting vs if initiated from the browser url bar? What is wrong with the fetch-ed response that there is no response body?
I can write just js code into my client, but could not even figure out how would this be handled in a pure js SPA.
Also tried the whole thing in production, to remove the webpack devServer proxy from the equation, but everything stays the same.
First, create "signin" and "signout" routes in Giraffe:
/// Signs a user in via Azure
GET >=> routeCi "/signin"
>=> (fun (next: HttpFunc) (ctx: HttpContext) ->
if ctx.User.Identity.IsAuthenticated
then redirectTo false "/" next ctx
else challenge AzureADDefaults.AuthenticationScheme next ctx
)
/// Signs a user out of Azure
GET >=> routeCi "/signout"
>=> signOut AzureADDefaults.AuthenticationScheme
>=> text "You are signed out."
Next, you need to configure the webpack "devServerProxy". This is how my current Fable app is configured:
// When using webpack-dev-server, you may need to redirect some calls
// to a external API server. See https://webpack.js.org/configuration/dev-server/#devserver-proxy
devServerProxy: {
// delegate the requests prefixed with /api/
'/api/*': {
target: "http://localhost:59641",
changeOrigin: true
},
// delegate the requests prefixed with /signin/
'/signin/*': {
target: "http://localhost:59641",
changeOrigin: true
},
// delegate the requests prefixed with /signout/
'/signout/*': {
target: "http://localhost:59641",
changeOrigin: true
}
},
This will allow you to provide a sign-in link from your SPA:
a [Href "/signin"] [str "Sign in"]
Now when the user loads your app, you can immediately try to pull back some user info (this route should require authentication). If the request (or any other) fails with a 401, you can prompt the user to "Sign in" with your sign-in link.
Lastly, your Azure app registration for your dev environment should point back to the port of your Web Api (which it sounds like yours already does).

How to call an express.js handler from another handler

I'm building an isomorphic React application which is using express.js on the server. The client app makes a number of AJAX requests to other express handler which currently entails them making multiple HTTP requests to itself.
As an optimisation I'd like to intercept requests I know the server handles and call them directly (thus avoiding the cost of leaving the application bounds). I've got as far as accessing the apps router to know which routes it handlers however I'm struggling to find the best way to start a new request. So my question is:
How do I get express to handle an HTTP request that comes from a programatic source rather than the network?
I would suggest create a common service and require it in both the handlers. What I do is break the business logic in the service and create controllers which handles the request and call specific services in this way u can use multiple services in same controller eg.
router.js
var clientController = require('../controllers/client-controller.js');
module.exports = function(router) {
router.get('/clients', clientController.getAll);
};
client-controller.js
var clientService = require('../services/client-service.js');
function getAll(req, res) {
clientService.getAll().then(function(data) {
res.json(data);
}, function(err) {
res.json(err);
});
}
module.exports.getAll = getAll;
client-service.js
function getAll() {
// implementation
}
module.exports.getAll = getAll;
u can also use something like http://visionmedia.github.io/superagent/ to make http calls from controllers and make use of them.

Restelet routing: some resources require authentication, some don't. How to do it?

I've been workin on a RESTlet 2.1 project. I've figured out how to set up authentication for my Resources. Fact is.. not all of them need authentication! I am quite puzzled about how should I do it right.
In the following code you can see the outline of my server Application, in particular the "create Inbound Root":
#Override
public Restlet createInboundRoot(){
/* the structure so far is: a filter, followed by an authenticator,
followed by a rooter.
The filter is returned at end of the method.
*/
//Init filter:
SomeFilter someFilter = new SomeFilter();
//Init authenticator:
ChallengeAuthenticator authenticator = new ChallengeAuthenticator(
......);
//more authenticator stuff goes here....
//Init router:
Router router = new Router(getContext());
//this should be a public resource, no need for auth:
router.attach("/0.1/getResource", SomeResource.class)
//this is a private resource, needs auth:
router.attach("/0.1/getPrivateResource", PrivateResource.class);
//set up the flow: filter -> authenticator -> router
authenticator.setNext(router);
someFilter.setNext(authenticator);
return someFilter;
}
The filter must be before everything, since I need to modify some Headers for all packages. After the filter I would like to set-up a fork, where requests of my public resource are just routed to the Resource class and requests of the private resource must pass through the authenticator.
How can I accomplish this? I am new to this framework and couldn't figure out even if it looks dead simple.
Think about your routers like a chain. Yours look like this:
someFilter -> authenticator -> router -> (SomeResource.class | PrivateResource.class)
This means all requests start at someFilter, go through the authenticator, hit the router and end up at either SomeResource or PrivateResource.
You need to put the authenticator in front of PrivateResource only, move the authenticator to that bit of the chain, so it looks more like this:
someFilter -> router -> (SomeResource.class | authenticator -> PrivateResource.class)
The code might look like:
ChallengeAuthenticator authenticator = new ChallengeAuthenticator(......);
authenticator.setNext(PrivateResource.class);
router.attach("/0.1/getPrivateResource", authenticator);
Does that help?
I've figured out the full solution to this, it was about "URI templates". The one thing missing was the different way a router can match the uri, in fact, the problem needed a "Match the first part of the URI" kind of approach.
/*
* Routing structure:
*
* ---/public---->(publicR()----> Public Resources
* (Filter()---->(routerPP()--|
* ---/private--->(authenticator()---->(privateR()---> Private Resources
*
*/
where routerPP takes the decision if the URL begins with /public or /private:
Router routerPP = new Router(getContext());
routerPP.setDefaultMatchingMode(Template.MODE_STARTS_WITH);
routerPP.attach("/private", authenticator);
routerPP.attach("/public", publicR);
the one particularity is that, after an URL "passes through" a router, it looses the matched part of the URL, therefore a following router (e.g. the public one) will have this structure:
Router publicR = new Router(getContext());
publicR.attach("/somePublicResource", SomePublicResource.class);
and such configuration matches the following URL:
http://somehost.com/public/somePublicResource
if in the second router you add the "/public/" token again, you will get a "resource not found" error, and the resource would then be on: http://somehost.com/public/public/somePublicResource
So the routers match and remove from the URL.
Reference about the routing and the URI matching I've found useful are:
http://restlet-discuss.1400322.n2.nabble.com/Trying-to-route-to-two-routes-that-start-with-same-prefix-td7019794.html
http://restlet.org/learn/javadocs/snapshot/jse/api/org/restlet/routing/Router.html