lico

package module
v0.62.0 Latest Latest
Warning

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

Go to latest
Published: May 8, 2024 License: Apache-2.0 Imports: 6 Imported by: 1

README

LibreGraph Connect

LibreGraph Connect implements an OpenID provider (OP) with integrated web login and consent forms.

Go Report Card

LibreGraph Connect has it origin in Kopano Konnect and is meant as its vendor agnostic successor.

Technologies

  • Go
  • React

Standards supported by Lico

Lico provides services based on open standards. To get you an idea what Lico can do and how you could use it, this section lists the OpenID Connect standards which are implemented.

Furthermore the following extensions/base specifications extend, define and combine the implementation details.

Build dependencies

Make sure you have Go 1.18 or later installed. This project uses Go Modules.

Lico also includes a modern web app which requires a couple of additional build dependencies which are furthermore also assumed to be in your $PATH.

To build Lico, a Makefile is provided, which requires make.

When building, third party dependencies will tried to be fetched from the Internet if not there already.

Building from source

git clone <THIS-PROJECT> lico
cd lico
make
Optional build dependencies

Some optional build dependencies are required for linting and continuous integration. Those tools are mostly used by make to perform various tasks and are expected to be found in your $PATH.

Build with Docker
docker build -t licod-builder -f Dockerfile.build .
docker run -it --rm -u $(id -u):$(id -g) -v $(pwd):/build licod-builder

Running Lico

Lico can provide user login based on available backends.

All backends require certain general parameters to be present. Create a RSA key-pair file with openssl genpkey -algorithm RSA -out private-key.pem -pkeyopt rsa_keygen_bits:4096 and provide the key file with the --signing-private-key parameter. Lico can load PEM encoded PKCS#1 and PKCS#8 key files and JSON Web Keys from .json files If you skip this, Lico will create a random non-persistent RSA key on startup.

To encrypt certain values, Lico needs a secure encryption key. Create a suitable key of 32 bytes with openssl rand -out encryption.key 32 and provide the full path to that file via the --encryption-secret parameter. If you skip this, Lico will generate a random key on startup.

To run a functional OpenID Connect provider, an issuer identifier is required. The iss is a full qualified https:// URI pointing to the web server which serves the requests to Lico (example: https://example.com). Provide the Issuer Identifier with the --iss parametter when starting Lico.

Furthermore to allow clients to utilize the Lico services, clients need to be known/registered. For now Lico uses a static configuration file which allows clients and their allowed urls to be registered. See the the example at identifier-registration.yaml.in. Copy and modify that file to include all the clients which should be able to use OpenID Connect and/or OAuth2 and start Lico with the --identifier-registration-conf parameter pointing to that file. Without any explicitly registered clients, Lico will only accept clients which redirect to an URI which starts with the value provided with the --iss parameter.

Lico cryptography and validation

A tool can be used to create keys for Lico and also to validate tokens to ensure correct operation is Step CLI. This helps since OpenSSL is not able to create or validate all of the different key formats, ciphers and curves which are supported by Lico.

Here are some examples relevant for Lico.

step crypto keypair 1-rsa.pub 1-rsa.pem \
  --kty RSA --size 4096 --no-password --insecure
step crypto keypair 1-ecdsa-p-256.pub 1-ecdsa-p-256.pem \
  --kty EC --curve P-256 --no-password --insecure
step crypto jwk create 1-eddsa-ed25519.pub.json 1-eddsa-ed25519.key.json \
  -kty OKP --crv Ed25519 --no-password --insecure
echo $TOKEN_VALUE | step crypto jwt verify --iss $ISS \
  --aud playground-trusted.js --jwks $ISS/konnect/v1/jwks.json
URL endpoints

Take a look at Caddyfile.example on the URL endpoints provided by Lico and how to expose them through a TLS proxy.

