You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/source/auth-providers.md
+41-2Lines changed: 41 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,7 @@ Giftless provides the following authentication and authorization modules by defa
23
23
24
24
*`giftless.auth.jwt:JWTAuthenticator` - uses [JWT tokens](https://jwt.io/) to both identify
25
25
the user and grant permissions based on scopes embedded in the token payload.
26
+
*`giftless.auth.github:GithubAuthenticator` - uses [GitHub Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) to both identify the user and grant permissions based on those for a GitHub repository of the same organization/name.
26
27
*`giftless.auth.allow_anon:read_only` - grants read-only permissions on everything to every
27
28
request; Typically, this is only useful in testing environments or in very limited
28
29
deployments.
@@ -75,7 +76,7 @@ Basic HTTP authentication.
75
76
76
77
You can disable this functionality or change the expected username using the `basic_auth_user` configuration option.
77
78
78
-
### Configuration Options
79
+
### `giftless.auth.jwt` Configuration Options
79
80
The following options are available for the `jwt` auth module:
80
81
81
82
* `algorithm` (`str`): JWT algorithm to use, e.g. `HS256` (default) or `RS256`. Must match the algorithm
@@ -191,6 +192,37 @@ The `leeway` parameter allows for providing a leeway / grace time to be
191
192
considered when checking expiry times, to cover for clock skew between
192
193
servers.
193
194
195
+
## GitHub Authenticator
196
+
This authenticator lets you provide a frictionless LFS backend for existing GitHub repositories. It plays nicely with `git` credential helpers and allows you to use GitHub as the single authentication & authorization provider.
197
+
198
+
### Details
199
+
The authenticator uses [GitHub Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens), the same ones used for cloning a GitHub repo over HTTPS. The provided token is used in a couple GitHub API calls that identify the token's identity and [its permissions](https://docs.github.com/en/rest/collaborators/collaborators?apiVersion=2022-11-28#get-repository-permissions-for-a-user) for the GitHub organization & repository. The token is supposed to be passed in the password part of the `Basic` HTTP auth (username is ignored). `Bearer` token HTTP auth is also supported, although no git client will likely use it.
200
+
201
+
For the authenticator to work properly the token must have the `read:org` for "Classic" or `metadata:read` permission for the fine-grained kind.
202
+
203
+
Note: Authentication via SSH that could be used to verify the user is [not possible with GitHub at the time of writing](https://github.com/datopian/giftless/issues/128#issuecomment-2037190728).
204
+
205
+
The GitHub repository permissions are mapped to [Giftless permissions](#permissions) in the straightforward sense that those able to write will be able to write, same with read; invalid tokens or identities with no repository access will get rejected.
206
+
207
+
To minimize the traffic to GitHub for each LFS action, most of the auth data is being temporarily cached in memory, which improves performance, but naturally also ignores immediate changes for identities with changed permissions.
208
+
209
+
### GitHub Auth Flow
210
+
Here's a description of the authentication & authorization flow. If any of these steps fails, the request gets rejected.
211
+
212
+
1. The URI of the primary git LFS (HTTP) [`batch` request](https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md) is used (as usual) to determine what GitHub organization and repository is being targeted (e.g. `https://<server>/<org>/<repo>.git/info/lfs/...`). The request's `Authentication` header is also searched for the required GitHub personal access token.
213
+
2. The token is then used in a [`/user`](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user) GitHub API call to get its identity data.
214
+
3. Further on the GitHub API is asked for the [user's permissions](https://docs.github.com/en/rest/collaborators/collaborators?apiVersion=2022-11-28#get-repository-permissions-for-a-user) to the org/repo in question.
215
+
4. Based on the information above the user will be granted or rejected access.
216
+
217
+
### `giftless.auth.github` Configuration Options
218
+
* `api_url` (`str` = `"https://api.github.com"`): Base URL for the GitHub API (enterprise servers have API at `"https://<custom-hostname>/api/v3/"`).
219
+
* `api_version` (`str | None` = `"2022-11-28"`): Target GitHub API version; set to `None` to use GitHub's latest (rather experimental).
220
+
* `cache` (`dict`): Cache configuration section
221
+
* `token_max_size` (`int` = `32`): Max number of entries in the token -> user LRU cache. This cache holds the authentication data for a token. Evicted tokens will need to be re-authenticated.
222
+
* `auth_max_size` (`int` = `32`): Max number of [un]authorized org/repos TTL(LRU) for each user. Evicted repos will need to get re-authorized.
223
+
* `auth_write_ttl` (`float` = `15 * 60`): Max age [seconds] of user's org/repo authorizations able to `WRITE`. A repo writer will also need to be re-authorized after this period.
224
+
* `auth_other_ttl` (`float` = `30`): Max age [seconds] of user's org/repo authorizations **not** able to `WRITE`. A repo reader or a rejected user will get a chance for a permission upgrade after this period.
225
+
194
226
## Understanding Authentication and Authorization Providers
195
227
196
228
This part is more abstract, and will help you understand how Giftless handles
@@ -220,6 +252,10 @@ Very simply, an `Identity` object encapsulates information about the current use
220
252
request, and is expected to have the following interface:
221
253
222
254
```python
255
+
from typing import Optional
256
+
from giftless.auth.identity import Permission
257
+
258
+
223
259
class Identity:
224
260
name: Optional[str] = None
225
261
id: Optional[str] = None
@@ -244,9 +280,12 @@ Authorizer classes may use the default built-in `DefaultIdentity`, or implement
244
280
subclass of their own.
245
281
246
282
#### Permissions
247
-
Giftless defines the following permissions on entites:
283
+
Giftless defines the following permissions on entities:
Copy file name to clipboardExpand all lines: docs/source/configuration.md
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -126,5 +126,17 @@ clients using these URLs. By default, the JWT auth provider is used here.
126
126
127
127
There is typically no need to override the default behavior.
128
128
129
+
#### `LEGACY_ENDPOINTS`
130
+
This is a `bool` flag, default `true` (deprecated, use `false` where possible), that affects the base URI of all the service endpoints. Previously, the endpoints didn't adhere to the rules for [automatic LFS server discovery](https://github.com/git-lfs/git-lfs/blob/main/docs/api/server-discovery.md), which needed additional routing or client configuration.
131
+
132
+
The default base URI for all giftless endpoints is now `/<org_path>/<repo>.git/info/lfs` while the legacy one is `/<org>/<repo>`.
133
+
*`<org>` is a simple organization name not containing slashes (common for GitHub)
134
+
*`<org_path>` is a more versatile organization path which can contain slashes (common for GitLab)
135
+
*`<repo>` is a simple repository name not containing slashes
136
+
137
+
With `LEGACY_ENDPOINTS` set to `true`, **both the current and legacy** endpoints work simultaneously. When using the `basic_streamimg` transfer adapter, for backward compatibility it is the **legacy URI** that is being used for the object URLs in the batch API responses.
138
+
139
+
Setting `LEGACY_ENDPOINTS` to `false` makes everything use the current base URI, requests to the legacy URIs will get rejected.
140
+
129
141
#### `DEBUG`
130
142
If set to `true`, enables more verbose debugging output in logs.
This guide shows how to use Giftless as the LFS server for an existing GitHub repository (not using GitHub LFS). Thanks to a handful tricks it also acts as a full remote HTTPS-based `git` repository, making this a zero client configuration setup.
5
+
6
+
This guide uses `docker compose`, so you need to [install it](https://docs.docker.com/compose/install/). It also relies on you using HTTPS for cloning GitHub repos. The SSH way is not supported.
7
+
8
+
### Running docker containers
9
+
To run the setup, `git clone https://github.com/datopian/giftless`, step into the `examples/github-lfs` and run `docker compose up`.
10
+
11
+
This will run two containers:
12
+
-`giftless`: Locally built Giftless server configured to use solely the [GitHub authentication provider](auth-providers.md#github-authenticator) and a local docker compose volume as the storage backend.
13
+
-`proxy`: An [Envoy reverse proxy](https://www.envoyproxy.io/) which acts as the frontend listening on a local port 5000, configured to route LFS traffic to `giftless` and pretty much anything else to `[api.]github.com`. **The proxy listens at an unencrypted HTTP**, setting the proxy to provide TLS termination is very much possible, but isn't yet covered (your turn, thanks for the contribution!).
14
+
15
+
Feel free to explore the `compose.yaml`, which contains all the details.
16
+
17
+
### Cloning a GitHub repository via proxy
18
+
The frontend proxy forwards the usual `git` traffic to GitHub, so go there and pick/create some testing repository where you have writable access and clone it via the proxy hostname (just change `github.com` for wherever you host):
When you don't use a credential helper, you might get asked a few times for the same credentials before the call gets through. [Make sure to get one](https://git-scm.com/doc/credential-helpers) before it drives you insane.
23
+
24
+
Thanks to the [automatic LFS server discovery](https://github.com/git-lfs/git-lfs/blob/main/docs/api/server-discovery.md) this is all you should need to become LFS-enabled!
25
+
26
+
### Pushing binary blobs
27
+
Let's try pushing some binary blobs then! See also [Quickstart](quickstart.md#create-a-local-repository-and-push-some-file).
28
+
```shell
29
+
# create some blob
30
+
dd if=/dev/urandom of=blob.bin bs=1M count=1
31
+
# make it tracked by LFS
32
+
git lfs track blob.bin
33
+
# the LFS tracking is written in .gitattributes, which you also want committed
34
+
git add .gitattributes blob.bin
35
+
git commit -m 'Hello LFS!'
36
+
# push it, assuming the local branch is main
37
+
# this might fail for the 1st time, when git automatically runs 'git config lfs.locksverify false'
38
+
git push -u origin main
39
+
```
40
+
41
+
This should eventually succeed, and you will find the LFS digest in place of the blob on GitHub and the binary blob on your local storage:
Next time anyone clones the repo (via the proxy), the binary blob will get properly downloaded. Failing to use the proxy hostname will make `git` use GitHub's own LFS, which is a paid service you are obviously trying to avoid.
51
+
52
+
### Service teardown
53
+
54
+
Finally, to shut down your containers, break (`^C`) the current compose run and clean up dead containers with:
55
+
```shell
56
+
docker compose down [--volumes]
57
+
```
58
+
Using `--volumes` tears down the `lfs-storage` volume too, so make sure it's what you wanted.
0 commit comments