vaultwarden icon indicating copy to clipboard operation
vaultwarden copied to clipboard

OIDC SSO Re: Issue #246

Open Sheap opened this issue 3 years ago • 64 comments

This branch adds the minimal required changes to allow OIDC SSO (at least with keycloak. There are many options/features of the process which I did not address, which may rule out other providers).

This is so far my biggest contact point with rust in a web server, as well as in implementing OIDC, so I wouldn't be surprised if there were places where I strayed from the path. But I have tested it, and at least it works. I'd welcome any feedback here. My greatest concern is that I'm currently ignoring the nonce. I believe it should be checked against, but I'm not sure where would be a sensible place to store it between generating it alongside the auth url, and consuming it when exchanging the code for an access token.

Note: There are associated changes required to the webvault here - I wasn't sure how I should link them, so to keep things simple for now, I've simply included a .patch file in this repo.

Sheap avatar Sep 01 '21 15:09 Sheap

Hi @Sheap Could you import your public GPG key into your GitHub account ?

williamdes avatar Sep 01 '21 18:09 williamdes

Done

Sheap avatar Sep 02 '21 07:09 Sheap

If you know a way to quickly setup a keycloak server to test this that would be great too

Running a docker instance of keycloak seems like the simplest option:

docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:15.0.2

I'm trying to test this PR locally, but haven't succeeded yet. The code builds and runs, but I don't see the "Login with SSO" button.

@Sheap What config (.env file) are you using, do I need to change anything besides the data folder? Also, how did you apply the patch?

pinpox avatar Sep 09 '21 09:09 pinpox

I manged to apply the patch, but am running into build errors. This is what I did:

git clone https://github.com/bitwarden/web.git
cd web
git checkout 62cd45030ad5b0a0bdbd08f0579f8ffac91a48a4
wget https://raw.githubusercontent.com/dani-garcia/vaultwarden/635a48514fad1f279379c954361bc493d64f7f0a/web-vault-sso.patch
git submodule update --init --recursive
git apply web-vault-sso.patch
npm install
npm run dist

Build output:

Build output

» npm run dist


> [email protected] dist /home/pinpox/code/github.com/bitwarden/web
> npm run build:prod && gulp postdist


> [email protected] build:prod /home/pinpox/code/github.com/bitwarden/web
> gulp prebuild && cross-env NODE_ENV=production ENV=production webpack

[14:04:31] Using gulpfile ~/code/github.com/bitwarden/web/gulpfile.js
[14:04:31] Starting 'prebuild'...
[14:04:31] Starting 'clean'...
[14:04:31] Finished 'clean' after 9.89 ms
[14:04:31] Starting 'webfonts'...
[14:04:32] Finished 'webfonts' after 360 ms
[14:04:32] Finished 'prebuild' after 372 ms
==================================================
envConfig
  proxyApi: https://api.bitwarden.com
  proxyIdentity: https://identity.bitwarden.com
  proxyEvents: https://events.bitwarden.com
  proxyNotifications: https://notifications.bitwarden.com
  proxyPortal: https://portal.bitwarden.com
  allowedHosts:
==================================================
Compiling @angular/core : module as esm2015
Compiling @angular/animations : module as esm2015
Compiling @angular/common : module as esm2015
Compiling @angular/cdk/collections : module as esm2015
Compiling @angular/animations/browser : module as esm2015
Compiling @angular/cdk/platform : module as esm2015
Compiling @angular/platform-browser : module as esm2015
Compiling ngx-infinite-scroll : module as esm5
Compiling @angular/cdk/bidi : module as esm2015
Compiling @angular/platform-browser-dynamic : module as esm2015
Compiling @angular/cdk/scrolling : module as esm2015
Compiling angular2-toaster : module as esm2015
Compiling @angular/router : module as esm2015
Compiling @angular/cdk/drag-drop : module as esm2015
Compiling @angular/forms : module as esm2015
Compiling @angular/platform-browser/animations : module as esm2015
Hash: 9e346d1a06390c2e3b8f
Version: webpack 4.46.0
Time: 12596ms
Built at: 15/09/2021 14.04.53
                                                   Asset       Size  Chunks               Chunk Names
                                               .nojekyll    0 bytes
                                                404.html   2.28 KiB
                                   404/bootstrap.min.css    158 KiB
                                404/font-awesome.min.css   30.3 KiB
                                          404/styles.css   2.28 KiB
                                             app-id.json  276 bytes
                        app/main.9e346d1a06390c2e3b8f.js  986 bytes       0  [immutable]  app/main
                    app/main.9e346d1a06390c2e3b8f.js.map   4.54 KiB       0  [dev]        app/main
                   app/polyfills.9e346d1a06390c2e3b8f.js  990 bytes       1  [immutable]  app/polyfills
               app/polyfills.9e346d1a06390c2e3b8f.js.map   4.55 KiB       1  [dev]        app/polyfills
                                       browserconfig.xml  234 bytes
              connectors/captcha.9e346d1a06390c2e3b8f.js  989 bytes       2  [immutable]  connectors/captcha
          connectors/captcha.9e346d1a06390c2e3b8f.js.map   4.55 KiB       2  [dev]        connectors/captcha
                  connectors/duo.9e346d1a06390c2e3b8f.js  985 bytes       3  [immutable]  connectors/duo
              connectors/duo.9e346d1a06390c2e3b8f.js.map   4.55 KiB       3  [dev]        connectors/duo
                  connectors/sso.9e346d1a06390c2e3b8f.js  985 bytes       4  [immutable]  connectors/sso
              connectors/sso.9e346d1a06390c2e3b8f.js.map   4.55 KiB       4  [dev]        connectors/sso
                  connectors/u2f.9e346d1a06390c2e3b8f.js   2.34 KiB       5  [immutable]  connectors/u2f
              connectors/u2f.9e346d1a06390c2e3b8f.js.map   9.74 KiB       5  [dev]        connectors/u2f
    connectors/webauthn-fallback.9e346d1a06390c2e3b8f.js  999 bytes       7  [immutable]  connectors/webauthn-fallback
