Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F15398799
D4854.id13902.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D4854.id13902.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D4854: First attempt to get oauth going
Attached
Detach File
Event Timeline
Log In to Comment