Skip to content

Commit

Permalink
Merge pull request #3 from globekeeper/daniel/dev-1058-bridges-as
Browse files Browse the repository at this point in the history
Bridge Authentication for External Auth Providers.
  • Loading branch information
Danieloni1 authored Jan 11, 2024
2 parents bff5dfb + 7557dd2 commit c3faa07
Show file tree
Hide file tree
Showing 18 changed files with 872 additions and 26 deletions.
12 changes: 12 additions & 0 deletions .cloudbuild/dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
steps:
- name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/bridgeas:$COMMIT_SHA', '-f', 'Dockerfile', '.']
- name: gcr.io/cloud-builders/kubectl
args: ['-n', 'dendrite', 'set', 'image', 'deployment/bridgeas', 'bridgeas=gcr.io/$PROJECT_ID/bridgeas:$COMMIT_SHA']
env:
- CLOUDSDK_CORE_PROJECT=globekeeper-development
- CLOUDSDK_COMPUTE_ZONE=europe-west2-a
- CLOUDSDK_CONTAINER_CLUSTER=synapse
images:
- gcr.io/$PROJECT_ID/bridgeas:$COMMIT_SHA
timeout: 600s
12 changes: 12 additions & 0 deletions .cloudbuild/prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
steps:
- name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/bridgeas:$TAG_NAME', '-f', 'Dockerfile', '.']
- name: gcr.io/cloud-builders/kubectl
args: ['set', 'image', 'deployment/bridgeas', 'bridgeas=gcr.io/$PROJECT_ID/bridgeas:$TAG_NAME']
env:
- CLOUDSDK_CORE_PROJECT=globekeeper-production
- CLOUDSDK_COMPUTE_ZONE=europe-west2-a
- CLOUDSDK_CONTAINER_CLUSTER=synapse-production
images:
- gcr.io/$PROJECT_ID/bridgeas:$TAG_NAME
timeout: 480s
20 changes: 0 additions & 20 deletions .github/workflows/newsfile.yml

This file was deleted.