The base URL of the frontend proxy is what will become the value of the --iss parameter when starting up Lico. OIDC requires the Issuer Identifier to be secure (https:// required).

LibreGraph backend

Generic backend support is available through the LibreGraph API. Any service can provide the required endpoints and Lico connects to them.

export LIBREGRAPH_URI=http://your-backend.local:5050
bin/licod serve --listen=127.0.0.1:8777 \
  --iss=https://mylico.local \
  libregraph
LDAP backend

This assumes that Lico can directly connect to an LDAP server via TCP.

export LDAP_URI=ldap://myldap.local:389
export LDAP_BINDDN="cn=admin,dc=example,dc=local"
export LDAP_BINDPW="its-a-secret"
export LDAP_BASEDN="dc=example,dc=local"
export LDAP_SCOPE=sub
export LDAP_LOGIN_ATTRIBUTE=uid
export LDAP_EMAIL_ATTRIBUTE=mail
export LDAP_NAME_ATTRIBUTE=cn
export LDAP_UUID_ATTRIBUTE=uidNumber
export LDAP_UUID_ATTRIBUTE_TYPE=text
export LDAP_FILTER="(objectClass=organizationalPerson)"

bin/licod serve --listen=127.0.0.1:8777 \
  --iss=https://mylico.local \
  ldap
Build Lico Docker image

This project includes a Dockerfile which can be used to build a Docker container from the locally build version. Similarly the Dockerfile.release builds the Docker image locally from the latest release download.

docker build -t licod .
docker build -f Dockerfile.release -t licod .

Run unit tests

make test

Development

As Lico includes a web application (identifier), a Caddyfile.dev file is provided which exposes the identifier's web application directly via a webpack dev server.

Debugging

Lico is built stripped and without debug symbols by default. To build for debugging, compile with additional environment variables which override/reset build optimization like this

LDFLAGS="" GCFLAGS="all=-N -l" ASMFLAGS="" make cmd/licod

The resulting binary is not stripped and sutiable to be debugged with Delve.

To connect Delve to a running Lico binary you can use the make dlv command. Control its behavior via DLV_* environment variables. See the Makefile source for details.

DLV_ARGS= make dlv
Remote debugging

To use remote debugging, pass additional args like this.

DLV_ARGS=--listen=:2345 make dlv

Usage survey

By default, any running licod regularly transmits survey data to a Kopano user survey service at https://stats.kopano.io . To disable participation, set the environment variable KOPANO_SURVEYCLIENT_AUTOSURVEY to no.

The survey data includes system and platform information and the following specific settings:

  • Identify manager name (as selected when starting licod)

See here for further documentation and customization possibilities.

License

See LICENSE.txt for licensing information of this project.

Documentation

Overview

Package lico is a Go implementation of an OpenID Connect server with flexibale authorization and authentication backends and consent screen.

See README.md for more info.

Index

Constants

View Source
const (
	RefClaim              = "lg.r"
	IdentityClaim         = "lg.i"
	IdentityProviderClaim = "lg.p"
	ScopesClaim           = "scp"
)

Access token claims used.

View Source
const (
	IdentifiedUserClaim        = "us"
	IdentifiedUserIDClaim      = "id"
	IdentifiedUsernameClaim    = "un"
	IdentifiedDisplayNameClaim = "dn"
	IdentifiedData             = "da"
	IdentifiedUserIsGuest      = "gu"
)

Identifier identity sub claims used.

View Source
const (
	InternalExtraIDTokenClaimsClaim     = "$lico.id.extra"
	InternalExtraAccessTokenClaimsClaim = "$lico.at.extra"
)

Internal claim names used for special things.

View Source
const (
	// ScopeNumericID is the string value for the built-in Numeric ID scope.
	ScopeNumericID = "LibgreGraph.NumericID"
	// ScopeUniqueUserID is the string value for the built-in Unique User ID scope.
	ScopeUniqueUserID = "LibgreGraph.UUID"

	// ScopeRawSubject is the string value for the built-in Raw Subject scope.
	ScopeRawSubject = "LibreGraph.RawSub"

	// ScopeGuestOK is the string value for the built-in Guest OK scope.
	ScopeGuestOK = "LibreGraph.GuestOK"
)

Variables

This section is empty.

Functions

func FromClaimsContext

func FromClaimsContext(ctx context.Context) (jwt.Claims, bool)

FromClaimsContext returns the AuthRecord value stored in ctx, if any.

func NewClaimsContext

func NewClaimsContext(ctx context.Context, claims jwt.Claims) context.Context

NewClaimsContext returns a new Context that carries value auth.

Types

type AccessTokenClaims

type AccessTokenClaims struct {
	jwt.StandardClaims

	TokenType TokenTypeValue `json:"lg.t"`

	AuthorizedClaimsRequest *payload.ClaimsRequest `json:"lg.acr,omitempty"`

	AuthorizedScopesList payload.ScopesValue `json:"scp"`

	IdentityClaims   jwt.MapClaims `json:"lg.i"`
	IdentityProvider string        `json:"lg.p,omitempty"`

	*oidc.SessionClaims
}

AccessTokenClaims define the claims found in access tokens issued.

func (AccessTokenClaims) AuthorizedScopes

func (c AccessTokenClaims) AuthorizedScopes() map[string]bool

AuthorizedScopes returns a map with scope keys and true value of all scopes set in the accociated access token.

func (AccessTokenClaims) Valid

func (c AccessTokenClaims) Valid() error

Valid implements the jwt.Claims interface.

type AccessTokenProvider

type AccessTokenProvider interface {
	MakeAccessToken(ctx context.Context, audience string, auth identity.AuthRecord) (string, error)
}

AccessTokenProvider is an interface for something which can create access tokens.

type NumericIDClaims added in v0.52.0

type NumericIDClaims struct {
	// NOTE(longsleep): Always keep these claims compatible with the GitLab API
	// https://docs.gitlab.com/ce/api/users.html#for-user.
	NumericID         int64  `json:"id,omitempty"`
	NumericIDUsername string `json:"username,omitempty"`
}

NumericIDClaims define the claims used with the konnect/id scope.

func (NumericIDClaims) Valid added in v0.52.0

func (c NumericIDClaims) Valid() error

Valid implements the jwt.Claims interface.

type RefreshTokenClaims

type RefreshTokenClaims struct {
	jwt.StandardClaims

	TokenType TokenTypeValue `json:"lg.t"`

	ApprovedScopesList payload.ScopesValue `json:"scp"`

	ApprovedClaimsRequest *payload.ClaimsRequest `json:"lg.acr,omitempty"`
	Ref                   string                 `json:"lg.r"`

	IdentityClaims   jwt.MapClaims `json:"lg.i"`
	IdentityProvider string        `json:"lg.p,omitempty"`
}

RefreshTokenClaims define the claims used by refresh tokens.

func (RefreshTokenClaims) Valid

func (c RefreshTokenClaims) Valid() error

Valid implements the jwt.Claims interface.

type TokenTypeValue added in v0.52.0

type TokenTypeValue string

TokenType defines the token type value.

const (
	TokenTypeIDToken      TokenTypeValue = "" // Just a placeholder, not actually set in ID Tokens.
	TokenTypeAccessToken  TokenTypeValue = "1"
	TokenTypeRefreshToken TokenTypeValue = "2"
)

The known token type values.

func (TokenTypeValue) Is added in v0.52.0

func (ttv TokenTypeValue) Is(value TokenTypeValue) bool

Is compares the associated TokenTypeValue to the provided one.

type UniqueUserIDClaims

type UniqueUserIDClaims struct {
	UniqueUserID string `json:"lg.uuid,omitempty"`
}

UniqueUserIDClaims define the claims used with the konnect/uuid scope.

func (UniqueUserIDClaims) Valid

func (c UniqueUserIDClaims) Valid() error

Valid implements the jwt.Claims interface.

type UserInfoResponse

type UserInfoResponse struct {
	*payload.UserInfoResponse

	*NumericIDClaims
	*UniqueUserIDClaims
}

UserInfoResponse defines the data returned from the Konnect UserInfo endpoint. It is the standard ODIC response, extended with additional claims.

Jump to

Keyboard shortcuts

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