traefik_subsonic_basicauth

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2024 License: MPL-2.0 Imports: 15 Imported by: 0

README

Traefik plugin to use BasicAuth with Subsonic

This Traefik plugin transforms Subsonic authentication parameters into a BasicAuth header.

In front of a ForwardAuth service, it lets you integrate into your existing authentication infrastructure Subsonic clients that only support the standard Subsonic authentication scheme.

In front of a Subsonic server that supports BasicAuth or some other authentication scheme, it lets you remove sensitive query parameters to reduce the risk of exposing them in logs.

The plugin validates Subsonic authentication parameters for security, and removes them before forwarding the request.

Security warning

This plugin requires clients to use the old subsonic authentication scheme where the password is transmitted in clear text (p query parameter) and does not support the "more secure" token scheme (t and s query parameters).

The reasons for this are

  1. there is no standard way to transmit two data points in the password field of a BasicAuth header, and I don't want to come up with my own little scheme;
  2. this requires the server to store the user's password in clear form or with reversible encryption (this is true for any compliant subsonic servers nowadays), and the goal of this plugin is to get rid of this madness.

From a security standpoint, letting clients transmit their credentials with the old subsonic scheme is not ideal, but if the connection is made over HTTPS it is similar in principle to authentication mechanisms you find on most websites, with the following caveats:

  1. The password can end up in server logs: Servers usually avoid logging the body of incoming requests, but the path and query parameters are often logged. This is somewhat mitigated with subsonic's token scheme where the user's password is not directly visible (even though it doesn't add any extra security from an authentication perspective).
  2. The password can be transmitted to third-parties: For example, in order to support casting, the subsonic client must transmit credentials to the cast receiver. Since this plugin only supports the old subsonic scheme, the casting devices will get access to the user's password.

Make sure you understand the implications of this and follow all privacy laws, regulations and policies applicable to you. The contributors to this plugin decline all responsibility and liability for your use of it.

Note that the OpenSubsonic initiative is working on adding support for a modern authentication scheme to the subsonic protocol (cf. os-api-auth), with support from authors of actively maintained clients and servers. You are encouraged to stop using this plugin (and stop supporting the legacy Subsonic schemes altogether) once a consensus has been reached and clients and servers adopt the new scheme.

Configuration

auth

Required, either backend or proxy.

The plugin supports two deployment scenarios:

  1. Backend authentication, where the subsonic service supports BasicAuth and authenticates requests itself;
  2. Proxy authentication, where a third-party service performs the authentication, e.g. using Traefik's ForwardAuth middleware.

The difference between the two modes is whether the response is intercepted and rewritten in case of authentication error: a subsonic authentication error does not look the same as an HTTP authentication error, and clients are expecting a proper subsonic error when authentication fails, which cannot be expected from a generic third-party authentication service.

header

Optional, defaults to Authorization.

Specifies the header that gets propagated with the Basic credentials. An empty value disables header propagation and response rewriting. The Subsonic authentication parameters still get validated and removed from the forwarded request.

client-headers

Optional, defaults to Authorization.

Specifies client headers that can contain Basic credentials. You can specify multiple headers by separating them with a comma.

Credentials in these headers are validated and stripped from the request before it gets forwarded to the Subsonic server. To avoid HPP vulnerabilities, the list should contain at least all BasicAuth headers supported by your Subsonic server, unless you remove them using another middleware.

debug

Optional, defaults to false.

Controls whether debug logs are produced. Debug logs should not contain sensitive data related to subsonic.

Examples

Backend authentication

# On your subsonic service
labels:
    traefik.http.routers.subsonic.rule: Host(`subsonic.example.com`) && PathPrefix(`/rest/`)
    traefik.http.routers.subsonic.middlewares: subsonicauth-sub2basic@docker

    traefik.http.middlewares.subsonicauth-sub2basic.plugin.subsonic-basicauth.auth: backend

Proxy authentication

In this scenario, the Subsonic backend still needs to know which user is making the request. This will depend on your Subsonic server, and the integration is not shown here.

Note that in this scenario you should avoid forwarding the BasicAuth header as-is to the Subsonic server, as it shouldn't need to get the user's password.

# On your authentication service
labels:
    # Your BasicAuth service, e.g. a BasicAuth or ForwardAuth middleware
    traefik.http.middlewares.authservice-basicauth.[...]

    # The subsonicauth middleware that should be mapped on your routes
    traefik.http.middlewares.authservice-subsonicauth.chain.middlewares: subsonicauth-sub2basic@docker,authservice-basicauth@docker,subsonicauth-cleanup@docker

    # Supporting middlewares
    traefik.http.middlewares.subsonicauth-sub2basic.plugin.subsonic-basicauth.auth: proxy
    traefik.http.middlewares.subsonicauth-sub2basic.plugin.subsonic-basicauth.header: Authorization
    traefik.http.middlewares.subsonicauth-cleanup.headers.customrequestheaders.Authorization: # empty removes the header
# On your subsonic service
labels:
    traefik.http.routers.subsonic.rule: Host(`subsonic.example.com`) && PathPrefix(`/rest/`)
    traefik.http.routers.subsonic.middlewares: authservice-subsonicauth@docker

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DEBUG = log.New(io.Discard, "DEBUG [subsonic-basicauth]: ", 0)

Functions

func New

func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error)

