npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ntlm-server

v0.1.3

Published

[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) ![NTLM Protocol Impl.](https://img.shields.io/badge/NTLM_Protocol_Impl.-Partial-orange) [![npm](https://github.com/Shadowfita/ntlm-serv

Downloads

10

Readme

License NTLM Protocol Impl. npm

NTLM Server Library

A TypeScript library that simplifies the integration of NTLM authentication in HTTP server applications.

Inspired by express-ntlm


Table of Contents


Features

  • NTLM v1 support with extended session security (NTLM v2 security over NTLM v1).
  • Designed for ease of integration in server-side applications.
  • Implements the server-side NTLM challenge-response flow.
  • Full NTLM protocol implementation planned.

Installation

To install the library, use npm or yarn:

npm install ntlm-server
yarn add ntlm-server

Getting Started

Here’s a basic pseudo-typescript example of how this library could be used with a HTTP server. The server will challenge clients for NTLM authentication.

Basic Usage

const authHeader = request.headers["authorization"];

if (!authHeader) {
    // Step 1: Challenge the client for NTLM authentication
    respond({
        status: 401,
        headers: {
            "WWW-Authenticate": "NTLM",
        },
    });
    return;
}

if (authHeader.startsWith("NTLM ")) {
    // Step 2: Handle NTLM negotiation message
    const clientNegotiation = new NTLMNegotiationMessage(authHeader);

    if (clientNegotiation.messageType == MessageType.NEGOTIATE) {
        // Step 3: Send NTLM challenge message
        const serverChallenge = new NTLMChallengeMessage(clientNegotiation);
        const base64Challenge = serverChallenge.toBuffer().toString("base64");

        respond({
            status: 401,
            headers: {
                "WWW-Authenticate": `NTLM ${base64Challenge}`,
            },
        });
        return;
    } else if (clientNegotiation.messageType == MessageType.AUTHENTICATE) {
        // Step 4: Handle NTLM Authenticate message
        const clientAuthentication = new NTLMAuthenticateMessage(authHeader);

        // LDAP or AD bind and fetch user info here

        respond({
            status: 200,
        });
        return;
    } else {
        console.warn("Invalid NTLM Message received.");
    }
}

respond({
    status: 400,
    body: "Bad NTLM request",
});

Explanation of the Authentication Flow

  1. Challenge the Client: If the Authorization header is missing, the server responds with a WWW-Authenticate: NTLM header to challenge the client.
  2. NTLM Negotiation and Authentication:
    • The client sends an NTLM Type 1 (Negotiate) message in the Authorization header.
    • The server replies with an NTLM Type 2 (Challenge) message.
    • The client responds with an NTLM Type 3 (Authenticate) message, which the server uses to authenticate the client.
  3. User Authentication: Once authenticated, the server can access the user's information, such as their username.

Roadmap

The current version of this library supports NTLM v1 with extended session security (offering NTLM v2 security over NTLM v1). Future releases will introduce full NTLM protocol support.

Contributing

I welcome contributions! To contribute, please follow these steps:

  1. Fork the repository.
  2. Create a new feature branch (git checkout -b feature-name).
  3. Commit your changes (git commit -m 'Add new feature').
  4. Push to your branch (git push origin feature-name).
  5. Open a Pull Request.

License

This project is licensed under the BSD-3-Clause License. Please see the LICENSE file for more information.

Support

If you encounter issues or have any questions, feel free to open an issue.

I will continue to implement the remaining parts of the NTLM protocol as time permits, as I work full-time and have other commitments. I have no set timeline for completing this additional work, so contributions from the community are welcome.

If you're interested in helping out or have ideas, feel free to contribute.

Examples

Example 1: Express Middleware

An express middleware example that uses ldapts to fetch user information based on the User Principal Name returned by the AuthenticateMessage. Caching or cookies should be used to reduce the amount of challenge and LDAP requests.

const app = express();
const port = 3001;

app.use(express.json());

const ntlmAuthMiddleware: RequestHandler = async (req, res, next) => {
    const authHeader = req.headers["authorization"];

    if (!authHeader) {
        // Step 1: Challenge the client for NTLM authentication
        res.setHeader("WWW-Authenticate", "NTLM");
        return res.status(401).end();
    }

    if (authHeader.startsWith("NTLM ")) {
        const clientNegotiation = new NTLMNegotiationMessage(authHeader);

        // Step 2: Handle NTLM negotiation message
        if (clientNegotiation.messageType == MessageType.NEGOTIATE) {
            // Step 3: Send NTLM challenge message
            const serverChallenge = new NTLMChallengeMessage(clientNegotiation);
            const base64Challenge = serverChallenge.toBuffer().toString("base64");

            res.setHeader("WWW-Authenticate", `NTLM ${base64Challenge}`);
            return res.status(401).end();
        } else if (clientNegotiation.messageType == MessageType.AUTHENTICATE) {
            // Step 4: Handle NTLM Authenticate message
            const clientAuthentication = new NTLMAuthenticateMessage(authHeader);

            try {
                // LDAP or AD bind and fetch user info
                const client = new Client({
                    url: "ldap://myldapserver",
                    timeout: 0,
                    connectTimeout: 0,
                    strictDN: true,
                });

                // Anonymous bind example
                await client.bind("", "");

                const { searchEntries } = await client.search("DC=yourDC", {
                    filter: `(userPrincipalName=${clientAuthentication.userName}@${clientAuthentication.domainName}*)`,
                });

                // Attach the search result to the request object to access it in the next route handler
                req.user = searchEntries[0];
                return next(); // Pass control to the next middleware or route handler
            } catch (error) {
                console.error("LDAP Authentication error:", error);
                return res.status(500).send("Internal Server Error");
            }
        } else {
            console.warn("Invalid NTLM Message received.");
            return res.status(400).send("Invalid NTLM message");
        }
    }

    return res.status(400).send("Bad NTLM request");
};

// Applying the middleware to a specific route
app.get("/", ntlmAuthMiddleware, (req: Request, res: Response) => {
    // Access user details populated by the middleware
    res.send(req.user);
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

Example 2: Next.js Middleware

A Next.js middleware example that secures routes based on the existence of a userName in the AuthenticateMessage. Caching or cookies should be used to reduce the amount of challenge requests.

This could be moved to an API endpoint where a library like ldapts could be used to fetch user information from ActiveDirectory.

// middleware.ts

export async function middleware(req: NextRequest) {
    const authHeader = req.headers.get("authorization");

    if (!authHeader) {
        // Step 1: Challenge the client for NTLM authentication
        return NextResponse.json(
            {},
            {
                status: 401,
                headers: {
                    "WWW-Authenticate": "NTLM",
                },
            }
        );
    }

    if (authHeader.startsWith("NTLM ")) {
        const clientNegotiation = new NTLMNegotiationMessage(authHeader);

        // Step 2: Handle NTLM negotiation message
        if (clientNegotiation.messageType === MessageType.NEGOTIATE) {
            // Step 3: Send NTLM challenge message
            const serverChallenge = new NTLMChallengeMessage(clientNegotiation);
            const base64Challenge = serverChallenge.toBuffer().toString("base64");

            return NextResponse.json(
                {},
                {
                    status: 401,
                    headers: {
                        "WWW-Authenticate": `NTLM ${base64Challenge}`,
                    },
                }
            );
        } else if (clientNegotiation.messageType === MessageType.AUTHENTICATE) {
            // Step 4: Handle NTLM Authenticate message
            const clientAuthentication = new NTLMAuthenticateMessage(authHeader);

            try {
                // If authentication is successful, proceed with the request
                // You can store the userName in headers or cookies for further processing
                const response = NextResponse.next();
                response.headers.set("X-User", this.clientAuthentication?.userName ?? "");
                return response;
            } catch (error) {
                console.error("LDAP Authentication error:", error);
                return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
            }
        } else {
            console.warn("Invalid NTLM Message received.");
            return NextResponse.json({ error: "Invalid NTLM message" }, { status: 400 });
        }
    }

    return NextResponse.json({ error: "Bad NTLM request" }, { status: 400 });
}

// Optionally, apply the middleware to specific routes
export const config = {
    matcher: ["/api/:path*", "/protected-route/:path*"],
};