37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,43 @@ mdbook build
sensible-browser book/index.html
```

### GlobeKeeper Related Docs

[Notion PRD](https://www.notion.so/globekeeper/Integrations-Service-3792bbf7cb0b453380f576a4d1683268?pvs=4)

The current GlobeKeeper customization to original hookshot can be divided into 2 different main functionalities:

1. Provisioning the space-associated bridged-external-authentication:

This provisioning endpoint is responsible of introducing a new type of service to hookshot, and by triggering the provisioner with that type, the bride will establish a new route that will authenticate/register users from external systems (currently supporting only GeoDome POST login payload) according to the provided external auth provider URL and name and the path-embedded spaceId. This endpoint is authorized using the unique provisioning secret from the config.

[This is the API for provisioning](https://globekeeper.postman.co/workspace/GlobeKeeper-Workspace~f5ae58c4-4f28-4de4-accd-be7c7f041c57/request/13078936-153e2f3e-e0a3-44d4-9261-b3ed873d9bc1?active-environment=c409c387-7381-4861-ac2c-aa5f9c8ac1a0) (Should be sent by VCP client when clicking on e.g - "Integrate Space" in the space settings).


2. Actual authentication logic:

The actual authentication logic that is triggered by the newly created route from the provisioner.
Making a request to the generated endpoint will execute the following logic:
- Authenticate against the configured external-auth-provider URL (this URL is an argument to the provisioning API) ->
- if authenticated, continues, else it returns 401 ->
- If the user is already registered in Dendrite -> Logs-in and returns homeserver credentials (userId, deviceId and access token)
- If the user isn't already registered in Dendrite -> Registers the user with the format `@{{localpart from email}}-{{name of external auth provider, provided in the provisioning API}}:{{homeserverUrl}}` -> join the newly created user to the space configured with this bridged-auth and returns homeserver credentials (homeserver name, userId, deviceId and access token)

[This is the bridged login endpoint](https://globekeeper.postman.co/workspace/GlobeKeeper-Workspace~f5ae58c4-4f28-4de4-accd-be7c7f041c57/request/13078936-455cf8c0-e1d6-4a41-a6cc-7cafab36084d?active-environment=c409c387-7381-4861-ac2c-aa5f9c8ac1a0) (what GeoDome would use essentially):

#### Coming-up:

1. Traccar integration for supporting incoming GPS devices location updates and streaming them to the homeserver in a way that would allow displaying them on the map in configured rooms.
2. ... 🤩

### Debugging

For debugging purposes, toggle auto-attach in VS Code:
1. `cmnd+shift+p`
2. `Debug: Toggle Auto Attach`
3. `yarn`
4. `yarn start`

## Contact

We have a Matrix support room ([#hookshot:half-shot.uk](https://matrix.to/#/#hookshot:half-shot.uk)).
7 changes: 7 additions & 0 deletions config.sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ listeners:
# client_secret: bar
# redirect_uri: https://example.com/bridge_oauth/

#bridgeAuth:
# # (Optional) Support for external auth events
# enabled: false
# enableHttpGet: false
# domain: example.com
# urlPrefix: https://example.com/bridge_auth/

#generic:
# # (Optional) Support for generic webhook events.
# #'allowJsTransformationFunctions' will allow users to write short transformation snippets in code, and thus is unsafe in untrusted environments
Expand Down
2 changes: 1 addition & 1 deletion helm/hookshot/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ hookshot:
namespaces:
rooms: []
users: []
sender_localpart: hookshot
sender_localpart: bridgeas
url: "http://example.com"
rate_limited: false
passkey: ""
62 changes: 61 additions & 1 deletion src/Bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { GetIssueResponse, GetIssueOpts } from "./Gitlab/Types"
import { GithubInstance } from "./github/GithubInstance";
import { IBridgeStorageProvider } from "./Stores/StorageProvider";
import { IConnection, GitHubDiscussionSpace, GitHubDiscussionConnection, GitHubUserSpace, JiraProjectConnection, GitLabRepoConnection,
GitHubIssueConnection, GitHubProjectConnection, GitHubRepoConnection, GitLabIssueConnection, FigmaFileConnection, FeedConnection, GenericHookConnection, WebhookResponse } from "./Connections";
GitHubIssueConnection, GitHubProjectConnection, GitHubRepoConnection, GitLabIssueConnection, FigmaFileConnection, FeedConnection, GenericHookConnection, BridgeAuthConnection, WebhookResponse } from "./Connections";
import { IGitLabWebhookIssueStateEvent, IGitLabWebhookMREvent, IGitLabWebhookNoteEvent, IGitLabWebhookPushEvent, IGitLabWebhookReleaseEvent, IGitLabWebhookTagPushEvent, IGitLabWebhookWikiPageEvent } from "./Gitlab/WebhookTypes";
import { JiraIssueEvent, JiraIssueUpdatedEvent, JiraVersionEvent } from "./jira/WebhookTypes";
import { JiraOAuthResult } from "./jira/Types";
Expand All @@ -37,6 +37,7 @@ import { ListenerService } from "./ListenerService";
import { SetupConnection } from "./Connections/SetupConnection";
import { JiraOAuthRequestCloud, JiraOAuthRequestOnPrem, JiraOAuthRequestResult } from "./jira/OAuth";
import { GenericWebhookEvent, GenericWebhookEventResult } from "./generic/types";
import { BridgeAuthEvent, BridgeAuthEventResult } from "./bridge_auth/types";
import { SetupWidget } from "./Widgets/SetupWidget";
import { FeedEntry, FeedError, FeedReader, FeedSuccess } from "./feeds/FeedReader";
import PQueue from "p-queue";
Expand Down Expand Up @@ -153,6 +154,9 @@ export class Bridge {
if (this.config.generic) {
this.connectionManager.registerProvisioningConnection(GenericHookConnection);
}
if (this.config.bridgeAuth) {
this.connectionManager.registerProvisioningConnection(BridgeAuthConnection);
}
this.provisioningApi = new Provisioner(
this.config.provisioning,
this.connectionManager,
Expand Down Expand Up @@ -659,6 +663,62 @@ export class Bridge {
}
});

this.queue.on<BridgeAuthEvent>("bridge_auth.event", async (msg) => {
const { data, messageId } = msg;
const { username, password } = data;
const connections = connManager.getConnectionsForBridgeAuth(data.hookId);

if (!connections.length) {
await this.queue.push<BridgeAuthEventResult>({
data: {notFound: true},
sender: "bridge_auth",
messageId: messageId,
eventName: "response.bridge_auth.event",
});
}

let didPush = false;
await Promise.all(connections.map(async (c, index) => {
if (index !== 0) {
log.info(`Got more than one connection for bridge auth in space: ${c.roomId}`);
return;
}
try {
const { successful, response } = await c.onBridgeAuthHook(username, password);
await this.queue.push<BridgeAuthEventResult>({
data: {
successful,
response,
unauthorized: response?.unauthorized ?? true,
},
sender: "bridge_auth",
messageId,
eventName: "response.bridge_auth.event",
});
didPush = true;
}
catch (ex) {
log.warn(`Failed to handle bridge auth`, ex);
Metrics.connectionsEventFailed.inc({
event: "bridge_auth.event",
connectionId: c.connectionId
});
}
}));

// We didn't manage to complete sending the event or even sending a failure.
if (!didPush) {
await this.queue.push<BridgeAuthEventResult>({
data: {
successful: false
},
sender: "bridge_auth",
messageId,
eventName: "response.bridge_auth.event",
});
}
});

this.bindHandlerToQueue<FigmaEvent, FigmaFileConnection>(
"figma.payload",
(data) => connManager.getForFigmaFile(data.payload.file_key, data.instanceName),
Expand Down
6 changes: 5 additions & 1 deletion src/ConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Appservice, Intent, StateEvent } from "matrix-bot-sdk";
import { ApiError, ErrCode } from "./api";
import { BridgeConfig, BridgePermissionLevel, GitLabInstance } from "./config/Config";
import { CommentProcessor } from "./CommentProcessor";
import { ConnectionDeclaration, ConnectionDeclarations, GenericHookConnection, GitHubDiscussionConnection, GitHubDiscussionSpace, GitHubIssueConnection, GitHubProjectConnection, GitHubRepoConnection, GitHubUserSpace, GitLabIssueConnection, GitLabRepoConnection, IConnection, IConnectionState, JiraProjectConnection } from "./Connections";
import { ConnectionDeclaration, ConnectionDeclarations, GenericHookConnection, BridgeAuthConnection, GitHubDiscussionConnection, GitHubDiscussionSpace, GitHubIssueConnection, GitHubProjectConnection, GitHubRepoConnection, GitHubUserSpace, GitLabIssueConnection, GitLabRepoConnection, IConnection, IConnectionState, JiraProjectConnection } from "./Connections";
import { FigmaFileConnection, FeedConnection } from "./Connections";
import { GetConnectionTypeResponseItem } from "./provisioning/api";
import { GitLabClient } from "./Gitlab/Client";
Expand Down Expand Up @@ -333,6 +333,10 @@ export class ConnectionManager extends EventEmitter {
return this.connections.filter((c) => (c instanceof GenericHookConnection && c.hookId === hookId)) as GenericHookConnection[];
}

public getConnectionsForBridgeAuth(hookId: string): BridgeAuthConnection[] {
return this.connections.filter((c) => (c instanceof BridgeAuthConnection && c.hookId === hookId)) as BridgeAuthConnection[];
}

public getForFigmaFile(fileKey: string, instanceName: string): FigmaFileConnection[] {
return this.connections.filter((c) => (c instanceof FigmaFileConnection && (c.fileId === fileKey || c.instanceName === instanceName))) as FigmaFileConnection[];
}
Expand Down
Loading

0 comments on commit c3faa07

Please sign in to comment.