basic

package module
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2023 License: MIT Imports: 4 Imported by: 0

README

Basic

Provides plug and play, generic, secure, easy to use, customizable, and painless Basic Authentication middleware for Go's HTTP handlers. No dependencies!

This package tries its best to implement all specifications in a customizable way as specified in RFC 7617, the newest version of Basic Authentication which obsoletes RFC 2617.

Why Basic?

  • No dependencies. Basic only needs standard Go and no dependencies are required.
  • Battle-tested. This library conforms to the standard library (which a lot of people use nowadays).
  • Lightweight. Basic is small in size, due to not having any dependencies.
  • Secure. Tries its best to implement as many security considerations as possible, but you definitely have to use HTTPS in production if you intend to use this in production.
  • Generic. This library is generic and implements http.Handler to ensure maximum compatibility with as many Go frameworks as possible.
  • 100% tested. As this library is small, the code coverage is still 100% for now.
  • Well documented. Check out this README.md document and the technical documentation for further reading!

Security Considerations

If you want to use this in production environment, here are additional security considerations:

  • Ensure you are running this using HTTPS with SSL/TLS to prevent man in the middle attacks.
  • Enable HSTS (Strict-Transport-Security) to prevent your site from being accessed with HTTP. Set redirects (301 Moved Permanently) from HTTP to HTTPS permanently in your reverse proxy / Go app. Use HTTPS forever!
  • Use secure HTTP headers to prevent malicious browser agents (X-XSS-Protection, X-Content-Type-Options, X-DNS-Prefetch-Control, and the like).
  • Use rate limiters in endpoints protected by Basic Authentication to prevent brute-force attacks.
  • As usual, keep your passwords strong. Use symbols, numbers, uppercases, and lowercases. Even better if you use password managers.
  • Follow and read security guidelines: OWASP Cheatsheets!
  • My two cents and security tip: Basic Authentication should placed in an endpoint that gives out sessions / tokens on successful authentication. Make sure that endpoint is not cacheable (use PUT, PATCH, POST without Cache-Control headers, by default they are not cacheable, do not use GET and HEAD if possible). This relieves the pain of having to deal with logout and/or cache problems. You can then delegate your authentication via the given out sessions / tokens.

Documentation

Complete documentation could be seen in the official pkg.go.dev site.

Installation

You have to perform the following steps (assume using Go 1.18):

  • Download this library.
go install github.com/lauslim12/basic

# for older go versions: go get -u github.com/lauslim12/basic
  • Import it in your source code.
import "github.com/lauslim12/basic"
  • Instantiate the BasicAuth object, and you can wrap it in any endpoint you desire to protect it!
func main() {
    // Create a one-to-one mapping of username and password.
    users := map[string]string{"nehemiah":"nehemiahpassword"}

    // Use default authenticator function, set charset to UTF-8, use default invalid scheme response,
    // use default invalid credentials response, set custom realm, and set static user list.
    basicAuth := basic.NewCustomBasicAuth(nil, "UTF-8", nil, nil, "Private", users)
    http.HandleFunc("/", basicAuth.Authenticate(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(http.StatusText(http.StatusOK)))
    }))
}
  • Test the endpoint!
curl -u nehemiah:nehemiahpassword <API_ENDPOINT_URL>
  • Done!

Customizations

Customization is the core part of this library. You can customize anything, and you can even define / create a middleware before or after the Authenticate middleware method if you need to perform some preprocessing or postprocessing.

  • As an example, you may define your own authorizer if you need to do so. Below code is for reference:
func main() {
    // This pseudocode example sets no static users and calls the user from the DB based on
    // the user's input. It then matches the password and returns the boolean value.
    basicAuth := basic.NewCustomBasicAuth(func(username, password string) bool {
        user := getUserFromDB(username)
        match := basic.CompareInputs(password, user.Password)

        return match
    }, "UTF-8", nil, nil, "Private Not-Static", nil)

    // After defining it, we then hook it into our handler.
    http.HandleFunc("/", basicAuth.Authenticate(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusAccepted)
        w.Write([]byte(http.StatusText(http.StatusAccepted)))
    }))
}
  • You can customize your Authenticator function (signature is func(username, password string) bool), Charset (defaults to UTF-8 according to RFC 7617), InvalidSchemeResponse (signature is http.Handler), InvalidCredentialsResponse (signature is http.Handler), Realm (signature is string), and Users (signature is map[string]string). Users itself will contain the 1-to-1 mapping of username and password. As long as it conforms to the interface / function signature, you can customize it with anything you want.

Examples

Please see examples at the example project (example/main.go). You can run it by doing go run example/main.go and then connect to localhost:5000 on your web browser / API client.

