Skip to content

Commit 8441e9e

Browse files
committed
add client facade (JsonRpcAuthProviderClient)
1 parent 29220b5 commit 8441e9e

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { Code, ConnectError, PromiseClient } from "@connectrpc/connect";
8+
import { PartialMessage } from "@bufbuild/protobuf";
9+
import { AuthProviderService } from "@gitpod/public-api/lib/gitpod/v1/authprovider_connect";
10+
import {
11+
CreateAuthProviderRequest,
12+
GetAuthProviderRequest,
13+
ListAuthProvidersRequest,
14+
ListAuthProviderDescriptionsRequest,
15+
UpdateAuthProviderRequest,
16+
DeleteAuthProviderRequest,
17+
CreateAuthProviderResponse,
18+
ListAuthProvidersResponse,
19+
GetAuthProviderResponse,
20+
ListAuthProviderDescriptionsResponse,
21+
UpdateAuthProviderResponse,
22+
DeleteAuthProviderResponse,
23+
AuthProvider,
24+
AuthProviderType,
25+
OAuth2Config,
26+
} from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
27+
import { AuthProviderEntry } from "@gitpod/gitpod-protocol";
28+
import { getGitpodService } from "./service";
29+
30+
export class JsonRpcAuthProviderClient implements PromiseClient<typeof AuthProviderService> {
31+
async createAuthProvider(request: PartialMessage<CreateAuthProviderRequest>): Promise<CreateAuthProviderResponse> {
32+
throw new ConnectError("unimplemented", Code.Unimplemented);
33+
}
34+
async getAuthProvider(request: PartialMessage<GetAuthProviderRequest>): Promise<GetAuthProviderResponse> {
35+
if (!request.authProviderId) {
36+
throw new ConnectError("authProviderId is required", Code.InvalidArgument);
37+
}
38+
throw new ConnectError("unimplemented", Code.Unimplemented);
39+
}
40+
async listAuthProviders(request: PartialMessage<ListAuthProvidersRequest>): Promise<ListAuthProvidersResponse> {
41+
if (!request.id?.case) {
42+
throw new ConnectError("id is required", Code.InvalidArgument);
43+
}
44+
const organizationId = request.id.case === "organizationId" ? request.id.value : undefined;
45+
const userId = request.id.case === "userId" ? request.id.value : undefined;
46+
47+
if (organizationId) {
48+
const result = await getGitpodService().server.getOrgAuthProviders({
49+
organizationId,
50+
});
51+
const response = new ListAuthProvidersResponse();
52+
response.list = result.map(toAuthProvider);
53+
return response;
54+
}
55+
if (userId) {
56+
const result = await getGitpodService().server.getOwnAuthProviders();
57+
const response = new ListAuthProvidersResponse();
58+
response.list = result.map(toAuthProvider);
59+
return response;
60+
}
61+
throw new ConnectError("either organizationId or userId are required", Code.InvalidArgument);
62+
}
63+
async listAuthProviderDescriptions(
64+
request: PartialMessage<ListAuthProviderDescriptionsRequest>,
65+
): Promise<ListAuthProviderDescriptionsResponse> {
66+
throw new ConnectError("unimplemented", Code.Unimplemented);
67+
}
68+
async updateAuthProvider(request: PartialMessage<UpdateAuthProviderRequest>): Promise<UpdateAuthProviderResponse> {
69+
if (!request.authProviderId) {
70+
throw new ConnectError("authProviderId is required", Code.InvalidArgument);
71+
}
72+
const clientId = request?.oauth2Config?.clientId;
73+
const clientSecret = request?.oauth2Config?.clientSecret;
74+
if (!clientId || !clientSecret) {
75+
throw new ConnectError("clientId or clientSecret are required", Code.InvalidArgument);
76+
}
77+
78+
await getGitpodService().server.updateAuthProvider(request.authProviderId, {
79+
clientId,
80+
clientSecret,
81+
});
82+
return new UpdateAuthProviderResponse();
83+
}
84+
async deleteAuthProvider(request: PartialMessage<DeleteAuthProviderRequest>): Promise<DeleteAuthProviderResponse> {
85+
if (!request.authProviderId) {
86+
throw new ConnectError("authProviderId is required", Code.InvalidArgument);
87+
}
88+
await getGitpodService().server.deleteAuthProvider(request.authProviderId);
89+
return new DeleteAuthProviderResponse();
90+
}
91+
}
92+
93+
function toAuthProvider(entry: AuthProviderEntry): AuthProvider {
94+
const ap = new AuthProvider();
95+
ap.verified = entry.status === "verified";
96+
ap.host = entry.host;
97+
ap.id = entry.id;
98+
ap.type = toAuthProviderType(entry.type);
99+
ap.oauth2Config = toOAuth2Config(entry);
100+
ap.scopes = entry.oauth?.scope?.split(entry.oauth?.scopeSeparator || " ") || [];
101+
ap.settingsUrl = entry.oauth.settingsUrl;
102+
return ap;
103+
}
104+
105+
function toOAuth2Config(entry: AuthProviderEntry): OAuth2Config {
106+
const config = new OAuth2Config();
107+
config.clientId = entry.oauth.clientId;
108+
config.clientSecret = entry.oauth.clientSecret;
109+
return config;
110+
}
111+
112+
function toAuthProviderType(type: string): AuthProviderType {
113+
switch (type) {
114+
case "GitHub":
115+
return AuthProviderType.GITHUB;
116+
case "GitLab":
117+
return AuthProviderType.GITLAB;
118+
case "Bitbucket":
119+
return AuthProviderType.BITBUCKET;
120+
case "BitbucketServer":
121+
return AuthProviderType.BITBUCKET_SERVER;
122+
default:
123+
return AuthProviderType.UNSPECIFIED; // not allowed
124+
}
125+
}

