mirror of
https://github.com/9p4/jellyfin-plugin-sso.git
synced 2026-09-19 13:12:19 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e232d7cf9 | ||
|
|
eaf7e87747 | ||
|
|
8df2bd94e8 | ||
|
|
815d6cbe7e | ||
|
|
6a0fcfe711 | ||
|
|
f9331665e7 | ||
|
|
299f3f7220 | ||
|
|
4eec8bb789 | ||
|
|
55d795b9d8 | ||
|
|
5a8d1da6de | ||
|
|
e3efd97964 | ||
|
|
9199fce64f | ||
|
|
0e590858c0 | ||
|
|
9b4393981c | ||
|
|
29e902c109 | ||
|
|
b777e3a346 | ||
|
|
5da7e02faf |
@@ -0,0 +1,62 @@
|
||||
name: Publish Nightly
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build Dotnet
|
||||
run: dotnet build --no-restore --warnaserror
|
||||
- name: "Flag as nightly in build.yaml"
|
||||
uses: fjogeleit/[email protected]
|
||||
with:
|
||||
valueFile: 'build.yaml'
|
||||
propertyPath: 'version'
|
||||
value: "0.0.0.9000"
|
||||
commitChange: false
|
||||
updateFile: true
|
||||
- name: "JPRM: Build"
|
||||
id: jrpm
|
||||
uses: oddstr13/jellyfin-plugin-repository-manager@b9e92867a6aa279d611a5ea80cf61f6358838c39
|
||||
with:
|
||||
version: "0.0.0.9000"
|
||||
verbosity: debug
|
||||
path: .
|
||||
dotnet-target: "net6.0"
|
||||
output: _dist
|
||||
- name: Publish output artifacts
|
||||
id: publish-assets
|
||||
uses: softprops/action-gh-release@50195ba7f6f93d1ac97ba8332a178e008ad176aa
|
||||
with:
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: true
|
||||
tag_name: nightly
|
||||
files: |
|
||||
_dist/*
|
||||
build.yaml
|
||||
body: |
|
||||
Nightly build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Publish Plugin Manifest
|
||||
uses: Kevinjil/jellyfin-plugin-repo-action@a7832ecc44c6b1a45d531970f6647b8682b005b8
|
||||
with:
|
||||
ignorePrereleases: false
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
repository: ${{ github.repository }}
|
||||
pagesBranch: manifest-release
|
||||
pagesFile: manifest.json
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Publish Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: jellyfin/jellyfin-meta-plugins/.github/workflows/build.yaml@30fd723cc3bafc4457a4a85be3cdbee2f3e2013b
|
||||
with:
|
||||
dotnet-version: "6.0.*"
|
||||
dotnet-target: "net6.0"
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/[email protected]
|
||||
with:
|
||||
name: build-artifact
|
||||
- name: Prepare GitHub Release assets
|
||||
run: |-
|
||||
for file in ./*; do
|
||||
md5sum ${file#./} >> ${file%.*}.md5
|
||||
sha256sum ${file#./} >> ${file%.*}.sha256
|
||||
done
|
||||
ls -l
|
||||
- name: Upload GitHub Release assets
|
||||
uses: shogo82148/[email protected]
|
||||
with:
|
||||
upload_url: ${{ github.event.release.upload_url }}
|
||||
asset_path: ./*
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- upload
|
||||
steps:
|
||||
- name: Publish Plugin Manifest
|
||||
uses: Kevinjil/jellyfin-plugin-repo-action@a7832ecc44c6b1a45d531970f6647b8682b005b8
|
||||
with:
|
||||
ignorePrereleases: false
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
repository: ${{ github.repository }}
|
||||
pagesBranch: manifest-release
|
||||
pagesFile: manifest.json
|
||||
@@ -38,8 +38,13 @@ This is 100% alpha software! PRs are welcome to improve the code.
|
||||
|
||||
## Tested Providers
|
||||
|
||||
[Find provider specific documentation in providers.md](providers.md)
|
||||
|
||||
- Authelia
|
||||
- authentik
|
||||
- Keycloak
|
||||
- OIDC & SAML
|
||||
- Google OpenID: Works, but usernames are all numeric
|
||||
- Keycloak OpenID and SAML: Works
|
||||
|
||||
## Supported Protocols
|
||||
|
||||
@@ -52,7 +57,7 @@ This is my first time writing C# so please take all of the code written here wit
|
||||
|
||||
## Installing
|
||||
|
||||
Add the package repo [https://repo.saggis.com/jellyfin/manifest.json](https://repo.saggis.com/jellyfin/manifest.json) to your Jellyfin configuration. Then, install the package!
|
||||
Add the package repo [https://repo.ersei.net/jellyfin/manifest.json](https://repo.ersei.net/jellyfin/manifest.json) to your Jellyfin configuration. Then, install the package!
|
||||
|
||||
## Building
|
||||
|
||||
|
||||
@@ -563,9 +563,9 @@ public class SSOController : ControllerBase
|
||||
{
|
||||
_logger.LogInformation("SSO user doesn't exist, creating...");
|
||||
user = await _userManager.CreateUserAsync(username).ConfigureAwait(false);
|
||||
user.AuthenticationProviderId = GetType().FullName;
|
||||
}
|
||||
|
||||
user.AuthenticationProviderId = GetType().FullName;
|
||||
if (enableAuthorization)
|
||||
{
|
||||
user.SetPermission(PermissionKind.IsAdministrator, isAdmin);
|
||||
@@ -588,9 +588,9 @@ public class SSOController : ControllerBase
|
||||
_logger.LogInformation("Auth request created...");
|
||||
if (!string.IsNullOrEmpty(defaultProvider))
|
||||
{
|
||||
user.AuthenticationProviderId = defaultProvider;
|
||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||
_logger.LogInformation("Set default login provider to " + defaultProvider);
|
||||
user.AuthenticationProviderId = defaultProvider;
|
||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||
_logger.LogInformation("Set default login provider to " + defaultProvider);
|
||||
}
|
||||
|
||||
return await _sessionManager.AuthenticateDirect(authRequest).ConfigureAwait(false);
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
+200
@@ -0,0 +1,200 @@
|
||||
# Provider Specific Configuration
|
||||
|
||||
This plugin has been tested to work against various providers, though not all providers provide support for all of this plugins' features.
|
||||
|
||||
## TOC / Tested Providers:
|
||||
|
||||
This section is broken into providers that support Role-Based Access Control (RBAC), and those that do not
|
||||
|
||||
### Providers that support RBAC
|
||||
|
||||
- ✅ [Authelia](#authelia)
|
||||
- ✅ [authentik](#authentik)
|
||||
- [✅ Keycloak](#keycloak-oidc)
|
||||
- Both [OIDC](#keycloak-oidc) & [SAML](#keycloak-saml)
|
||||
|
||||
### No RBAC Support
|
||||
|
||||
- ✅ Google OIDC
|
||||
- ❗ Usernames are numeric
|
||||
|
||||
## General Options, when RBAC is supported
|
||||
|
||||
For any provider that supports RBAC, we can configure it as we see fit:
|
||||
|
||||
```yaml
|
||||
Enabled: true
|
||||
EnableAuthorization: true
|
||||
EnableAllFolders: true
|
||||
EnabledFolders: []
|
||||
Roles: ["jellyfin_user"]
|
||||
AdminRoles: ["jellyfin_admin"]
|
||||
EnableFolderRoles: false
|
||||
FolderRoleMapping: []
|
||||
```
|
||||
|
||||
## Authelia
|
||||
|
||||
Authelia is simple to configure, and RBAC is straightforward.
|
||||
|
||||
### Authelia's Config
|
||||
|
||||
Below is the `identity_providers` section of an Authelia config:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
# hmac secret and private key given by env variables
|
||||
clients:
|
||||
- id: jellyfin
|
||||
description: My media server
|
||||
# Client secret should be randomly generated
|
||||
secret: <redacted>
|
||||
authorization_policy: one_factor
|
||||
redirect_uris:
|
||||
- https://jellyfin.example.com/sso/OID/r/authelia
|
||||
```
|
||||
|
||||
### Jellyfin's Config
|
||||
|
||||
On Jellyfin's end, we need to configure an Authelia provider as follows:
|
||||
|
||||
In order to test group membership, we need to request Authelia's `groups` OIDC scope, which we will use to check user roles.
|
||||
|
||||
```yaml
|
||||
authelia:
|
||||
OidEndpoint: https://authelia.example.com
|
||||
OidClientId: jellyfin
|
||||
OidSecret: <redacted>
|
||||
RoleClaim: groups
|
||||
OidScopes: ["groups"]
|
||||
```
|
||||
|
||||
## authentik
|
||||
|
||||
To begin with, we must set up an OIDC provider + application in authentik. Refer to the official documentation for detailed instruction.
|
||||
|
||||
### authentik's Config
|
||||
|
||||
authentik supports RBAC, but is slightly more complicated to configure than Authelia, as we need to configure a custom scope binding to include in the OIDC response.
|
||||
|
||||
To do this, we:
|
||||
|
||||
- create a **Custom Property Mapping**
|
||||
|
||||

|
||||
|
||||
- Create a **Scope Mapping**
|
||||
|
||||

|
||||
|
||||
- Assign the following attributes:
|
||||
|
||||

|
||||
|
||||
```yaml
|
||||
# A nice, human readable name
|
||||
name: Group Membership
|
||||
# The name of the scope a client must request to get access to a user's groups
|
||||
Scope Name: groups
|
||||
# A description of what is being requested to show to a user
|
||||
Description: See Which Groups you belong to
|
||||
```
|
||||
|
||||
- For the **Expression** field, use the following code:
|
||||
```python
|
||||
return [group.name for group in user.ak_groups.all()]
|
||||
```
|
||||
|
||||
Now we can add this property mapping to authentik's Jellyfin OAuth provider:
|
||||
|
||||
- Navigate to `Applications/providers`
|
||||
|
||||

|
||||
|
||||
- Edit / Update your Jellyfin OAuth provider
|
||||
- Under **"Advanced Protocol Settings"**, add the **Group Membership** Scope
|
||||
|
||||

|
||||
|
||||
### Jellyfin's Config
|
||||
|
||||
On Jellyfin's end, we need to configure an authentik provider as follows:
|
||||
|
||||
In order to test group membership, we need to request authentik's OIDC scope `groups`, which we will use to check user roles.
|
||||
|
||||
```yaml
|
||||
authentik:
|
||||
OidEndpoint: https://authentik.example.com/application/o/jellyfin
|
||||
OidClientId: <same-as-in-authentik>
|
||||
OidSecret: <redacted>
|
||||
RoleClaim: groups
|
||||
OidScopes: ["groups"]
|
||||
```
|
||||
|
||||
## Keycloak OIDC
|
||||
|
||||
Keycloak in general is a little more complicated than other providers. Ensure that you have a realm created and have some usable users.
|
||||
|
||||
### Keycloak's Config
|
||||
|
||||
Create a new Keycloak `openid-connect` application. Set the root URL to your Jellyfin URL (ie https://myjellyfin.example.com)
|
||||
|
||||
Ensure that the following configuration options are set:
|
||||
|
||||
- Access Type: Confidential
|
||||
- Standard Flow Enabled
|
||||
- Redirect URI: https://myjellyfin.example.com/sso/OID/r/PROVIDER_NAME
|
||||
- Base URL: https://myjellyfin.example.com
|
||||
|
||||
Press the "Save" button at the bottom of the page and open the "Credentials" tab. Note down the secret.
|
||||
|
||||
For adding groups and RBAC, go to the "mappers" tab, press "Add Builtin", and select either "Groups", "Realm Roles", or "Client Roles", depending on the role system you are planning on using. Once the mapper is added, edit the mapper and ensure that you note down the Token Claim Name as well as enable all four toggles: "Multivalued", "Add to ID token", "Add to access token", and "Add to userinfo" are enabled.
|
||||
|
||||
Note that if you are using the template for the "Client Roles" mapper, the default token claim name has `${client_id}` in it. When noting down this value, make sure you note down the actual Client ID (which should be written above).
|
||||
|
||||
### Jellyfin's Config
|
||||
|
||||
On Jellyfin's side, we need to configure a Keycloak provider as follows:
|
||||
|
||||
```yaml
|
||||
keycloak:
|
||||
OidEndpoint: https://keycloak.example.com/realms/<realm>
|
||||
OidClientId: <same-as-in-keycloak>
|
||||
OidSecret: <redacted>
|
||||
RoleClaim: <same-as-token-claim-name>
|
||||
```
|
||||
|
||||
## Keycloak SAML
|
||||
|
||||
Keycloak with SAML is very similar to OpenID. Again, Keycloak in general is a little more complicated than other providers. Ensure that you have a realm created and have some usable users.
|
||||
|
||||
### Keycloak's Config
|
||||
|
||||
Create a new Keycloak `saml` application. Set the root URL to your Jellyfin URL (ie https://myjellyfin.example.com)
|
||||
|
||||
Ensure that the following configuration options are set:
|
||||
|
||||
- Sign Documents on
|
||||
- Sign Assertions off
|
||||
- Client Signature Required off
|
||||
- Redirect URI: [https://myjellyfin.example.com/sso/SAML/p/PROVIDER_NAME](https://myjellyfin.example.com/sso/SAML/p/PROVIDER_NAME)
|
||||
- Base URL: [https://myjellyfin.example.com](https://myjellyfin.example.com)
|
||||
- Master SAML processing URL: [https://myjellyfin.example.com/sso/SAML/p/PROVIDER_NAME](https://myjellyfin.example.com/sso/SAML/p/PROVIDER_NAME)
|
||||
|
||||
Press the "Save" button at the bottom of the page.
|
||||
|
||||
For adding groups and RBAC, go to the "mappers" tab, press "Add Builtin", and select either "Groups", "Realm Roles", or "Client Roles", depending on the role system you are planning on using. Once the mapper is added, edit the mapper and ensure that you note down the Token Claim Name as well as enable all four toggles: "Multivalued", "Add to ID token", "Add to access token", and "Add to userinfo" are enabled.
|
||||
|
||||
Note that if you are using the template for the "Client Roles" mapper, the default token claim name has `${client_id}` in it. When noting down this value, make sure you note down the actual Client ID (which should be written above).
|
||||
|
||||
Finally, download the certificate. Open the "Installation" tab, select "Mod Auth Mellon files", and download the zip. Extract the zip file, and open the `idp-metadata.xml` file. Note down the contents of the `X509Certificate` value.
|
||||
|
||||
### Jellyfin's Config
|
||||
|
||||
```yaml
|
||||
keycloak:
|
||||
SamlEndpoint: https://keycloak.example.com/realms/<realm>/protocol/saml
|
||||
SamlClientId: <same-as-in-keycloak>
|
||||
SamlCertificate: <copied-from-xml-file>
|
||||
```
|
||||
Reference in New Issue
Block a user