connectors/webauthn-fallback.9e346d1a06390c2e3b8f.js.map   4.56 KiB       7  [dev]        connectors/webauthn-fallback
             connectors/webauthn.9e346d1a06390c2e3b8f.js  990 bytes       6  [immutable]  connectors/webauthn
         connectors/webauthn.9e346d1a06390c2e3b8f.js.map   4.55 KiB       6  [dev]        connectors/webauthn
                                             favicon.ico   33.7 KiB
                                            images/0.png   5.91 KiB
                                            images/1.png   2.61 KiB
                                            images/2.png   1.18 KiB
                                            images/3.png   1.59 KiB
                                          images/404.png     92 KiB
                                            images/7.png   1.58 KiB
                                        images/cards.png   17.1 KiB
                                     images/fa-globe.png  344 bytes
                 images/icons/android-chrome-192x192.png   5.15 KiB
                 images/icons/android-chrome-512x512.png   13.4 KiB
                       images/icons/apple-touch-icon.png   4.19 KiB
                          images/icons/favicon-16x16.png   2.11 KiB
                          images/icons/favicon-32x32.png    3.5 KiB
                         images/icons/mstile-150x150.png   5.24 KiB
                      images/icons/safari-pinned-tab.svg    2.6 KiB
                                      images/loading.svg  291 bytes
                                 images/[email protected]   10.1 KiB
                        images/logo-horizontal-white.png   16.4 KiB
        images/register-layout/logo-horizontal-white.png   16.4 KiB
                   images/register-layout/wired-logo.png   2.86 KiB
                               images/totp-countdown.png    1.6 KiB
                                 images/two-factor/0.png   5.91 KiB
                                 images/two-factor/1.png   2.61 KiB
                                 images/two-factor/2.png   1.18 KiB
                                 images/two-factor/3.png   1.59 KiB
                                 images/two-factor/4.png    4.7 KiB
                                 images/two-factor/6.png   1.18 KiB
                                 images/two-factor/7.png   1.58 KiB
                                       images/u2fkey.jpg    174 KiB
                                   images/wired-logo.png   2.86 KiB
                                      images/yubikey.jpg   27.5 KiB
                                locales/af/messages.json    116 KiB
                                locales/az/messages.json    115 KiB
                                locales/be/messages.json    123 KiB
                                locales/bg/messages.json    161 KiB
                                locales/bn/messages.json    125 KiB
                                locales/ca/messages.json    125 KiB
                                locales/cs/messages.json    122 KiB
                                locales/da/messages.json    118 KiB
                                locales/de/messages.json    126 KiB
                                locales/el/messages.json    166 KiB
                                locales/en/messages.json    115 KiB
                             locales/en_GB/messages.json    115 KiB
                             locales/en_IN/messages.json    115 KiB
                                locales/eo/messages.json    117 KiB
                                locales/es/messages.json    123 KiB
                                locales/et/messages.json    118 KiB
                                locales/fi/messages.json    121 KiB
                                locales/fr/messages.json    129 KiB
                                locales/he/messages.json    130 KiB
                                locales/hr/messages.json    118 KiB
                                locales/hu/messages.json    126 KiB
                                locales/id/messages.json    119 KiB
                                locales/it/messages.json    123 KiB
                                locales/ja/messages.json    129 KiB
                                locales/kn/messages.json    165 KiB
                                locales/ko/messages.json    124 KiB
                                locales/lv/messages.json    122 KiB
                                locales/ml/messages.json    160 KiB
                                locales/nb/messages.json    119 KiB
                                locales/nl/messages.json    120 KiB
                                locales/pl/messages.json    122 KiB
                             locales/pt_BR/messages.json    123 KiB
                             locales/pt_PT/messages.json    122 KiB
                                locales/ro/messages.json    124 KiB
                                locales/ru/messages.json    160 KiB
                                locales/si/messages.json    115 KiB
                                locales/sk/messages.json    122 KiB
                                locales/sl/messages.json    116 KiB
                                locales/sr/messages.json    116 KiB
                                locales/sv/messages.json    120 KiB
                                locales/tr/messages.json    121 KiB
                                locales/uk/messages.json    159 KiB
                                locales/vi/messages.json    120 KiB
                             locales/zh_CN/messages.json    111 KiB
                             locales/zh_TW/messages.json    112 KiB
                                           manifest.json  352 bytes
                                       scripts/dropin.js    466 KiB
                                   scripts/qrious.min.js   17.1 KiB
                       scripts/qrious.min.js.LICENSE.txt  127 bytes
                                          scripts/u2f.js    6.6 KiB
Entrypoint app/polyfills = app/polyfills.9e346d1a06390c2e3b8f.js app/polyfills.9e346d1a06390c2e3b8f.js.map
Entrypoint app/main = app/main.9e346d1a06390c2e3b8f.js app/main.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/u2f = connectors/u2f.9e346d1a06390c2e3b8f.js connectors/u2f.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/webauthn = connectors/webauthn.9e346d1a06390c2e3b8f.js connectors/webauthn.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/webauthn-fallback = connectors/webauthn-fallback.9e346d1a06390c2e3b8f.js connectors/webauthn-fallback.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/duo = connectors/duo.9e346d1a06390c2e3b8f.js connectors/duo.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/sso = connectors/sso.9e346d1a06390c2e3b8f.js connectors/sso.9e346d1a06390c2e3b8f.js.map
Entrypoint connectors/captcha = connectors/captcha.9e346d1a06390c2e3b8f.js connectors/captcha.9e346d1a06390c2e3b8f.js.map
[0] external "u2f" 42 bytes {5} [built]
[1] ./src/app/polyfills.ts 0 bytes {1} [built]
[2] ./src/app/main.ts 0 bytes {0} [built]
[3] ./src/connectors/u2f.js 3 KiB {5} [built]
[4] ./src/connectors/webauthn.ts 0 bytes {6} [built]
[5] ./src/connectors/webauthn-fallback.ts 0 bytes {7} [built]
[6] ./src/connectors/duo.ts 0 bytes {3} [built]
[7] ./src/connectors/sso.ts 0 bytes {4} [built]
[8] ./src/connectors/captcha.ts 0 bytes {2} [built]

ERROR in jslib/common/src/abstractions/api.service.ts:36:46 - error TS2307: Cannot find module '../models/request/organizationSsoUpdateRequest' or its corresponding type declarations.

36 import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/app-routing.module.ts:36:49 - error TS2307: Cannot find module './organizations/settings/sso.component' or its corresponding type declarations.

36 import { SsoComponent as OrgSsoComponent } from './organizations/settings/sso.component';
                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jslib/common/src/services/api.service.ts:40:46 - error TS2307: Cannot find module '../models/request/organizationSsoUpdateRequest' or its corresponding type declarations.