Contributing

This tool is open source and the contribution of this tool is highly encouraged! If you want to contribute to this project, please feel free to read the CONTRIBUTING.md file for the contributing guidelines.

License

This work is licensed under MIT License. Please check the LICENSE file for more information.

Documentation

Overview

Package basic provides plug and play, generic, secure, easy to use, customizable, and painless Basic Authentication for Go's HTTP handlers. This package tries its best to implement all specifications in a customizable way as specified in [RFC 7617](https://datatracker.ietf.org/doc/html/rfc7617), the newest version of Basic Authentication which obsoletes [RFC 2617](https://datatracker.ietf.org/doc/html/rfc2617).

Basic Authentication itself is a simple and secure way to protect your API endpoints. However, for it to be completely secure, you have to augment the authentication by using SSL/TLS. You may use hashes / encryption in advance, but I think it's not necessary. SSL/TLS provides excellent security as long as you can trust your Certificate Authority and can ensure your connections are end-to-end encrypted, no sniffers or spoofers whatsoever.

In order to use this package, you have to instantiate a new `BasicAuth` instance before hooking it to a handler. You can set various configurations, such as the authenticator function, charset (if using non-standard, other than UTF-8 charset), invalid credentials response, invalid scheme response, custom realm, and static users if applicable. If you want to do anything with the `*http.Request` struct, it is recommended for you to process it in a previous custom middleware before implementing your authentication with this library. This package tries its best to be as generic as possible, so you can definitely use any web framework or customized handlers as long as it conforms to the main interface (`http.Handler`).

As a note about the `BasicAuth` attributes, you may use the authenticator function in order to perform a more sophisticated authentication logic, such as pulling your user based on their username from the database. Another thing to note is that you can pass `nil` or `make(map[string]string)` to the `Users` attribute if you do not need static credentials. Finally, the `WWW-Authenticate` header is only sent if both `Charset` and `Realm` are set. `Users` attribute is a 1-to-1 mapping of username and password.

See example in `example/main.go`.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompareInputs

func CompareInputs(input, expected string) bool

CompareInputs is to safe compare two inputs (prevents timing attacks).

Types

type BasicAuth

type BasicAuth struct {
	Authenticator              func(username, password string) bool // Custom callback to find out the validity of a user's authentication process. This can be implemented in any implementation detail (for example: DB calls).
	Charset                    string                               // Custom charset to be passed in the `WWW-Authenticate` header. According to RFC 7617, this has to be 'UTF-8'.
	InvalidCredentialsResponse http.Handler                         // Callback to be invoked after receiving an InvalidCredentials error.
	InvalidSchemeResponse      http.Handler                         // Callback to be invoked after receiving an InvalidScheme error.
	Realm                      string                               // Specific realm for an authorization endpoint. This can be an arbitrary string.
	Users                      map[string]string                    // Static credentials for all users. Can be `nil` if need be.
}

BasicAuth is used to configure all the library options.

func NewCustomBasicAuth

func NewCustomBasicAuth(
	authenticator func(username, password string) bool,
	charset string,
	invalidCredentialsResponse http.Handler,
	invalidSchemeResponse http.Handler,
	realm string,
	users map[string]string,
) *BasicAuth

NewCustomBasicAuth is used to set up Basic Auth options with customizable configurations.

func NewDefaultBasicAuth

func NewDefaultBasicAuth(users map[string]string) *BasicAuth

NewDefaultBasicAuth is used to set up Basic Auth options with default configurations.

func (*BasicAuth) Authenticate

func (a *BasicAuth) Authenticate(next http.HandlerFunc) http.HandlerFunc

Authenticate is a middleware to safeguard a route with the updated version of Basic Authentication (RFC 7617).

func (*BasicAuth) SendInvalidCredentialsResponse

func (a *BasicAuth) SendInvalidCredentialsResponse(w http.ResponseWriter, r *http.Request)

SendInvalidCredentialsResponse is used to send back an invalid response if the Basic Authorization credentials are invalid.

func (*BasicAuth) SendInvalidSchemeResponse

func (a *BasicAuth) SendInvalidSchemeResponse(w http.ResponseWriter, r *http.Request)

SendInvalidSchemeResponse is used to send back invalid response if the Basic Authorization header is not in the proper format.

func (*BasicAuth) SetWWWAuthenticate

func (a *BasicAuth) SetWWWAuthenticate(w http.ResponseWriter)

SetWWWAuthenticate sets the `WWW-Authenticate` network header on the API response payload. If the charset and realm are both empty, we do not set the `WWW-Authenticate` header.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL