forked from vtsykun/packeton
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
782 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# JWT API Authentication | ||
|
||
By default, packeton is storage api tokens in database for each user. But when user | ||
loaded from custom user provider, like LDAP need to enable JWT configuration to use API. So Packeton can be | ||
configured with a non-standard login type to support [JSON Web Tokens](https://en.wikipedia.org/wiki/JSON_Web_Token). | ||
|
||
The JSON Web Token integration in Packeton uses the [Firebase library](https://github.com/firebase/php-jwt). | ||
Also, JWT authentication can be enabled only for API. | ||
|
||
Add `yaml` configuration file to path `config/packages/`, for example `config/packages/jwt.yaml` to enable it. | ||
|
||
```yaml | ||
packeton: | ||
jwt_authentication: | ||
private_key: '%kernel.project_dir%/var/jwt/eddsa-key.pem' | ||
public_key: '%kernel.project_dir%/var/jwt/eddsa-public.pem' | ||
``` | ||
Full configurations: | ||
```yaml | ||
# config/packages/config/packages/jwt.yaml | ||
packeton: | ||
jwt_authentication: | ||
private_key: '%kernel.project_dir%/var/jwt/eddsa-key.pem' # required for token sign | ||
public_key: '%kernel.project_dir%/var/jwt/eddsa-public.pem' # required for token verification | ||
passphrase: ~ | ||
algo: EdDSA # Sign algo, here libsodium EdDSA | ||
``` | ||
## Generate the public/private keys | ||
``` | ||
bin/console packagist:jwt:generate-keypair | ||
|
||
bin/console packagist:jwt:generate-keypair --overwrite | ||
``` | ||
|
||
Available options: | ||
* --overwrite will overwrite your keys if they already exist. | ||
|
||
If keys already exists, a warning message will be raised to prevent you from overwriting your keys accidentally. | ||
|
||
### JWT Token TTL. | ||
|
||
JWT Token is never expire. It was done for compatibility with composer basic HTTP authorization. | ||
Each time the api is called, Packeton is checked that the user exists in the database and that | ||
he has the same set of permissions and roles. | ||
|
||
### Digital signatures algos. | ||
|
||
We support all algos from Firebase lib: HMAC, OpenSSL RSA, OpenSSL | ||
|
||
Rsa, HMAC, EdDSA algorithms generate invariant tokens, i.e. the value of the token will be constant for the same user. | ||
It might be convenient as the app does not store the generated tokens. | ||
|
||
Example how to change algo: | ||
|
||
```yaml | ||
packeton: | ||
jwt_authentication: | ||
... | ||
algo: RS256 # RSA 256 | ||
``` | ||
### Generating keys using OpenSSL | ||
Example, how to generate an RSA private key, `key.pem` - private key. `public.pem` - public | ||
|
||
``` | ||
openssl genrsa -out key.pem 2048 | ||
openssl rsa -in key.pem -outform PEM -pubout -out public.pem | ||
``` | ||
Example, how to generate an ES256 (elliptic curve) key pairs. | ||
``` | ||
openssl ecparam -name prime256v1 -genkey -noout -out key.pem | ||
openssl ec -in key.pem -pubout -out public.pem | ||
``` | ||
## Obtain the token | ||
You can run command `packagist:user:manager` to show the api token: | ||
``` | ||
bin/console packagist:user:manager admin --show-token --token-format=jwt | ||
``` | ||
Or you can found api token on your profile page. | ||
[](img/jwt_keys.png) | ||
### Use the token | ||
Simply use the JWT, like standard API token for composer api. | ||
#### Cache LDAP user loading. | ||
Since 2.0 composer downloads all packages in parallel, it may run more 12 request at the same time. | ||
To prevent calls external LDAP provider each time for JWT token verify, the obtained LDAP user object | ||
placed to cache with 60 sec TTL. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# Authenticating against an LDAP server | ||
|
||
You can enable LDAP authenticating only on configuration level. | ||
|
||
Packeton has pre-installed Symfony LDAP component. Add the file `config/packages/ldap.yaml` to enable LDAP | ||
with following content. See LDAP in [Symfony Docs](https://symfony.com/doc/current/security/ldap.html) | ||
|
||
```yaml | ||
parameters: | ||
default_login_provider: 'form_login_ldap' | ||
default_login_options: | ||
provider: all_users | ||
login_path: /login | ||
use_forward: false | ||
check_path: /login | ||
failure_path: null | ||
service: Symfony\Component\Ldap\Ldap | ||
dn_string: 'uid={username},dc=example,dc=com' | ||
|
||
services: | ||
Symfony\Component\Ldap\Ldap: | ||
arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter'] | ||
tags: | ||
- ldap | ||
|
||
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter: | ||
arguments: | ||
- host: ldap.forumsys.com | ||
port: 389 | ||
|
||
security: | ||
providers: | ||
users_ldap: | ||
ldap: | ||
service: Symfony\Component\Ldap\Ldap | ||
base_dn: dc=example,dc=com | ||
search_dn: "cn=read-only-admin,dc=example,dc=com" | ||
search_password: password | ||
default_roles: ROLE_MAINTAINER | ||
uid_key: uid | ||
|
||
all_users: | ||
chain: | ||
providers: ['packagist', 'users_ldap'] | ||
``` | ||
Here is working example where used test `ldap.forumsys.com` server https://www.forumsys.com/2022/05/10/online-ldap-test-server/ | ||
|
||
Using LDAP integration does not prevent you from creating user manually from CLI and assign more accessible roles. | ||
At the same LDAP password validation will be done on LDAP server side, because `CheckLdapCredentialsListener` has higher priority | ||
loading than default check listener. Therefore, if user is not enable in LDAP - it will not able login to packeton. | ||
|
||
## User providers priority. | ||
|
||
Packeton use Symfony [Chain User Provider](https://symfony.com/doc/current/security/user_providers.html#chain-user-provider) | ||
to lookup users. | ||
|
||
If you want to use customer user restriction by vendors and versions, `packagist` user provider must load before ldap. | ||
|
||
```yaml | ||
security: | ||
providers: | ||
users_ldap: | ||
ldap: | ||
... | ||
all_users: | ||
chain: | ||
providers: ['packagist', 'users_ldap'] # Load user/roles form default packagist and if not found - use ldap user | ||
providers: ['users_ldap', 'packagist'] # packagist users will be ignore | ||
``` | ||
|
||
## Load different roles from LDAP. | ||
|
||
You can use more 1 user providers: | ||
|
||
```yaml | ||
security: | ||
providers: | ||
users_ldap: | ||
ldap: | ||
service: Symfony\Component\Ldap\Ldap | ||
base_dn: dc=example,dc=com | ||
search_dn: "cn=read-only-admin,dc=example,dc=com" | ||
filter: "(&(objectclass=groupOfUniqueNames)(ou=scientists)(uniqueMember=uid={username},dc=example,dc=com))" | ||
search_password: password | ||
default_roles: ROLE_MAINTAINER | ||
uid_key: uid | ||
users_ldap_admin: | ||
ldap: | ||
service: Symfony\Component\Ldap\Ldap | ||
base_dn: dc=example,dc=com | ||
search_dn: "cn=read-only-admin,dc=example,dc=com" | ||
filter: "(&(objectclass=groupOfUniqueNames)(ou=mathematicians)(uniqueMember=uid={username},dc=example,dc=com))" | ||
search_password: password | ||
default_roles: ROLE_ADMIN | ||
uid_key: uid | ||
all_users: | ||
chain: | ||
providers: ['packagist', 'users_ldap', 'users_ldap_admin'] | ||
``` | ||
|
||
Here test example where exists two Groups (ou) that include: | ||
|
||
* ou=mathematicians,dc=example,dc=com - assign role ROLE_ADMIN | ||
* ou=scientists,dc=example,dc=com - assign role ROLE_MAINTAINER | ||
|
||
## API authentication with LDAP users. | ||
|
||
By default, packeton is storage api token in database for each user. | ||
But if the user was loaded by custom external users' provider, but from the database, you will need enable JWT configuration. | ||
See [JWT Configuration](authentication-jwt.md) | ||
|
||
## Enable LDAP for docker runtime. | ||
|
||
You can use docker volume to share own configuration to application. | ||
|
||
``` | ||
... | ||
volumes: | ||
- .docker:/data | ||
- ${PWD}/ldap.yaml:/var/www/packagist/config/packages/ldap.yaml | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# User Authentication | ||
|
||
Packeton may support multiple methods of authenticating users. It can additionally be extended to support | ||
custom authentication schemes. | ||
|
||
## Web User authentication | ||
Included in packeton is support for authenticating users via: | ||
|
||
* A username and password. | ||
* An email address and password. | ||
|
||
But possible to enable LDAP only via configuration, see [ldap authentication](./authentication-ldap.md) | ||
|
||
## Composer API authentication | ||
|
||
Packeton is support API authentication only with api token. Password usage is not allowed. | ||
You can see api token in thr user profile menu. | ||
|
||
Support for authenticating users via: | ||
* HTTP Basic Authentication (username and api token) | ||
* Short query param `token` = `username:apiToken` | ||
* Default packagist hook API (query params: `username` = username, `apiToken` = apiToken) | ||
|
||
Your customer needs to authenticate to access their Composer repository: | ||
The simplest way to provide your credentials is providing your set of credentials inline with the repository specification such as: | ||
|
||
```json | ||
{ | ||
"repositories": [ | ||
{ | ||
"type": "composer", | ||
"url": "https://<username>:<api_token>@example.org" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
When you don't want to hard code your credentials into your composer.json, you can set up it global. | ||
|
||
``` | ||
composer config --global --auth http-basic.example.org username api_token | ||
``` | ||
|
||
Example API call. | ||
|
||
``` | ||
curl https://example.com/packages/list.json | ||
-u "username:apiToken" | ||
``` | ||
|
||
``` | ||
curl https://example.com/packages/list.json?token=username:apiToken | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.