Skip to content

Commit 4886c74

Browse files
authored
fix: auth providers: allow only one at a time (#1382)
Signed-off-by: Grant Linville <[email protected]>
1 parent 194c866 commit 4886c74

File tree

4 files changed

+80
-13
lines changed

4 files changed

+80
-13
lines changed

pkg/api/handlers/authprovider.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,23 @@ func (ap *AuthProviderHandler) ByID(req api.Context) error {
5959
}
6060

6161
func (ap *AuthProviderHandler) List(req api.Context) error {
62+
resp, err := ap.listAuthProviders(req)
63+
if err != nil {
64+
return err
65+
}
66+
67+
return req.Write(types.AuthProviderList{Items: resp})
68+
}
69+
70+
func (ap *AuthProviderHandler) listAuthProviders(req api.Context) ([]types.AuthProvider, error) {
6271
var refList v1.ToolReferenceList
6372
if err := req.List(&refList, &kclient.ListOptions{
6473
Namespace: req.Namespace(),
6574
FieldSelector: fields.SelectorFromSet(map[string]string{
6675
"spec.type": string(types.ToolReferenceTypeAuthProvider),
6776
}),
6877
}); err != nil {
69-
return err
78+
return nil, err
7079
}
7180

7281
credCtxs := make([]string, 0, len(refList.Items))
@@ -78,7 +87,7 @@ func (ap *AuthProviderHandler) List(req api.Context) error {
7887
CredentialContexts: credCtxs,
7988
})
8089
if err != nil {
81-
return fmt.Errorf("failed to list auth provider credentials: %w", err)
90+
return nil, fmt.Errorf("failed to list auth provider credentials: %w", err)
8291
}
8392

8493
credMap := make(map[string]map[string]string, len(creds))
@@ -90,8 +99,7 @@ func (ap *AuthProviderHandler) List(req api.Context) error {
9099
for _, ref := range refList.Items {
91100
resp = append(resp, convertToolReferenceToAuthProvider(ref, credMap[string(ref.UID)+ref.Name]))
92101
}
93-
94-
return req.Write(types.AuthProviderList{Items: resp})
102+
return resp, nil
95103
}
96104

97105
func (ap *AuthProviderHandler) Configure(req api.Context) error {
@@ -104,6 +112,19 @@ func (ap *AuthProviderHandler) Configure(req api.Context) error {
104112
return types.NewErrBadRequest("%q is not an auth provider", ref.Name)
105113
}
106114

115+
// Check to see if there are any other configured auth providers.
116+
// For now, we only support one auth provider at a time to be configured.
117+
allAuthProviders, err := ap.listAuthProviders(req)
118+
if err != nil {
119+
return err
120+
}
121+
122+
for _, ap := range allAuthProviders {
123+
if ap.Configured && (ap.Name != authProviderNameFromToolRef(ref) || ap.Namespace != ref.Namespace) {
124+
return types.NewErrBadRequest("another auth provider is already configured")
125+
}
126+
}
127+
107128
var envVars map[string]string
108129
if err := req.Read(&envVars); err != nil {
109130
return err
@@ -198,16 +219,19 @@ func (ap *AuthProviderHandler) Reveal(req api.Context) error {
198219
return types.NewErrNotFound("no credential found for %q", ref.Name)
199220
}
200221

201-
func convertToolReferenceToAuthProvider(ref v1.ToolReference, credEnvVars map[string]string) types.AuthProvider {
222+
func authProviderNameFromToolRef(ref v1.ToolReference) string {
202223
name := ref.Name
203224
if ref.Status.Tool != nil {
204225
name = ref.Status.Tool.Name
205226
}
227+
return name
228+
}
206229

230+
func convertToolReferenceToAuthProvider(ref v1.ToolReference, credEnvVars map[string]string) types.AuthProvider {
207231
ap := types.AuthProvider{
208232
Metadata: MetadataFrom(&ref),
209233
AuthProviderManifest: types.AuthProviderManifest{
210-
Name: name,
234+
Name: authProviderNameFromToolRef(ref),
211235
Namespace: ref.Namespace,
212236
ToolReference: ref.Spec.Reference,
213237
},

ui/admin/app/components/auth-and-model-providers/AuthProviderLists.tsx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CircleCheckIcon, CircleSlashIcon } from "lucide-react";
1+
import { CircleCheckIcon, CircleHelpIcon, CircleSlashIcon } from "lucide-react";
22
import { Link } from "react-router";
33

44
import { AuthProvider } from "~/lib/model/providers";
@@ -8,7 +8,23 @@ import { ProviderIcon } from "~/components/auth-and-model-providers/ProviderIcon
88
import { ProviderMenu } from "~/components/auth-and-model-providers/ProviderMenu";
99
import { AuthProviderLinks } from "~/components/auth-and-model-providers/constants";
1010
import { Badge } from "~/components/ui/badge";
11+
import { Button } from "~/components/ui/button";
1112
import { Card, CardContent, CardHeader } from "~/components/ui/card";
13+
import {
14+
Tooltip,
15+
TooltipContent,
16+
TooltipTrigger,
17+
} from "~/components/ui/tooltip";
18+
19+
function isDisabled(
20+
authProvider: AuthProvider,
21+
authProviders: AuthProvider[]
22+
): boolean {
23+
return (
24+
!authProvider.configured &&
25+
authProviders.filter((p) => p.configured).length > 0
26+
);
27+
}
1228

1329
export function AuthProviderList({
1430
authProviders,
@@ -21,13 +37,32 @@ export function AuthProviderList({
2137
{authProviders.map((authProvider) => (
2238
<Card key={authProvider.id}>
2339
<CardHeader className="flex flex-row items-center justify-between pb-4 pt-2">
24-
{authProvider.configured ? (
40+
{authProvider.configured && (
2541
<div className="flex flex-row items-center gap-2">
2642
<ProviderMenu provider={authProvider} />
2743
</div>
28-
) : (
29-
<div className="h-9 w-9" />
3044
)}
45+
{isDisabled(authProvider, authProviders) && (
46+
<div className="flex flex-row items-center gap-2">
47+
<Tooltip>
48+
<TooltipTrigger>
49+
<Button variant="ghost" size="icon">
50+
<CircleHelpIcon />
51+
</Button>
52+
</TooltipTrigger>
53+
<TooltipContent>
54+
<span>
55+
You must deconfigure the existing provider before
56+
configuring this one.
57+
</span>
58+
</TooltipContent>
59+
</Tooltip>
60+
</div>
61+
)}
62+
{!isDisabled(authProvider, authProviders) &&
63+
!authProvider.configured && (
64+
<div className="flex flex-row items-center gap-2" />
65+
)}
3166
</CardHeader>
3267
<CardContent className="flex flex-col items-center gap-4">
3368
<Link to={AuthProviderLinks[authProvider.id]}>
@@ -50,7 +85,10 @@ export function AuthProviderList({
5085
</span>
5186
)}
5287
</Badge>
53-
<ProviderConfigure provider={authProvider} />
88+
<ProviderConfigure
89+
provider={authProvider}
90+
disabled={isDisabled(authProvider, authProviders)}
91+
/>
5492
</CardContent>
5593
</Card>
5694
))}

ui/admin/app/components/auth-and-model-providers/ModelProviderLists.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function ModelProviderList({
6060
</span>
6161
)}
6262
</Badge>
63-
<ProviderConfigure provider={modelProvider} />
63+
<ProviderConfigure provider={modelProvider} disabled={false} />
6464
</CardContent>
6565
</Card>
6666
))}

ui/admin/app/components/auth-and-model-providers/ProviderConfigure.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ import { Link } from "~/components/ui/link";
2626

2727
type ProviderConfigureProps = {
2828
provider: ModelProvider | AuthProvider;
29+
disabled: boolean;
2930
};
3031

31-
export function ProviderConfigure({ provider }: ProviderConfigureProps) {
32+
export function ProviderConfigure({
33+
provider,
34+
disabled,
35+
}: ProviderConfigureProps) {
3236
const [dialogIsOpen, setDialogIsOpen] = useState(false);
3337
const [showDefaultModelAliasForm, setShowDefaultModelAliasForm] =
3438
useState(false);
@@ -70,6 +74,7 @@ export function ProviderConfigure({ provider }: ProviderConfigureProps) {
7074
<Dialog open={dialogIsOpen} onOpenChange={setDialogIsOpen}>
7175
<DialogTrigger asChild>
7276
<Button
77+
disabled={disabled}
7378
variant={provider.configured ? "secondary" : "accent"}
7479
className="mt-0 w-full"
7580
>

0 commit comments

Comments
 (0)