Page MenuHomePhorge

D4854.id13902.diff
No OneTemporary

D4854.id13902.diff

diff --git a/bin/podman_shared b/bin/podman_shared
--- a/bin/podman_shared
+++ b/bin/podman_shared
@@ -269,9 +269,12 @@
podman__run_synapse() {
$PODMAN run -dt --pod $POD --name $POD-synapse --replace \
- $SYNAPSE_STORAGE \
+ $SYNAPSE_STORAGE \
+ -v $CERTS_PATH:/etc/certs:ro \
-e APP_DOMAIN \
-e KOLAB_URL="http://127.0.0.1:8000" \
+ -e SYNAPSE_OAUTH_CLIENT_ID="${PASSPORT_SYNAPSE_OAUTH_CLIENT_ID:?"missing env variable"}" \
+ -e SYNAPSE_OAUTH_CLIENT_SECRET="${PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET:?"missing env variable"}" \
synapse:latest
}
diff --git a/ci/env b/ci/env
--- a/ci/env
+++ b/ci/env
@@ -151,6 +151,8 @@
MEET_SERVER_TOKEN=simple123
PASSPORT_PROXY_OAUTH_CLIENT_ID=5909ca4f-df7e-45fe-b355-e7c195aef117
PASSPORT_PROXY_OAUTH_CLIENT_SECRET=3URb+3JGJM9wPuDnlUSTPOw2mqmHsoOV8NXanx9xwQM=
+PASSPORT_SYNAPSE_OAUTH_CLIENT_ID=2909ca4f-df7e-45fe-b355-e7c195aef112
+PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET=2URb+3JGJM9wPuDnlUSTPOw2mqmHsoOV8NXanx9xwQM=
DES_KEY=kBxUM/53N9p9abusAoT0ZEAxwI2pxFz/
KOLAB_GIT_REF=master
diff --git a/ci/testctl b/ci/testctl
--- a/ci/testctl
+++ b/ci/testctl
@@ -112,7 +112,8 @@
export MARIADB_STORAGE=--mount=type=tmpfs,tmpfs-size=512M,destination=/var/lib/mysql,U=true
export REDIS_STORAGE=--mount=type=tmpfs,tmpfs-size=128M,destination=/var/lib/redis,U=true
export MINIO_STORAGE=--mount=type=tmpfs,tmpfs-size=128M,destination=/data,U=true
-
+export PASSPORT_SYNAPSE_OAUTH_CLIENT_ID=2909ca4f-df7e-45fe-b355-e7c195aef112
+export PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET=2URb+3JGJM9wPuDnlUSTPOw2mqmHsoOV8NXanx9xwQM=
export PODMAN_IGNORE_CGROUPSV1_WARNING=true
diff --git a/config.demo/src/database/seeds/PassportSeeder.php b/config.demo/src/database/seeds/PassportSeeder.php
--- a/config.demo/src/database/seeds/PassportSeeder.php
+++ b/config.demo/src/database/seeds/PassportSeeder.php
@@ -30,5 +30,20 @@
]);
$client->id = \config('auth.proxy.client_id');
$client->save();
+
+ //Create a client for synapse oauth
+ #FIXME not sure about the provider
+ $client = Passport::client()->forceFill([
+ 'user_id' => null,
+ 'name' => "Synapse oauth client",
+ 'secret' => \config('auth.synapse.client_secret'),
+ 'provider' => 'users',
+ 'redirect' => 'https://' . \config('app.website_domain') . "/_synapse/client/oidc/callback",
+ 'personal_access_client' => 0,
+ 'password_client' => 0,
+ 'revoked' => false,
+ ]);
+ $client->id = \config('auth.synapse.client_id');
+ $client->save();
}
}
diff --git a/config.prod/src/database/seeds/PassportSeeder.php b/config.prod/src/database/seeds/PassportSeeder.php
--- a/config.prod/src/database/seeds/PassportSeeder.php
+++ b/config.prod/src/database/seeds/PassportSeeder.php
@@ -30,5 +30,19 @@
]);
$client->id = \config('auth.proxy.client_id');
$client->save();
+
+ //Create a client for synapse oauth
+ $client = Passport::client()->forceFill([
+ 'user_id' => null,
+ 'name' => "Synapse oauth client",
+ 'secret' => \config('auth.synapse.client_secret'),
+ 'provider' => 'users',
+ 'redirect' => 'https://' . \config('app.website_domain') . "/_synapse/client/oidc/callback",
+ 'personal_access_client' => 0,
+ 'password_client' => 0,
+ 'revoked' => false,
+ ]);
+ $client->id = \config('auth.synapse.client_id');
+ $client->save();
}
}
diff --git a/docker/synapse/Dockerfile b/docker/synapse/Dockerfile
--- a/docker/synapse/Dockerfile
+++ b/docker/synapse/Dockerfile
@@ -20,14 +20,14 @@
openssl-devel \
sed \
wget && \
- pip3 install matrix-synapse && \
+ pip3 install matrix-synapse authlib && \
dnf clean all
COPY /rootfs /
RUN id default || (groupadd -g 1001 default && useradd -d /opt/app-root/ -u 1001 -g 1001 default)
-RUN PATHS=(/opt/app-root/src) && \
+RUN PATHS=(/opt/app-root/src /etc/pki/ca-trust/extracted/ /etc/pki/ca-trust/source/anchors/) && \
mkdir -p ${PATHS[@]} && \
chmod -R 777 ${PATHS[@]} && \
chown -R 1001:0 ${PATHS[@]} && \
diff --git a/docker/synapse/rootfs/opt/app-root/src/homeserver.yaml b/docker/synapse/rootfs/opt/app-root/src/homeserver.yaml
--- a/docker/synapse/rootfs/opt/app-root/src/homeserver.yaml
+++ b/docker/synapse/rootfs/opt/app-root/src/homeserver.yaml
@@ -109,22 +109,25 @@
federation_domain_whitelist:
- APP_DOMAIN
-# oidc_providers:
-# - idp_id: kolab
-# idp_name: "Kolab"
-# issuer: "https://127.0.0.1:8443/auth/realms/{realm_name}"
-# client_id: "synapse"
-# client_secret: "copy secret generated from above"
-# scopes: ["openid", "profile"]
-# user_mapping_provider:
-# config:
-# localpart_template: "\{\{ user.preferred_username }}"
-# display_name_template: "\{\{ user.name }}"
+oidc_providers:
+ - idp_id: kolab
+ idp_name: "Kolab"
+ discover: false
+ issuer: "https://APP_DOMAIN"
+ authorization_endpoint: "https://APP_DOMAIN/authorize"
+ #These connections go over localhost, but must still be https (otherwise it doesn't work). Also the certificate must match, so we can't use 127.0.0.1.
+ token_endpoint: "https://APP_DOMAIN:6443/oauth/token"
+ userinfo_endpoint: "https://APP_DOMAIN:6443/api/auth/info"
+ client_id: "SYNAPSE_OAUTH_CLIENT_ID"
+ client_secret: "SYNAPSE_OAUTH_CLIENT_SECRET"
+ client_auth_method: client_secret_post
+ scopes: []
+ user_mapping_provider:
+ config:
+ subject_claim: "id"
+ email_template: "{{ user.email }}"
+ display_name_template: "{{ user.settings.first_name }}"
-modules:
-- module: kolab_auth_provider.KolabAuthProvider
- config:
- kolab_url: "KOLAB_URL"
## API Configuration ##
diff --git a/docker/synapse/rootfs/opt/app-root/src/init.sh b/docker/synapse/rootfs/opt/app-root/src/init.sh
--- a/docker/synapse/rootfs/opt/app-root/src/init.sh
+++ b/docker/synapse/rootfs/opt/app-root/src/init.sh
@@ -1,11 +1,18 @@
#!/bin/bash
set -e
+if [[ -f /etc/certs/ca.cert ]]; then
+ cp /etc/certs/ca.cert /etc/pki/ca-trust/source/anchors/
+ update-ca-trust
+fi
+
sed -i -r \
-e "s|APP_DOMAIN|$APP_DOMAIN|g" \
-e "s|KOLAB_URL|$KOLAB_URL|g" \
-e "s|TURN_SHARED_SECRET|$TURN_SHARED_SECRET|g" \
-e "s|TURN_URIS|$TURN_URIS|g" \
+ -e "s|SYNAPSE_OAUTH_CLIENT_ID|$SYNAPSE_OAUTH_CLIENT_ID|g" \
+ -e "s|SYNAPSE_OAUTH_CLIENT_SECRET|$SYNAPSE_OAUTH_CLIENT_SECRET|g" \
/opt/app-root/src/homeserver.yaml
exec synctl --no-daemonize start ${CONFIGFILE:-/opt/app-root/src/homeserver.yaml}
diff --git a/kolabctl b/kolabctl
--- a/kolabctl
+++ b/kolabctl
@@ -110,6 +110,16 @@
echo "PASSPORT_PROXY_OAUTH_CLIENT_SECRET=${PASSPORT_PROXY_OAUTH_CLIENT_SECRET}" >> src/.env
fi
+ if ! grep -q "PASSPORT_SYNAPSE_OAUTH_CLIENT_ID=" src/.env; then
+ PASSPORT_SYNAPSE_OAUTH_CLIENT_ID=$(uuidgen);
+ echo "PASSPORT_SYNAPSE_OAUTH_CLIENT_ID=${PASSPORT_SYNAPSE_OAUTH_CLIENT_ID}" >> src/.env
+ fi
+
+ if ! grep -q "PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET=" src/.env; then
+ PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET=$(openssl rand -base64 32);
+ echo "PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET=${PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET}" >> src/.env
+ fi
+
if ! grep -q "PASSPORT_PUBLIC_KEY=|PASSPORT_PRIVATE_KEY=" src/.env; then
PASSPORT_PRIVATE_KEY=$(openssl genrsa 4096);
echo "PASSPORT_PRIVATE_KEY=\"${PASSPORT_PRIVATE_KEY}\"" >> src/.env
diff --git a/src/app/Http/Controllers/API/AuthController.php b/src/app/Http/Controllers/API/AuthController.php
--- a/src/app/Http/Controllers/API/AuthController.php
+++ b/src/app/Http/Controllers/API/AuthController.php
@@ -9,6 +9,9 @@
use Illuminate\Support\Facades\Validator;
use Laravel\Passport\TokenRepository;
use Laravel\Passport\RefreshTokenRepository;
+use League\OAuth2\Server\AuthorizationServer;
+use Psr\Http\Message\ServerRequestInterface;
+use Nyholm\Psr7\Response as Psr7Response;
class AuthController extends Controller
{
@@ -87,6 +90,49 @@
return self::logonResponse($user, $request->password, $request->secondfactor);
}
+ /**
+ * Approval request for the oauth authorization endpoint
+ *
+ *
+ * * The user is authenticated via the regular login page
+ * * We assume implicit consent in the Authorization page
+ * * Ultimately we return an authorization code to the caller via the redirect_uri
+ *
+ * The implementation is based on Laravel\Passport\Http\Controllers\AuthorizationController
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ *
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function oauthApprove(
+ ServerRequestInterface $psrRequest,
+ Request $request,
+ AuthorizationServer $server
+ ) {
+ if ($request->response_type != "code") {
+ return response()->json(['status' => 'error', 'errors' => ["invalid response_type"]], 422);
+ }
+
+ $user = Auth::guard()->user();
+ if (!$user) {
+ \Log::warning("User not found");
+ return response()->json(['status' => 'error', 'message' => self::trans('auth.failed')], 401);
+ }
+
+ try {
+ $authRequest = $server->validateAuthorizationRequest($psrRequest);
+ } catch (\Exception $e) {
+ return response()->json(['status' => 'error', 'message' => "Failed to validate"], 401);
+ }
+
+ //TODO I'm not sure if we should still execute this to deny the request
+ $authRequest->setUser(new \Laravel\Passport\Bridge\User($user->getAuthIdentifier()));
+ $authRequest->setAuthorizationApproved(true);
+
+ # This will generate a 302 redirect to the redirect_uri with the generated authorization code
+ return $server->completeAuthorizationRequest($authRequest, new Psr7Response());
+ }
+
/**
* Get the user (geo) location
*
diff --git a/src/app/Providers/AppServiceProvider.php b/src/app/Providers/AppServiceProvider.php
--- a/src/app/Providers/AppServiceProvider.php
+++ b/src/app/Providers/AppServiceProvider.php
@@ -16,8 +16,6 @@
*/
public function register(): void
{
- Passport::enablePasswordGrant();
- Passport::ignoreRoutes();
}
/**
diff --git a/src/app/Providers/PassportServiceProvider.php b/src/app/Providers/PassportServiceProvider.php
--- a/src/app/Providers/PassportServiceProvider.php
+++ b/src/app/Providers/PassportServiceProvider.php
@@ -17,6 +17,9 @@
*/
public function boot()
{
+ Passport::enablePasswordGrant();
+ Passport::ignoreRoutes();
+
Passport::tokensCan([
'api' => 'Access API',
'mfa' => 'Access MFA API',
diff --git a/src/config/auth.php b/src/config/auth.php
--- a/src/config/auth.php
+++ b/src/config/auth.php
@@ -135,6 +135,11 @@
'client_secret' => env('PASSPORT_PROXY_OAUTH_CLIENT_SECRET'),
],
+ 'synapse' => [
+ 'client_id' => env('PASSPORT_SYNAPSE_OAUTH_CLIENT_ID'),
+ 'client_secret' => env('PASSPORT_SYNAPSE_OAUTH_CLIENT_SECRET'),
+ ],
+
'token_expiry_minutes' => env('OAUTH_TOKEN_EXPIRY', 60),
'refresh_token_expiry_minutes' => env('OAUTH_REFRESH_TOKEN_EXPIRY', 30 * 24 * 60),
];
diff --git a/src/resources/js/user/routes.js b/src/resources/js/user/routes.js
--- a/src/resources/js/user/routes.js
+++ b/src/resources/js/user/routes.js
@@ -1,4 +1,5 @@
import LoginComponent from '../../vue/Login'
+import AuthorizeComponent from '../../vue/Authorize'
import LogoutComponent from '../../vue/Logout'
import PageComponent from '../../vue/Page'
import PasswordResetComponent from '../../vue/PasswordReset'
@@ -85,6 +86,12 @@
component: FileListComponent,
meta: { requiresAuth: true, perm: 'files' }
},
+ {
+ path: '/authorize',
+ name: 'authorize',
+ component: AuthorizeComponent,
+ meta: { requiresAuth: true }
+ },
{
path: '/login',
name: 'login',
diff --git a/src/resources/vue/Authorize.vue b/src/resources/vue/Authorize.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Authorize.vue
@@ -0,0 +1,60 @@
+<template>
+ <div class="container d-flex flex-column align-items-center justify-content-center">
+ <div id="logon-form" class="card col-sm-8 col-lg-6">
+ <div class="card-body p-4">
+ <!--h1 class="card-title text-center mb-3">{{ $t('login.header') }}</h1-->
+ <h1 class="card-title text-center mb-3">Authorizing...</h1>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+ import { library } from '@fortawesome/fontawesome-svg-core'
+
+ library.add(
+ require('@fortawesome/free-solid-svg-icons/faRightToBracket').definition,
+ )
+
+ export default {
+ props: {
+ dashboard: { type: Boolean, default: true }
+ },
+ data() {
+ return {
+ loading: false
+ }
+ },
+ created() {
+ // Just auto approve for now
+ // If we wanted we could use this page to list what is being authorized,
+ // and allow the user to approve/reject.
+ this.submitApproval()
+ },
+ methods: {
+ submitApproval() {
+ var post = {};
+
+ post.client_id = this.$route.query.client_id;
+ post.redirect_uri = this.$route.query.redirect_uri;
+ post.state = this.$route.query.state;
+ post.nonce = this.$route.query.nonce;
+ post.response_type = this.$route.query.response_type;
+
+ this.loading = true
+
+ axios.post('/api/auth/approve', post, { params: post })
+ .then(response => {
+ // Follow the redirect to the external page
+ this.$emit('success')
+ window.location.href = response.request.responseURL;
+ })
+ .catch(() => {})
+ .finally(() => {
+ this.loading = false
+ })
+ }
+ }
+ }
+</script>
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -26,6 +26,7 @@
Route::group(
['middleware' => 'auth:api'],
function () {
+ Route::post('approve', [API\AuthController::class, 'oauthApprove']);
Route::get('info', [API\AuthController::class, 'info']);
Route::post('info', [API\AuthController::class, 'info']);
Route::get('location', [API\AuthController::class, 'location']);

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 20, 2:56 AM (8 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9465885
Default Alt Text
D4854.id13902.diff (14 KB)

Event Timeline