What is the best approach to validate the client certificate supplied by the user?
i am using express.js and validating certificates using client-certificate-auth.
at the moment i am checking the certificate fingerprint, something like this:
var checkAuth = function (cert) {
if (cert.fingerprint === 'XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX') {
return true;
} else {
return false;
}
};
is this the best approach? or am i doing something wrong?
Thanks.
Related
After logging in using the MsalAuthenticationTemplate InteractionType.Redirect, how do I get the JWT returned after successful authentication? It does not seem to be included in the msal instance.
import { MsalProvider, MsalAuthenticationTemplate, useMsal, useAccount } from "#azure/msal-react";
const { instance } = useMsal();
You should call acquireTokenSilent each time you need an access token. You can read more in our getting started doc and also review the msal-react-samples
Another way of getting the idToken(JWT) after successful login is to hook into the addEventCallback and check for EventType.LOGIN_SUCCESS.
const callbackId = instance.addEventCallback(message => {
if (message.eventType === EventType.LOGIN_SUCCESS) {
const { payload } = message;
// Get idToken(JWT) from the payload.
console.log(payload.idToken);
}
})
https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/events.md
I'm trying to launch a really basic chat app for myself and a few friends and wanted to include a password check upon loading the site by using a prompt + socket.emit:
var username = prompt('password:');
socket.emit('password', password);
I wanted to insert a function that checks their input against whatever I define as the answer. Something like this:
var codeword = prompt('password:', function checkPrompt(password) {
if (prompt.password.length === 0) {
return false;
}
if (password.value !== answer.value) {
return false;
}
return true;
});
But I get ERR_INVALID_ARG_TYPE(name, 'Function', value); once I run the app. How can I implement this?
Sidenote: I know this is super insecure. I'll implement a real password check once I have a DB set up but until then I just wanted a simple placeholder.
prompt is a "blocking" method, so there is no need for a callback. Callbacks are needed when you are uncertain when code within the callback will be executed. This is not the case here. You can work with the returned result in a do...while loop for example.
Dummy example with static password check:
// We will keep the user in the loop until the password is correct...
do {
var password = prompt('Password:');
} while (password !== 'abcd');
// At this point we know the password was correct.
alert('Password was correct!');
Dummy example with dedicated auth method:
function authenticate(username, password) {
if (username == 'john' && password == 'abcd') {
return true;
}
return false;
}
// We will keep the user in the loop until the password is correct...
do {
var username = prompt('Username:');
var password = prompt('Password:');
var loginSuccessful = authenticate(username, password);
} while (!loginSuccessful);
// At this point we know the password was correct.
alert('Password was correct!');
From the security point of view, it only makes sense to have the authentication logic on server-side, so you'll most probably will want to make an AJAX call from within the above authenticate function (using the Fetch API for example or jQuery.post - if you're using jQuery). Then the method would return true or false based on the response of the server-side call.
I am trying to set up a webhook in Xero. I have created an endpoint which Xero hits and send some header and payload. I extract the hash from the header and match with the hash of payload but i never get the same hash. I am using the below code to do that.
router.post('/weebhook', function(req, res, next) {
console.log(req.headers)
console.dir(req.body);
try {
var xero_signature = req.headers['x-xero-signature']
var encoded_data = encodePayload(req.body)
console.log(xero_signature)
console.log(encoded_data)
if (encoded_data == xero_signature) {
res.status(200).json();
} else {
res.status(401).json();
}
}catch(eror) {
console.log(eror)
}
});
function encodePayload(payload) {
console.log(JSON.stringify(payload))
const secret = 'TbJjeMSPAvJiMiD2WdHbjP20iodKCA3bL5is8vo47/pCcuGCsjtUDb7cBnWo20e0TBwZsQ/lPM41QgypzZE6lQ==';
const hash = crypto.createHmac('sha256',secret,true)
.update(JSON.stringify(payload))
.digest().toString('base64');
return hash
}
Xero hash - NzQOq6yw6W6TKs1sQ1AJtMWX24uzzkyvh92fMxukreE=
my hash - L74zFdcuRsK3zHmzu9K37Y1mAVIAIsDgneAPHaJ+vI4=
Please let me know what is the issue ?
There's a typescript sample application provided by Xero that implements the webhooks signature verification.
Does the code in here help you at all? https://github.com/XeroAPI/XeroWebhooksReceiver-Node/blob/master/src/server/server.ts#L58L59
Also, please delete and recreate your webhook as you've just provided everyone with your secret webhooks key.
Change .update(JSON.stringify(payload)) to .update(payload.toString())
I'm trying to create my own authentication strategy that reads the client's PKI certificate within a FeathersJS backend. This is handled in a before hook and based on the documentation hooks are
A hook is transport independent, which means it does not matter if it has been called through HTTP(S) (REST), Socket.io, Primus or any other transport Feathers may support in the future. They are also service agnostic, meaning they can be used with any service regardless of whether they have a model or not.
This is not a bad idea, however I need the TLS socket structure within the hook to get the user's certificate. Essentially calling: req.socket.getPeerCertificate(). I'm using the passport-client-certificate module and here's the strategy in question:
class ClientCertStrategy extends Strategy {
constructor (options, verify) {
if (typeof options === 'function') {
verify = options
options = {}
}
if (!verify) throw new Error('Client cert authentication strategy requires a verify function')
super()
this.name = 'client-cert'
this._verify = verify
this._passReqToCallback = options.passReqToCallback
}
_verified (err, user) {
if (err) { return this.error(err) }
if (!user) { return this.fail() }
this.success(user)
}
authenticate (req, options) {
// Requests must be authorized
// (i.e. the certificate must be signed by at least one trusted CA)
if (!req.socket.authorized) {
this.fail()
return
}
// This is where it fails! req.socket does not exist
const clientCert = req.socket.getPeerCertificate()
if (!clientCert) {
this.fail()
// TODO: Failure message
// this.fail({message: options.badRequestMessage || 'Missing client certificate'}, 400)
return
}
try {
if (this._passReqToCallback) {
this._verify(req, clientCert, this._verified.bind(this))
} else {
this._verify(clientCert, this._verified.bind(this))
}
} catch (err) {
return this.error(err)
}
}
}
Based on the FeathersJS code, the authenticate function basically makes a new request object from the hook. Is there any way to get the user's certificate earlier and make it available later on when the hook is executed?
I wrote an issue and was pointed to the FAQ which ultimately helped me solve this:
https://github.com/feathersjs/authentication/issues/693
https://docs.feathersjs.com/faq/readme.html#how-do-i-access-the-request-object-in-hooks-or-services
I ended up writing a middleware that stuck the certificate into the request params. The request params are copied into the hook which is then passed into the Passport strategy.
I have in incoming bearer token that has an incorrect audience. There is enough information in the token via other claims that prove what the audience should be.
I was hoping to fix it up early so that I could still take advantage of the JwtBearerOptions.TokenValidationParameters.ValidateAudience = true;
JwtBearerOptions.TokenValidationParameters.ValidAudiences ={"the right one"};
I can hook the OnTokenValidated event, and rewrite the principal, but that is too late. Earlier in the pipeline the token has been validated and since the audience is wrong, it has already been rejected.
I am able to get around this by using authorization policies, by setting ValidateAudience=false and taking care of this at the controller level. I don't like having to add that [Authorize("the-correct-audience")] attribute to every controller, because someone will miss one.
Another alternative is to introduce a new middleware that works on the identitiy.claims and reject there.
In the end I want to be able to globally reject these tokens the way a validateAudience = true accomplishes, when validateAudience has been taken away from me as a filtering option.
Has anyone done something like this and what other alternatives have you used?
Solution 1: Solve it by introducing a middleware.
NOTE: Don't validate the audience
First hook the following;
```
JwtBearerOptions = options =>{
options.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
...
// this will put in the right aud
// replace the entire principal
var appIdentity = new ClaimsIdentity(newClaims);
var claimsPrincipal = new ClaimsPrincipal(appIdentity);
context.Principal = claimsPrincipal;
}
}
}
Introduce this middleware;
I am looking for aud here, but you everything is fair game in the identity.
```
app.UseAuthentication();
app.Use(async (HttpContext context, Func<Task> next) =>
{
//do work before the invoking the rest of the pipeline
if (context.Request.Headers.ContainsKey("x-authScheme") &&
context.Request.Headers.ContainsKey("Authorization") &&
context.User != null)
{
// looking for bearer token stuff.
var claims = context.User.Claims;
var q = from claim in claims
where claim.Type == "aud" && claim.Value == "aggregator_service"
select claim;
if (!q.Any())
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
}
await next.Invoke(); //let the rest of the pipeline run
//do work after the rest of the pipeline has run
});
```