Git Product home page Git Product logo

lico's Introduction

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.

lico's People

Contributors

deepdiver1975 avatar dependabot[bot] avatar fbartels avatar fschade avatar iljan avatar klausade avatar longsleep avatar rhafer avatar snehal1112 avatar sotneo avatar trickvi avatar weblate avatar wkloucek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

lico's Issues

Remove vendor specific backends

Since lico evolved out of Kopano Konnect it currently still contains a Kopano Groupware Core specific backend. Since the idea of libregraph is to be as vendor agnostic as possible, this backend should be removed from lico and instead maintained on Kopano side in a dedicated project.

Adding implicit scopes broken for clients requiring consent

I've been trying to implicitly add the LibgreGraph.UUID scope (to always get the lg.uuid claim added to tokens and userinfo) to our client configuration. But it breaks as soon as the client requires consent. (E.g. because trusted is not set to true or when the client sends prompts=consent with the authentication request.

E.g. this (trusted) client config works and successfully includes the lg.uuid claim in the response:

- id: works
  name: ownCloud Web app
  trusted: true
  implicit_scopes:
  - LibgreGraph.UUID
  secret: ""
  redirect_uris:
  - http://127.0.0.1
  - http://localhoyst
  origins: []
  application_type: native

while this one does not (only difference is the missing trusted: true:

- id: broken
  name: ownCloud Web app
  implicit_scopes:
  - LibgreGraph.UUID
  secret: ""
  redirect_uris:
  - http://127.0.0.1
  - http://localhost
  origins: []
  application_type: native

How to reproduce

Start lico using the clients registry from https://gist.github.com/rhafer/8f94d55d39332589ba0cb80fd6c1b2ce#file-identifier-registration-yaml

export LDAP_UUID_ATTRIBUTE=entryUUID
export LDAP_....
bin/licod serve --listen 0.0.0.0:9200 \
    --iss=https://ocis.owncloud.test \
    --signing-private-key private-key.pem \
    --encryption-secret encryption.key ldap  \
    --identifier-client-path identifier/build/ \
    --log-level debug \
    --identifier-registration-conf ~/.ocis/idp/tmp/identifier-registration.yaml

I used a slightly modified version of the go-oidc userinfo sample: https://gist.github.com/rhafer/8f94d55d39332589ba0cb80fd6c1b2ce#file-userinfo-go
which basically just return the userinfo of the authenticated user.

Just copied it into example/userinfo/app.go of a local clone of https://github.com/coreos/go-oidc and run it with:

CLIENT_ID=works go run example/userinfo/app.go

and point your brower to http://127.0.0.1:5556 (ideally a private window) with CLIENT_ID=works the browser should display the userinfo including the lg.uuid claim (provided the used LDAP server returns and entryUUID attribute for the user.

To reproduce the error use CLIENT_ID=broken go run example/userinfo/app.go and open a new private session in the browser.
This time you should be prompted for consent and now the lg.uuid claim is missing from the userinfo. Shouldn't the implict_scopes always be include regardless of the given consent? Or alternatively shouldn't the consent page request consent for that scope if it's part of the implict scopes?

BTW, the problem is also reproducible for trusted clients that require consent. See line 82 on the example app.

Expose configs and files as API in code

For the "embedding as library use-case" the consumer might want to provide a custom-configuration format (memory,vfs). Currently there is no way to embed lico without having an identifier-registration.yml somewhere on the file-system.

To solve this the configuration should be exposed as map or struct internally.

Also other supporting files like certs and secrets should be passable as an io.Reader or byte[].

Related: Kopano-dev/konnect#24

Allow to specify a custom cert file for TLS client config

Currently the TLS config for the different identity backends only allows to either switch off certificate validation completely (by setting Insecure: true) or to rely on the CA set supplied by the host's configuration. It would be good to be able to specify a custom cert to use for verification purposes. (E.g. to allow an easy setup with with self-signed certificates, but avoiding the use of insecure)

Support for password grant types

Reference

https://oauth.net/2/grant-types/password/

Why is this important?

In the context of ocis we are including lico as our default openIDConnect Provider.

It would give us an strong value, to provide a browser-less OIDC flow to get an access token for API usage. This is useful for automated provisioning and deployment tasks as well as 3rd party integrations which are not browser based.

@longsleep Is that something we could agree on? If yes, could you provide a pointer for implementing this?

Attribute tags not working (?)

I'm the maintainer of LLDAP, and a user came to me trying to use OCIS, which uses lico for the LDAP IDP.

They were trying to set the IDP_LDAP_UUID_ATTRIBUTE_TYPE=text env variable, but it didn't have the expected effect: instead of requesting the text version of the UUID, it requested both the uuid attribute and the text attribute (which doesn't exist).

The expected format for an attribute tag would be uuid;text.

I tried to trace it through the code, but I don't understand very well how you use that type attribute. After it's set (e.g.

fmt.Sprintf("%s_type", AttributeUUID): AttributeValueTypeText,
), I couldn't see other references to it specifically. However, I see in several places that you iterate through the attributes to write the values (e.g. ). That's going to completely dissociate the uuid_type from the uuid attribute, and just add a new attribute text or binary. Am I reading this wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.