components/dashboard/src/service/public-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import { getMetricsInterceptor } from "@gitpod/public-api/lib/metrics";
2222
import { getExperimentsClient } from "../experiments/client";
2323
import { JsonRpcOrganizationClient } from "./json-rpc-organization-client";
2424
import { JsonRpcWorkspaceClient } from "./json-rpc-workspace-client";
25+
import { JsonRpcAuthProviderClient } from "./json-rpc-authprovider-client";
26+
import { AuthProviderService } from "@gitpod/public-api/lib/gitpod/v1/authprovider_connect";
2527

2628
const transport = createConnectTransport({
2729
baseUrl: `${window.location.protocol}//${window.location.host}/public-api`,
@@ -45,6 +47,7 @@ export const organizationClient = createServiceClient(
4547
new JsonRpcOrganizationClient(),
4648
"organization",
4749
);
50+
export const authProviderClient = createServiceClient(AuthProviderService, new JsonRpcAuthProviderClient());
4851

4952
export async function listAllProjects(opts: { orgId: string }): Promise<ProtocolProject[]> {
5053
let pagination = {

components/gitpod-protocol/src/gitpod-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
104104
/** @deprecated used for public-api compatibility only */
105105
deleteAuthProvider(id: string): Promise<void>;
106106
/** @deprecated used for public-api compatibility only */
107-
updateAuthProvider(id: string, update: AuthProviderEntry.UpdateEntry): Promise<AuthProviderEntry>;
107+
updateAuthProvider(id: string, update: AuthProviderEntry.UpdateOAuth2Config): Promise<AuthProviderEntry>;
108108

109109
// Query/retrieve workspaces
110110
getWorkspaces(options: GitpodServer.GetWorkspacesOptions): Promise<WorkspaceInfo[]>;

components/gitpod-protocol/src/protocol.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ export namespace AuthProviderEntry {
15881588
clientSecret: string;
15891589
organizationId: string;
15901590
};
1591+
export type UpdateOAuth2Config = Pick<OAuth2Config, "clientId" | "clientSecret">;
15911592
export function redact(entry: AuthProviderEntry): AuthProviderEntry {
15921593
return {
15931594
...entry,

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3154,7 +3154,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
31543154
async updateAuthProvider(
31553155
ctx: TraceContextWithSpan,
31563156
id: string,
3157-
entry: AuthProviderEntry.UpdateEntry,
3157+
update: AuthProviderEntry.UpdateOAuth2Config,
31583158
): Promise<AuthProviderEntry> {
31593159
traceAPIParams(ctx, { id });
31603160

@@ -3167,10 +3167,22 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
31673167

31683168
if (authProvider.organizationId) {
31693169
return this.updateOrgAuthProvider(ctx, {
3170-
entry: { ...entry, organizationId: authProvider.organizationId },
3170+
entry: {
3171+
organizationId: authProvider.organizationId,
3172+
id: authProvider.id,
3173+
clientId: update.clientId,
3174+
clientSecret: update.clientSecret,
3175+
},
31713176
});
31723177
} else {
3173-
return this.updateOwnAuthProvider(ctx, { entry });
3178+
return this.updateOwnAuthProvider(ctx, {
3179+
entry: {
3180+
id: authProvider.id,
3181+
clientId: update.clientId,
3182+
clientSecret: update.clientSecret,
3183+
ownerId: user.id,
3184+
},
3185+
});
31743186
}
31753187
}
31763188

0 commit comments

Comments
 (0)