40 import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/app.module.ts:70:49 - error TS2307: Cannot find module './organizations/settings/sso.component' or its corresponding type declarations.

70 import { SsoComponent as OrgSsoComponent } from './organizations/settings/sso.component';
                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Child HtmlWebpackCompiler:
                          Asset      Size  Chunks  Chunk Names
    __child-HtmlWebpackPlugin_0  5.75 KiB       0  HtmlWebpackPlugin_0
    __child-HtmlWebpackPlugin_1  3.89 KiB       1  HtmlWebpackPlugin_1
    __child-HtmlWebpackPlugin_2  3.79 KiB       2  HtmlWebpackPlugin_2
    __child-HtmlWebpackPlugin_3  5.16 KiB       3  HtmlWebpackPlugin_3
    __child-HtmlWebpackPlugin_4   5.8 KiB       4  HtmlWebpackPlugin_4
    __child-HtmlWebpackPlugin_5  5.74 KiB       5  HtmlWebpackPlugin_5
    __child-HtmlWebpackPlugin_6  3.87 KiB       6  HtmlWebpackPlugin_6
        images/[email protected]  10.1 KiB
              images/u2fkey.jpg   174 KiB
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
    Entrypoint HtmlWebpackPlugin_1 = __child-HtmlWebpackPlugin_1
    Entrypoint HtmlWebpackPlugin_2 = __child-HtmlWebpackPlugin_2
    Entrypoint HtmlWebpackPlugin_3 = __child-HtmlWebpackPlugin_3
    Entrypoint HtmlWebpackPlugin_4 = __child-HtmlWebpackPlugin_4
    Entrypoint HtmlWebpackPlugin_5 = __child-HtmlWebpackPlugin_5
    Entrypoint HtmlWebpackPlugin_6 = __child-HtmlWebpackPlugin_6
    [0] ./node_modules/html-loader/dist/runtime/getUrl.js 548 bytes {0} {3} {4} {5} [built]
    [1] ./src/images/[email protected] 67 bytes {0} {4} {5} [built]
    [2] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 1.31 KiB {0} [built]
    [3] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/duo.html 287 bytes {1} [built]
    [4] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/u2f.html 183 bytes {2} [built]
    [5] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/webauthn.html 701 bytes {3} [built]
    [6] ./src/images/u2fkey.jpg 61 bytes {3} [built]
    [7] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/webauthn-fallback.html 1.32 KiB {4} [built]
    [8] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/sso.html 1.3 KiB {5} [built]
    [9] ./node_modules/html-webpack-plugin/lib/loader.js!./src/connectors/captcha.html 271 bytes {6} [built]
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build:prod: `gulp prebuild && cross-env NODE_ENV=production ENV=production webpack`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build:prod script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/pinpox/.npm/_logs/2021-09-15T12_04_53_567Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dist: `npm run build:prod && gulp postdist`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dist script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/pinpox/.npm/_logs/2021-09-15T12_04_53_601Z-debug.log

pinpox avatar Sep 15 '21 12:09 pinpox

@pinpox sorry for the delay in getting back to you - I was busy last week, then had a long weekend :relaxed: Regarding .env file, I just copied the template. The webvault build should be fixed, but this isn't the way I'm running things locally. I have the webvault repo cloned within my vaultwarden one, and then make the following changes to get it running in docker locally:

diff --git a/.dockerignore b/.dockerignore
index 69f51d2..6bc2dbd 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -3,7 +3,6 @@ target

 # Data folder
 data
-.env
 .env.template
 .gitattributes

@@ -24,4 +23,4 @@ hooks
 tools

 # Web vault
-web-vault
\ No newline at end of file
+#web-vault
diff --git a/docker/amd64/Dockerfile b/docker/amd64/Dockerfile
index 70d9c8f..8737ad5 100644
--- a/docker/amd64/Dockerfile
+++ b/docker/amd64/Dockerfile
@@ -22,7 +22,6 @@
 #     $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
 #     [vaultwarden/web-vault:v2.21.1]
 #
-FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault

 ########################## BUILD IMAGE  ##########################
 FROM rust:1.53 as build
@@ -101,7 +100,7 @@ EXPOSE 3012
 # and the binary from the "build" stage to the current stage
 WORKDIR /
 COPY Rocket.toml .
-COPY --from=vault /web-vault ./web-vault
+COPY ./web-vault/build ./web-vault
 COPY --from=build /app/target/release/vaultwarden .

 COPY docker/healthcheck.sh /healthcheck.sh

@dani-garcia Thanks for the comments - I've addressed the simpler points already, but I didn't have time today to look into the ones which required more consideration. I'll hopefully get to them this week.

Sheap avatar Sep 15 '21 15:09 Sheap

@Sheap I just wanted to say thank you for getting the ball rolling on this. It's amazing!

technowhizz avatar Sep 16 '21 08:09 technowhizz

@Sheap I got it to work, but am running into a panic when trying to Login via SSO:

[2021-09-20 09:42:35.537][request][INFO] GET /identity/account/prevalidate?domainHint=test-org
[2021-09-20 09:42:35.537][response][INFO] GET /identity/account/prevalidate?<domainHint> (prevalidate) => 200 OK
[2021-09-20 09:42:35.596][request][INFO] GET /identity/connect/authorize?client_id=web&redirect_uri=htt
[2021-09-20 09:42:35.612][panic][ERROR] thread 'unnamed' panicked at 'invalid issuer URL: RelativeUrlWithoutBase': src/api/identity.rs:583
   0: vaultwarden::init_logging::{{closure}}
   1: std::panicking::rust_panic_with_hook
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/std/src/panicking.rs:628:17
   2: std::panicking::begin_panic_handler::{{closure}}
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/std/src/panicking.rs:521:13
   3: std::sys_common::backtrace::__rust_end_short_backtrace
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/std/src/sys_common/backtrace.rs:141:18
   4: rust_begin_unwind
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/std/src/panicking.rs:517:5
   5: core::panicking::panic_fmt
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/core/src/panicking.rs:93:14
   6: core::result::unwrap_failed
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/core/src/result.rs:1617:5
   7: vaultwarden::api::identity::get_client_from_identifier
   8: vaultwarden::api::identity::rocket_route_fn_authorize
   9: <F as rocket::handler::Handler>::handle
  10: rocket::rocket::Rocket::route_and_process
  11: <rocket::rocket::Rocket as hyper::server::Handler>::handle
  12: hyper::server::Worker<H>::handle_connection
  13: hyper::server::listener::spawn_with::{{closure}}
  14: std::sys_common::backtrace::__rust_begin_short_backtrace
  15: core::ops::function::FnOnce::call_once{{vtable.shim}}
  16: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/alloc/src/boxed.rs:1636:9
      <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/alloc/src/boxed.rs:1636:9
      std::sys::unix::thread::Thread::new::thread_start
             at rustc/d3e2578c31688619ddc0a10ddf8543bf4ebcba5b/library/std/src/sys/unix/thread.rs:106:17
  17: start_thread
  18: clone