Types

type Config

type Config struct {
	// # Authentication mode
	//
	// * "backend": The subsonic backend is performing the BasicAuth
	//   authentication.
	//
	//   In this mode, the SubsonicAuth parameters are removed, and the response
	//   is not rewritten: as the backend is a subsonic server, it is expected
	//   to sent proper subsonic responses in all situations.
	//
	// * "proxy": The proxy is handling the authentication, e.g. using
	//   ForwardAuth.
	//
	//   In this mode, the SubsonicAuth parameters are removed, and the response
	//   is rewritten in case of authentication error: the proxy and the backend
	//   authentication service are not expected to know how to properly answer
	//   with a subsonic error, so the plugin has to intervene.
	//
	//   SECURITY NOTES:
	//   - If used with a ForwardAuth middleware, make sure to remove the
	//     BasicAuth header after the authentication and before forwarding the
	//     request to the backend. Traefik's architecture makes it impossible to
	//     handle this directly in this plugin.
	//   - Make sure to check your subsonic server's documentation and disable
	//     authentication mechanisms not supported by this plugin, or prevent
	//     them from being used by clients (e.g. by stripping the corresponding
	//     credentials from requests). If not done correctly, THIS COULD LEAVE
	//     YOUR SYSTEM VULNERABLE TO HPP ATTACKS, where different credentials
	//     are retrieved in different ways by different components of your
	//     system. Credential sources not supported by this plugin could include
	//     non-standard headers (see the `ClientHeaders` option), cookies, or
	//     non-standard query parameters.
	Auth string `json:"auth"`

	// Enable debug logs. Does not contain sensitive data related to the
	// subsonic authentication.
	Debug bool `json:"debug"`

	// Name of the header used to propagate the BasicAuth token.
	//
	// The default value is "Authorization".
	//
	// The sanitization-only mode is enabled by setting an empty value: The
	// authentication parameters get validated and stripped from the query, but
	// without adding a BasicAuth header to the forwarded request nor rewriting
	// responses.
	Header string `json:"header"`

	// Name of headers that clients can use to send BasicAuth credentials.
	// Multiple headers can be specified separated by a comma.
	//
	// The default value is "Authorization".
	//
	// This list should contain at least all the headers supported by your
	// subsonic server, unless you remove them from client requests using
	// another middleware.
	ClientHeaders string `json:"client-headers"`
}

func CreateConfig

func CreateConfig() *Config

type Error

type Error struct {
	Code    int32  `xml:"code,attr"    json:"code"`
	Message string `xml:"message,attr" json:"message,omitempty"`
}

type JsonWrapper

type JsonWrapper struct {
	Subsonic Subsonic `json:"subsonic-response"`
}

type Middleware

type Middleware struct {
	// contains filtered or unexported fields
}

func (*Middleware) ServeHTTP

func (mw *Middleware) ServeHTTP(res http.ResponseWriter, req *http.Request)

type Subsonic

type Subsonic struct {
	XMLName       xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
	Status        string   `xml:"status,attr"                                   json:"status"`
	Version       string   `xml:"version,attr"                                  json:"version"`
	Type          string   `xml:"type,attr"                                     json:"type"`
	ServerVersion string   `xml:"serverVersion,attr"                            json:"serverVersion"`
	OpenSubsonic  bool     `xml:"openSubsonic,attr,omitempty"                   json:"openSubsonic,omitempty"`
	Error         *Error   `xml:"error,omitempty"                               json:"error,omitempty"`
}

Jump to

Keyboard shortcuts

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