Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kerberos authentication in Node.js https.get or https.request

I'm trying to write a simple script that requests some data from a tool on an internal network. Here is the code:

#!/usr/bin/node

var https = require('https');
var fs = require('fs');

var options = {
  host: '<link>',
  port: 443,
  path: '<path>',
  auth: 'username:password',
  ca: [fs.readFileSync('../.cert/newca.crt')]
};

https.get(options, function(res) {
  console.log("Got response: " + res.statusCode);
  res.on('data', function (d) {
    console.log('BODY: ' + d);
  });
}).on('error', function(e) {
  console.log("Got error: " + e.message);
});

Now the question is, how can I use a Kerberos ticket to authenticate rather than supplying my credentials in auth: in plain text?

like image 211
mart1n Avatar asked Nov 20 '13 14:11

mart1n


People also ask

Does Kerberos work over HTTP?

Kerberos authentication on HTTP will encapsulate Kerberos ticket inside a SPNEGO token and will not expose user credentials. Replay attack is stopped by authenticators. But there is a possibility to do a active MITM attack where you would prevent server from receiving captured authenticator.

What is Kerberos TGS request?

What is TGT Kerberos? In Kerberos authentication, a Ticket Granting Ticket (TGT) is a user authentication token issued by the Key Distribution Center (KDC) to be used to request from the Ticket Granting Service (TGS) access tokens for specific resources/systems joined to the domain.


4 Answers

from http://docs.oracle.com/cd/E24191_01/common/tutorials/authn_kerberos_service.html

Client Token Location for Message-Level Standards: The Kerberos Service ticket can either be sent in the Authorization HTTP header or inside the message itself, for example, inside a element. Alternatively, it may be contained within a message attribute. Select one of the following options:

so instead of your username:password you provide the ticket

alternatively you can as stated below that information put it in the message body or as a message attribute

var request = https.request(options, function(resource) {
  var chunks = [];
   resource.on('data', function (chunk) {
     chunks.push(chunk);
   });
   resource.on('end', function () {
     var data = chunks.join('');
     console.log(data);
   });
}

request.on('error',...)
request.send('<body-with-ticket>');
request.end();

EDIT:

the "" part was my example of where to use the ticket, put it in a multiytype body and send that, alternatively use the WWW-Authenticate header to send it

eg. add it to the options on https.request

options = {
    host: 'hostname',
    port: 443, 
    'WWW-Authenticate': 'Negotiate ' + ticketdata
};

google has some nice diagrams on how it works: https://developers.google.com/search-appliance/kb/secure/kerberos-diagram

like image 111
Paul Scheltema Avatar answered Oct 26 '22 06:10

Paul Scheltema


I have gotten this to work using "kerberos" module, version 0.0.12. I have created a Gist with the working example:

https://gist.github.com/dmansfield/c75817dcacc2393da0a7

Basically, you use three methods to obtain the "Authorization" header data:

  • authGSSClientInit, which requires the service name, e.g. [email protected]
  • authGSSClientStep, which requires the existence of a credentials cache (on Linux you get this by doing "kinit" and can verify it with "klist"), and actually gives you back the base64 stuff you need (without the leading "Negotiate " string)
  • authGSSClientClean, which frees all allocated memory structures

Then you create an "Authorization" header (NOT WWW-Authenticate as shown above, which is what the server sends back) and it should work.

Note also: typically, web browsers request a resource, get a 401 back with a WWW-Authenticate: Negotiate header in the response, then re-request the resource with the ticket data supplied in the "Authorization" header. This two-step dance happens for every resource. I'm not sure if it means anything or not.

like image 21
dmansfield Avatar answered Oct 26 '22 08:10

dmansfield


In Paul Scheltema's answer, you need to get ticketdata from depth of operating system. You (or a module on behalf of you) must use GSS-API to have ticketdata generated by Active Directory for you.

Such mechanism is present in Chrome, but it seems that it's not included in Node.js (only the javascript engine from Chrome), so you may need to add a module, for example:

  • Passport-Kerberos: https://www.npmjs.org/package/passport-kerberos and http://passportjs.org/guide/
  • Kerberos (npm install kerberos)
  • In source code of Node.js at github there's a trace that someone has been using Bones module for that (https://github.com/joyent/node/search?q=kerberos&ref=cmdform). 3 years ago, with DES (this encoding type is very weak and has been deprecated for years)

To install/compile such module you may need to have Visual Studio.


To set up environment, - On all computers you must have tcp and udp enabled on ports 88 (Kerberos) and 53 (dns). - On Windows Server Active Directory must be running (ldap, dns, kdc) - On the page https://www.npmjs.org/package/passport-kerberos they use term REALM. It's a name of domain, written uppercase.

like image 27
greenmarker Avatar answered Oct 26 '22 07:10

greenmarker


If you are on Windows, you can use the SSPI interface. It is exposed on Node with the project node-expose-sspi.

The SSPI interface allows you to write any client or server using SSO (NTLM and Kerberos).

https://github.com/jlguenego/node-expose-sspi

Note: I am the author of node-expose-sspi.

like image 29
jlguenego Avatar answered Oct 26 '22 07:10

jlguenego