Might be a configuration error, but a panic seems a bit harsh?

pinpox avatar Sep 20 '21 09:09 pinpox

It's not an error I've seen. Removing the panics in favour of graceful errors is one of the things I'm looking into at the moment.

Sheap avatar Sep 20 '21 11:09 Sheap

Okay, big changes :sleepy:. I think I've addressed all of the above points now. Hopefully we're close, I'm going to have some other commitments taking up most of my time now, so I won't have much more time to work on this.

Sheap avatar Sep 22 '21 12:09 Sheap

The newest patch fails to apply again:

» git apply ../web-vault-sso.patch
error: src/app/organizations/settings/sso.component.html: No such file or directory
error: src/app/organizations/settings/sso.component.ts: No such file or directory

Are these files missing?

pinpox avatar Sep 27 '21 09:09 pinpox

The newest patch fails to apply again:

» git apply ../web-vault-sso.patch
error: src/app/organizations/settings/sso.component.html: No such file or directory
error: src/app/organizations/settings/sso.component.ts: No such file or directory

Are these files missing?

Again, this is not the correct place for those patches. Also, the web-vault has been updated in the mean time, so this patch will probably not work at all.

BlackDex avatar Sep 27 '21 09:09 BlackDex

Again, this is not the correct place for those patches

I got it to build by adding the files from the previous patch version. @BlackDex what would be the correct place for it or where/how would you prefer to continue with the development on this?

pinpox avatar Sep 27 '21 09:09 pinpox

Hi @Sheap -- this is awesome, thank you for contributing this (I've been hoping for sso on vaultwarden for some time now) and for your efforts.

One clarifying question from a user (I'm not a contributor here, yet) -- does your PR only support vaultwarden initiating the SSO and handling the responses for auth? Or does it also allow for the jwt or information to be passed from upstream (e.g. something like oauth2proxy or Caddy's auth portal)?

j0sh3rs avatar Oct 07 '21 15:10 j0sh3rs

This would be really a killing feature for me. Can"t wait! Any progress so far?

Akruidenberg avatar Oct 25 '21 18:10 Akruidenberg

This would be really a killing feature for me. Can"t wait! Any progress so far?

To be clear: This is NOT actuall SSO, it just adds dubble authentication with the SSO provider as first-stage. Maybe change the title of the ticket to be clear it is NOT actually SSO?

PrivatePuffin avatar Nov 03 '21 17:11 PrivatePuffin

Also from my Side @Sheap „awesome contribution.“

As @Ornias1993 said, this is only a double auth as main login stage. For my clarification. Does that mean that the credentials live in keycloak and a user account is created in vaultwarden when the user logs in the first time with keycloak? But the keycloak login (SSO) actually does not persist over too other SSO clients?

jakoberpf avatar Nov 12 '21 08:11 jakoberpf

To be clear on the whole SSO support of Bitwarden (and thus Vaultwarden if it will be implemented). It is only used to verify if a user has access, and an account can be created via SSO. A user always needs to provide an encryption password for the vault since Bitwarden doesn't receive the password entered via SSO and thus can't use that to decrypt the vault.

BlackDex avatar Nov 12 '21 08:11 BlackDex

To be clear on the whole SSO support of Bitwarden (and thus Vaultwarden if it will be implemented). It is only used to verify if a user has access, and an account can be created via SSO. A user always needs to provide an encryption password for the vault since Bitwarden doesn't receive the password entered via SSO and thus can't use that to decrypt the vault.

It's important to note why it's implemented though: Phone Apps and browser extentions

Where for normal webapplications one would "just" throw a autentication proxy in front of the application (like Authelia for example), Apps inherently do not allow an authenication proxy to sit in-front of the URL they try to connect to.

By implementing the "SSO" feature, Bitwarden allowed companies to deploy bitwarden within their existing secure login infrastructure, including the Apps on phones and browser extentions.

PrivatePuffin avatar Nov 12 '21 13:11 PrivatePuffin

I'm still interested in helping getting this merged. @Sheap did you port your patch to the newer vaultwarden versions, are you still working on this?

@BlackDex What is missing to get this merged?

pinpox avatar Nov 30 '21 12:11 pinpox

I have the same question

Akruidenberg avatar Dec 29 '21 09:12 Akruidenberg

Any progress?

Akruidenberg avatar Jan 24 '22 08:01 Akruidenberg

It looks like I'll be freed up soon to try finishing this off :partying_face:

@BlackDex can you please let me know how the patches should be defined to better sync this with the webvault?

Sheap avatar Jan 25 '22 16:01 Sheap

Progress! I've updated the webvault patch for the new version, and while I was there, I found the issues with the files failing to patch for you @pinpox.

Sheap avatar Feb 03 '22 14:02 Sheap

@Sheap for those web-vault patches you need to go to: https://github.com/dani-garcia/bw_web_builds

BlackDex avatar Feb 03 '22 14:02 BlackDex

realized I merged my the wrong remote to update the main repo - resolving now

Sheap avatar Feb 03 '22 14:02 Sheap

Properly updated now :partying_face:

@BlackDex should I just create it as a separate MR? The changes should be merged simultaneously, as they are interdependent. Which is why I didn't do this initially.

Sheap avatar Feb 03 '22 16:02 Sheap

@Sheap Thanks for the update! I'm trying to use this with the latest version of https://github.com/dani-garcia/bw_web_builds, but there seems to have been changes in the frontend.

When trying to save a OIDC configuration in the UI, the following JSON is submitted now:

{
  "enabled": false,
  "data": {
    "acrValues": "requested authentication context class",
    "additionalEmailClaimTypes": "additinaional email",
    "additionalNameClaimTypes": "additioonal name claim tyeps",
    "additionalScopes": "additonal scopes",
    "additionalUserIdClaimTypes": "additoal userid",
    "authority": "authority",
    "clientId": "clientid",
    "clientSecret": "clientsecrte",
    "configType": 1,
    "expectedReturnAcrValue": "expectde acr",
    "getClaimsFromUserInfoEndpoint": true,
    "idpAllowUnsolicitedAuthnResponse": false,
    "idpArtifactResolutionServiceUrl": null,
    "idpBindingType": 1,
    "idpDisableOutboundLogoutRequests": false,
    "idpEntityId": null,
    "idpOutboundSigningAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
    "idpSingleLogoutServiceUrl": null,
    "idpSingleSignOnServiceUrl": null,
    "idpWantAuthnRequestsSigned": false
    "idpX509PublicCert": null,
    "keyConnectorEnabled": false,
    "keyConnectorUrl": null,
    "metadataAddress": "metadata adress",
    "redirectBehavior": 1,
    "spMinIncomingSigningAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
    "spNameIdFormat": 7,
    "spOutboundSigningAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
    "spSigningBehavior": 0,
    "spValidateCertificates": false,
    "spWantAssertionsSigned": false,
  }
}

Which fails to be parsed in https://github.com/motius/vaultwarden/blob/f8e1739408f40c0c64481002aa2c6ce5de70ce8a/src/api/core/organizations.rs#L84-L93

Also the PUT request now seems to be a POST. Are you maybe using an older web-vault version?

pinpox avatar Feb 09 '22 14:02 pinpox

Odd, when I save OIDC configuration, it's sending a PUT, with the following body:

{
	"authority": "***",
	"callbackPath": "http://localhost/#/sso/",
	"clientId": "***",
	"clientSecret": "***",
	"signedOutCallbackPath": "http://localhost/#/sso/",
	"useSso": true
}

And it works fine.

My webvault is checkout out as v2.25.0, with my diffs applied. I'll look into my diffs and see if anything might be wrong there.

Sheap avatar Feb 10 '22 09:02 Sheap

My webvault is checkout out as v2.25.0, with my diffs applied.

I see, my bad, I was on 2.26.0. What commit of jslib do you have checked out to apply the patch? I get a bunch of errors on images and other binary files:

Patch errors
» git apply ../web-vault-sso.patch
error: cannot apply binary patch to 'jslib/angular/src/images/cards/amex-dark.png' without full index line
error: jslib/angular/src/images/cards/amex-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/amex-light.png' without full index line
error: jslib/angular/src/images/cards/amex-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/diners_club-dark.png' without full index line
error: jslib/angular/src/images/cards/diners_club-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/diners_club-light.png' without full index line
error: jslib/angular/src/images/cards/diners_club-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/discover-dark.png' without full index line
error: jslib/angular/src/images/cards/discover-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/discover-light.png' without full index line
error: jslib/angular/src/images/cards/discover-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/jcb-dark.png' without full index line
error: jslib/angular/src/images/cards/jcb-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/jcb-light.png' without full index line
error: jslib/angular/src/images/cards/jcb-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/maestro-dark.png' without full index line
error: jslib/angular/src/images/cards/maestro-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/maestro-light.png' without full index line
error: jslib/angular/src/images/cards/maestro-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/mastercard-dark.png' without full index line
error: jslib/angular/src/images/cards/mastercard-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/mastercard-light.png' without full index line
error: jslib/angular/src/images/cards/mastercard-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/union_pay-dark.png' without full index line
error: jslib/angular/src/images/cards/union_pay-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/union_pay-light.png' without full index line
error: jslib/angular/src/images/cards/union_pay-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/visa-dark.png' without full index line
error: jslib/angular/src/images/cards/visa-dark.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/images/cards/visa-light.png' without full index line
error: jslib/angular/src/images/cards/visa-light.png: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/scss/bwicons/fonts/bwi-font.ttf' without full index line
error: jslib/angular/src/scss/bwicons/fonts/bwi-font.ttf: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/scss/bwicons/fonts/bwi-font.woff' without full index line
error: jslib/angular/src/scss/bwicons/fonts/bwi-font.woff: patch does not apply
error: cannot apply binary patch to 'jslib/angular/src/scss/bwicons/fonts/bwi-font.woff2' without full index line
error: jslib/angular/src/scss/bwicons/fonts/bwi-font.woff2: patch does not apply

To avoid further confusion, I'm on: vaultwarden: f8e1739408f40c0c64481002aa2c6ce5de70ce8a web-vault: d10dc94a48f7786d0b7b33a53f15a208f3f2b75f jslib: c65e7db6e0bce10c77fe507c218bc51334714c94

pinpox avatar Feb 10 '22 11:02 pinpox

There were some issues with my set up too. There's a lot I'd forgotten between when I was last working on it and coming back. I'm resolving it now, but unfortunately it looks like it's not a trivial fix

Sheap avatar Feb 10 '22 13:02 Sheap

There were some issues with my set up too. There's a lot I'd forgotten between when I was last working on it and coming back. I'm resolving it now, but unfortunately it looks like it's not a trivial fix

@Sheap Just so we don't spam this issue further, are you in the vaultwarden matrix channel or is there any other place to contact you more directly? I'm working on this issue aswell and can help out, test or contribute. Let me know if I can assist you, I'm in the matrix channel under the same nickname.

pinpox avatar Feb 10 '22 14:02 pinpox

I'm running into a panic, when I click the "Login with SSO" button. I'm not sure if my SSO provider settings are correct, but in either case probably a panic is wrong?

@Sheap what OIDC provider and settings are you using to test the login?

[2022-02-14 13:17:27.756][request][INFO] GET /identity/account/prevalidate?domainHint=test-org
[2022-02-14 13:17:29.109][panic][ERROR] thread 'unnamed' panicked at 'called `Option::unwrap()` on a `None` value': src/api/identity.rs:635
   0: vaultwarden::init_logging::{{closure}}
             at src/main.rs:196:25
   1: std::panicking::rust_panic_with_hook
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panicking.rs:695:17
   2: std::panicking::begin_panic_handler::{{closure}}
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panicking.rs:579:13
   3: std::sys_common::backtrace::__rust_end_short_backtrace
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/sys_common/backtrace.rs:139:18
   4: rust_begin_unwind
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panicking.rs:577:5
   5: core::panicking::panic_fmt
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/panicking.rs:135:14
   6: core::panicking::panic
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/panicking.rs:48:5
   7: core::option::Option<T>::unwrap
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/option.rs:752:21
   8: vaultwarden::api::identity::prevalidate
             at src/api/identity.rs:635:24
   9: vaultwarden::api::identity::rocket_route_fn_prevalidate
             at src/api/identity.rs:633:4
  10: core::ops::function::Fn::call
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/ops/function.rs:70:5
  11: <F as rocket::handler::Handler>::handle
             at /home/pinpox/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/263e39b/core/lib/src/handler.rs:177:9
  12: rocket::rocket::Rocket::route
             at /home/pinpox/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/263e39b/core/lib/src/rocket.rs:297:27
  13: rocket::rocket::Rocket::route_and_process
             at /home/pinpox/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/263e39b/core/lib/src/rocket.rs:243:34
  14: rocket::rocket::Rocket::dispatch
             at /home/pinpox/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/263e39b/core/lib/src/rocket.rs:218:28
  15: <rocket::rocket::Rocket as hyper::server::Handler>::handle
             at /home/pinpox/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/263e39b/core/lib/src/rocket.rs:83:24
  16: hyper::server::Worker<H>::keep_alive_loop
             at /home/pinpox/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:340:13
  17: hyper::server::Worker<H>::handle_connection
             at /home/pinpox/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:282:15
  18: hyper::server::handle::{{closure}}
             at /home/pinpox/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:242:34
  19: hyper::server::listener::spawn_with::{{closure}}
             at /home/pinpox/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/listener.rs:50:31
  20: std::sys_common::backtrace::__rust_begin_short_backtrace
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/sys_common/backtrace.rs:123:18
  21: std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/thread/mod.rs:477:17
  22: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/panic/unwind_safe.rs:271:9
  23: std::panicking::try::do_call
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panicking.rs:485:40
  24: __rust_try
  25: std::panicking::try
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panicking.rs:449:19
  26: std::panic::catch_unwind
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/panic.rs:136:14
  27: std::thread::Builder::spawn_unchecked::{{closure}}
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/thread/mod.rs:476:30
  28: core::ops::function::FnOnce::call_once{{vtable.shim}}
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/core/src/ops/function.rs:227:5
  29: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/alloc/src/boxed.rs:1854:9
      <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/alloc/src/boxed.rs:1854:9
      std::sys::unix::thread::Thread::new::thread_start
             at /rustc/bfe15646761a75f0259e204cab071565eed2b1e5/library/std/src/sys/unix/thread.rs:108:17
  30: start_thread
  31: clone

pinpox avatar Feb 14 '22 12:02 pinpox

I'm running into a panic, when I click the "Login with SSO" button. I'm not sure if my SSO provider settings are correct, but in either case probably a panic is wrong?

It looks like the organisation identifier (test-org) does not match any existing organisation. You can set it the identifier of an organisation in the organisation's settings page. Agreed that it shouldn't panic when no suitable organisation is found.

bendem avatar Feb 21 '22 12:02 bendem

I'll look into the panic. Regarding my settings, I'm using a keycloak server within my company network, so it's not really something I can share publicly :smile:

Sheap avatar Feb 23 '22 15:02 Sheap

Can confirm the panic is fixed. I have not been able to configure keycloak correctly yet, currently seing this error when trying to login, even though I created a client in keycloak:

{"ErrorModel":{"Message":"Unable to find client from identifier","Object":"error"},"ExceptionMessage":null,"ExceptionStackTrace":null,"InnerExceptionMessage":null,"Message":"Unable to find client from identifier","Object":"error","ValidationErrors":{"":["Unable to find client from identifier"]},"error":"","error_description":""}

pinpox avatar Feb 28 '22 14:02 pinpox

I'd like to try this, but I'm getting error: corrupt patch at line 511 when trying to apply web-vault-sso.patch. What am I doing wrong?

dorianim avatar Mar 02 '22 22:03 dorianim

Any update on this?

Cookie-Monster-Coder avatar Apr 08 '22 21:04 Cookie-Monster-Coder

The json format returned from the web-vault when configuring SSO for an organisation seems to have changed. The OrganizationSsoUpdateData struct now looks like this:

#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
struct OrganizationSsoUpdateData {
    Enabled: Option<bool>,
    Data: Option<SsoOrganizationData>,
}

With the actual values one level more nested in Data. This struct works for me for:

#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
struct SsoOrganizationData {
    AcrValues: Option<String>,
    AdditionalEmailClaimTypes: Option<String>,
    AdditionalNameClaimTypes: Option<String>,
    AdditionalScopes: Option<String>,
    AdditionalUserIdClaimTypes: Option<String>,
    Authority: Option<String>,
    ClientId: Option<String>,
    ClientSecret: Option<String>,
    ConfigType: Option<String>,
    ExpectedReturnAcrValue: Option<String>,
    GetClaimsFromUserInfoEndpoint: Option<bool>,
    IdpAllowUnsolicitedAuthnResponse: Option<bool>,
    IdpArtifactResolutionServiceUrl: Option<String>,
    IdpBindingType: Option<u8>,
    IdpDisableOutboundLogoutRequests: Option<bool>,
    IdpEntityId: Option<String>,
    IdpOutboundSigningAlgorithm: Option<String>,
    IdpSingleLogoutServiceUrl: Option<String>,
    IdpSingleSignOnServiceUrl: Option<String>,
    IdpWantAuthnRequestsSigned: Option<bool>,
    IdpX509PublicCert: Option<String>,
    KeyConnectorUrlY: Option<String>,
    KeyConnectorEnabled: Option<bool>,
    MetadataAddress: Option<String>,
    RedirectBehavior: Option<String>,
    SpMinIncomingSigningAlgorithm: Option<String>,
    SpNameIdFormat: Option<u8>,
    SpOutboundSigningAlgorithm: Option<String>,
    SpSigningBehavior: Option<u8>,
    SpValidateCertificates: Option<bool>,
    SpWantAssertionsSigned: Option<bool>,
}

Lastly the put_organization_sso method/route now uses post. I'm still debugging that method here: https://github.com/pinpox/vaultwarden/blob/44e4c845ce0fb8ed259ac2f218772714df21fa39/src/api/core/organizations.rs#L336

pinpox avatar Apr 11 '22 07:04 pinpox

Lastly the put_organization_sso method/route now uses post. I'm still debugging that method here: https://github.com/pinpox/vaultwarden/blob/44e4c845ce0fb8ed259ac2f218772714df21fa39/src/api/core/organizations.rs#L336

Be sure to double check this with a totally new SSO, since PUT's are used for new items, and POST's for updates if remember correctly.

BlackDex avatar Apr 11 '22 07:04 BlackDex

The issue I'm currently running into: After configuring SSO for an organization I created, I can see it is saved correctly now in the database. When trying to login however I click the "Enterprise SSO Login" button, then enter the configured identifier, then "Login" I see this error message:

{"ErrorModel":{"Message":"Unable to find client from identifier","Object":"error"},"ExceptionMessage":null,"ExceptionStackTrace":null,"InnerExceptionMessage":null,"Message":"Unable to find client from identifier","Object":"error","ValidationErrors":{"":["Unable to find client from identifier"]},"error":"","error_description":""}

I havn't been able to find out where this comes from

pinpox avatar Apr 11 '22 13:04 pinpox

Be sure to double check this with a totally new SSO, since PUT's are used for new items, and POST's for updates if remember correctly.

Is this the upstream behaviour? PUT is usually an inplace update and POST is creating a new object as per the HTTP Verb specs. If bitwarden does it differently we should of course follow their (maybe flawed) lead.

Blackclaws avatar Apr 21 '22 09:04 Blackclaws

Be sure to double check this with a totally new SSO, since PUT's are used for new items, and POST's for updates if remember correctly.

Is this the upstream behaviour? PUT is usually an inplace update and POST is creating a new object as per the HTTP Verb specs. If bitwarden does it differently we should of course follow their (maybe flawed) lead.

Sorry, i had them mixed up. POST is indeed new items, and PUT for updates.

BlackDex avatar Apr 21 '22 09:04 BlackDex

I've got a version with the login process working now. I get redirected correctly to the authentication page of the authentication provider) and can login. However, I've not been able to find out what values are needed for callback_path and signed_out_callback_path to get OIDC to work. Offcial bitwarden has these defaults:

           callback_path = https://sso.bitwarden.com/oidc-signin
signed_out_callback_path = https://sso.bitwarden.com/oidc-signedout

What do I have to set for the Callback Path and Callback Signed Out Path in vaultwarden? I have not been able to find the endpoint browsing through the diff of this PR. Can anyone help?

pinpox avatar Apr 25 '22 14:04 pinpox

I think, those fields should be read only. In a vanilla bitwarden they are https://bitwarden.example.com/sso/oidc-signin for callback and https://bitwarden.example.com/sso/oidc-signedout for Signed Out Callback. As far as I understand it, they are used as redirect targets by the identity provider.

dorianim avatar Apr 25 '22 15:04 dorianim

As far as I understand it, they are used as redirect targets by the identity provider.

That's true, but they have to be set to something, otherwise the login process fails as far as I could find out.

I've been continuing to work on this PR. Not sure if @Sheap is still planning on working on it, should I open a second on (maybe as draft?) to track progress? I've rebased against the current master so that it builds with the updated web vault, but still am running into a few bugs and some feedback would be great to help me get it in a mergable state. @BlackDex let me know what way you prefer.

pinpox avatar May 02 '22 09:05 pinpox

If the comments above are addressed i don't mind how this will be getting to a mergeable PR. I would though be sure to give credit to all the correct people by using the following: https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors#creating-co-authored-commits-on-the-command-line

BlackDex avatar May 02 '22 09:05 BlackDex

@pinpox looking over my code, I believe those fields should be {root}/#/sso. Although both being the same seems odd, I don't remember my reasoning. That worked at least enough for my testing locally. Thanks for making a new MR - I unfortunately don't have the time to get this ready for merge. I'll continue checking on the progress and trying to offer any help I can.

Sheap avatar May 10 '22 07:05 Sheap

I'm running into a problem here: The code seems to work fine now, I can login and get redirected to the URL I specify. However {root}/#/sso is not a valid URL for ADFS.

image

Where is that defined and can it be changed to something else that does not include # or ? ?

pinpox avatar May 23 '22 13:05 pinpox

@pinpox The path is defined in webvault src/app/oss-routing.module.ts. But I don't think that will help with the #. I believe that's down to the configuration of the angular router. The only other option would be a query, but it doesn't look like that would help.

If ADFS don't allow fragments or queries, then the only option I can think of would be to set up a subdomain. But I don't know how to do that in this context.

Sheap avatar Jun 01 '22 11:06 Sheap

@Sheap @pinpox @BlackDex @dani-garcia There are two open PRs regarding (pseudo) SSO in vaultwarden (#1955 and #2449). Both seem to be stuck in the review stage for many weeks. I know how hard it is to find time for these projects – totally understandable.

If we (the user community) got together and collected some money to be split among all of you, would that speed up to process? Probably won't be much, but still more than nothing, and might be enough to buy a nice dinner for everyone. Are you open to the idea of such a bounty model? I'd also appreciate any reactions by the community, to show you'd be willing to donate some money to this cause (just to get an idea about how many people are willing to pay some money for this feature).

pReya avatar Jul 26 '22 14:07 pReya

@pReya I am still actively working on my PR, but progress is a bit slow. I currently have the time to work on it and money is not the show stopper, what I would need to speed this up would be some technical assistance in questions specific to this project and to rust. I'm currently in the process of applying all the fixes from the review that was made on my PR, but it took so long that I have since changed quite a few things and have to adapt a lot.

I'll try the matrix channel later with a few questions I still have to get this finished. Would be nice to speed up the feedback loop.

pinpox avatar Jul 27 '22 10:07 pinpox

@Sheap did this work for you? https://github.com/dani-garcia/vaultwarden/pull/2449/files#diff-1c5b0c87dec2154a167b89110c637a7a4bc04f59af0b83e8ddba39eb2134518cR126 It is panicing for me, because the token is missing an email field. Has that changed, was it there before? If so, how do I find the user now?

I added a print statement to see the token, it is:

eyJhbGciOiJSUzI1NiIsImtpZCI6IkxVOUJFbkNlc3dUd3FVWGJBNGx2THQ1Z3hIcW4xdzVlakFPUmFFRnR5bzgiLCJ0eXAiOiJKV1QifQ.eyJnbnQiOjEsInR0IjowLCJleHAiOjE2NTg5MjM3NjIsImlhdCI6MTY1ODkyMDE2Mn0.eHLHopIUslDKBj4Fk5ubfRUYGYbikD1yHw-f_H41R8KQGEPEjIbnlZ1UyxT9f2_LivJE7PVxZ0jNSZe2jWEYkRcZyGdlUWJd_ElxaRJVZ-qqmjZ3pfQJHzOXHXvGI6D9z7A9najpxYtno9pNG5rY4K-iDfxEUAql36eLFlJJuzvCx5UXwwfCw-isKOE63qykZVix67kffu9QzQVX0Ms1wetCocNoik9rzR2g3KCmflqZHA9xtXLB0kgrOTd70VPsGwUJwgfm7AncGBDwkjcuiZMRzjh8rnBbr5-lsz5vj6Sgl7MDhhzNnlS-w-oN_Mq4VIB1VWBtf50Qvmu3-d3x2X-wOrrV8MM8VNWjDXQFvMKp8xpn3Qdz6EtrVdKwNDYM29Z0LAhCpT8OJP_5kvsJYATeO1gox5gn_y2lbdW1Ty4zVg8yQ_ZY-mY98dmejMC1svRy6jKeEsWlaBM4vZYiu5gXTWA5P6ccLMmQqxmT_r_uvD0LNAu7ZIZF4yZ-X3TAPy8Y4qt_uFAE3E4E1mVmkcFgb6eVHFBYx9L8I2fxdEc9BY1PiNMU4ml1wIw_66_dOtidQkH0ohz1YDt3xVIS8zbaTRU9pLeAO1Yl5hIPXYG2CzyQfvZd6GyHYt_DHHy9zjKHQ1Q9rQPkwy2ZwX8f3svNYejO-bQTbrsacOkaw6

Which according to jwt.io decodes to the payload:

{
  "gnt": 1,
  "tt": 0,
  "exp": 1658923762,
  "iat": 1658920162
}

pinpox avatar Jul 27 '22 11:07 pinpox

@pinpox I think that the email is a mandatory field inside an OAuth token. Which identity provider are you using? I think you should add the email claim to it.

gianlucapisati avatar Jul 28 '22 13:07 gianlucapisati

I think that the email is a mandatory field inside an OAuth token. Which identity provider are

This is not right. Required claims are listed here https://openid.net/specs/openid-connect-core-1_0.html#IDToken but this is something I noticed multiple times, that email is used instead of sub by certain clients.

Lurkars avatar Jul 28 '22 14:07 Lurkars

Ok @Lurkars you are right about the theory, but neither sub or email are present in that token (which by the way is an access_token, not an id_token), my question is still valid, which system generated that token?

gianlucapisati avatar Jul 28 '22 15:07 gianlucapisati

I think Gitea's Oauth2 provider implementation is only meant to allow third party apps to access Gitea's API. It's doesn't look like it's really meant to authenticate users on a external service.

Kab1r avatar Jul 28 '22 17:07 Kab1r

Ok @Lurkars you are right about the theory, but neither sub or email are present in that token (which by the way is an access_token, not an id_token), my question is still valid, which system generated that token?

The format of an access_token is not defined, it can also be a random string and not containing any encoded data. So don't rely any requirements on getting information from an access_token. It seems like Gitea generates access_tokens as JWTs, I don't know why, but this is not OAuth2 standard and cannot be assumed for other providers.

Claims like email, sub inside an ID Token are the additions OpenID Connect added to the OAuth2 spec. That's why we are asking for OpenID support and not only OAuth2.

The Gitea documentation is a bit confusing (https://docs.gitea.io/en-us/oauth2-provider/) because, they claim to support OpenID Connect, but sample token response does not contain an ID Token. I will now try to test if Gitea can be used as valid OpenID Connect provider.

Anyways, I am 0% into Rust, so cannot contribute directly here. But I am very deep into OpenID Connect protocol. So if you need any help here, ping me!

Edit: I just tested with a gitea instance. So it returns a valid ID token, so seems fine to me.

Lurkars avatar Jul 29 '22 07:07 Lurkars

A quick look at the code, I found this

let token = jsonwebtoken::dangerous_insecure_decode::<TokenPayload>(access_token.as_str()).unwrap().claims;

So it seems to try to read the access_token as ID token. Please use id_token instead. Every OpenID Provider will return id_token next to access_token in Token Response!

Taking a quick look at library example:

https://github.com/ramosbugs/openidconnect-rs/blob/main/examples/google.rs#L215

seems like you can get claims directly from this and don't need to decode JWT yourself! So I would recommend to simple use the library to get email and sub etc.

Lurkars avatar Jul 29 '22 08:07 Lurkars

I think Gitea's Oauth2 provider implementation is only meant to allow third party apps to access Gitea's API. It's doesn't look like it's really meant to authenticate users on a external service.

@Kab1r This can't be correct. I have an account on bitwarden.com and have tested the configuration there. Gitea works perfectly with an official bitwarden account.

Edit: I just tested with a gitea instance. So it returns a valid ID token, so seems fine to me.

Can confirm.

@Lurkars

So it seems to try to read the access_token as ID token. Please use id_token instead. Every OpenID Provider will return id_token next to access_token in Token Response!

Perfect, thanks that was what I was looking for! Indeed using the id_token works, it contains the email field as expected (among other which are not used atm) I have adapted the code to use it in https://github.com/dani-garcia/vaultwarden/pull/2449/commits/13c169cd64753999b1a624277fd94e6f3c7226aa This could probably be simplified as @Lurkars pointed out, but should work for now.

Logging it seems to work now via OIDC, but I still don't know what the callback path is supposed to be. Currently it just redirect to the login screen again after login. /#/sso seems to be incorrect, not sure how that worked for @Sheap

If anyone (with more front-end) knowledge) can find out what the callback path is supposed to be, that would be of great help!

pinpox avatar Aug 01 '22 09:08 pinpox

Wow, that's a wonderful development! :star_struck: Will this also work with Authelia?

alexanderadam avatar Aug 01 '22 10:08 alexanderadam

Will this also work with Authelia?

I haven't used authelia personally, but their website says it supports OpenID connect in the beta version currently. If it can operate as OIDC provider, it should work.

pinpox avatar Aug 01 '22 12:08 pinpox