Skip to content

Commit bfb771b

Browse files
committed
update openapi spec and small fixes
1 parent cee6508 commit bfb771b

File tree

5 files changed

+160
-6
lines changed

5 files changed

+160
-6
lines changed

packages/maas/bff/internal/api/access_review_handler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func AccessReviewHandler(app *App, w http.ResponseWriter, r *http.Request, _ htt
5656
app.badRequestResponse(w, r, err)
5757
return
5858
}
59+
if request.Data.Resource == "" || request.Data.Verb == "" {
60+
app.badRequestResponse(w, r, fmt.Errorf("resource and verb are required"))
61+
return
62+
}
5963

6064
client, err := k8s.NewTokenKubernetesClient(token, app.logger)
6165
if err != nil {

packages/maas/bff/internal/api/app.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ const (
3434
HealthCheckPath = "/healthcheck"
3535
UserPath = constants.ApiPathPrefix + "/user"
3636
NamespacePath = constants.ApiPathPrefix + "/namespaces"
37-
IsMaasAdminPath = constants.ApiPathPrefix + "/is-maas-admin"
3837
)
3938

4039
type App struct {
@@ -183,7 +182,8 @@ func (app *App) Routes() http.Handler {
183182
attachSubscriptionHandlers(apiRouter, app)
184183
attachMaaSModelRefHandlers(apiRouter, app)
185184
apiRouter.GET(constants.ApiPathPrefix+"/models", handlerWithApp(app, ListModelsHandler))
186-
apiRouter.GET(IsMaasAdminPath, handlerWithApp(app, IsMaasAdminHandler))
185+
apiRouter.GET(constants.IsMaasAdminPath, handlerWithApp(app, IsMaasAdminHandler))
186+
apiRouter.POST(constants.AccessReviewPath, handlerWithApp(app, AccessReviewHandler))
187187

188188
// Minimal Kubernetes-backed starter endpoints TODO: Remove?
189189
apiRouter.GET(UserPath, app.UserHandler)

packages/maas/bff/internal/constants/api_routes.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const (
1515
APIKeyByIDPath = ApiPathPrefix + "/api-keys/:id"
1616

1717
// Access review
18-
IsMaasAdminPath = ApiPathPrefix + "/is-maas-admin"
18+
IsMaasAdminPath = ApiPathPrefix + "/is-maas-admin"
19+
AccessReviewPath = ApiPathPrefix + "/access-review"
1920

2021
// Subscription routes
2122
SubscriptionListPath = ApiPathPrefix + "/all-subscriptions"

packages/maas/bff/openapi.yaml

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,155 @@ paths:
5555
'500':
5656
description: Internal Server Error
5757

58+
/api/v1/is-maas-admin:
59+
get:
60+
summary: Check MaaS Admin Access
61+
operationId: isMaasAdmin
62+
description: >
63+
Checks whether the requesting user has MaaS admin privileges by performing
64+
a SelfSubjectAccessReview against the `maasauthpolicies` resource in the
65+
`models-as-a-service` namespace. Returns `allowed: true` only for users
66+
who can create MaaSAuthPolicy resources (i.e. cluster/MaaS admins).
67+
68+
Token resolution priority:
69+
70+
1. `Authorization: Bearer <token>` — used by the ODH dashboard backend;
71+
correctly substituted with the impersonated user's token when the ODH
72+
dev impersonation feature (`DEV_IMPERSONATE_USER`) is active.
73+
74+
2. `x-forwarded-access-token` — fallback for standalone federated dev mode
75+
where the webpack proxy injects the real user's token directly.
76+
responses:
77+
'200':
78+
description: Access check result
79+
content:
80+
application/json:
81+
schema:
82+
type: object
83+
properties:
84+
data:
85+
type: object
86+
properties:
87+
allowed:
88+
type: boolean
89+
description: Whether the user has MaaS admin access
90+
required:
91+
- allowed
92+
example:
93+
data:
94+
allowed: true
95+
'400':
96+
description: Bad Request (missing authentication token)
97+
content:
98+
application/json:
99+
schema:
100+
$ref: '#/components/schemas/ErrorResponse'
101+
'500':
102+
description: Internal Server Error
103+
content:
104+
application/json:
105+
schema:
106+
$ref: '#/components/schemas/ErrorResponse'
107+
108+
/api/v1/access-review:
109+
post:
110+
summary: Generic Self-Subject Access Review
111+
operationId: accessReview
112+
description: >
113+
Performs a SelfSubjectAccessReview for the requesting user against the
114+
specified Kubernetes resource, group, and verb. Returns `allowed: true`
115+
if the user has the requested permission.
116+
117+
Use this endpoint when you need a custom permission check beyond the
118+
fixed MaaS-admin check provided by `/api/v1/is-maas-admin`.
119+
120+
Token resolution priority:
121+
122+
1. `Authorization: Bearer <token>` — used by the ODH dashboard backend;
123+
correctly substituted with the impersonated user's token when the ODH
124+
dev impersonation feature (`DEV_IMPERSONATE_USER`) is active.
125+
126+
2. `x-forwarded-access-token` — fallback for standalone federated dev mode
127+
where the webpack proxy injects the real user's token directly.
128+
requestBody:
129+
required: true
130+
content:
131+
application/json:
132+
schema:
133+
type: object
134+
required:
135+
- data
136+
properties:
137+
data:
138+
type: object
139+
required:
140+
- resource
141+
- verb
142+
properties:
143+
group:
144+
type: string
145+
description: API group of the resource
146+
example: maas.opendatahub.io
147+
resource:
148+
type: string
149+
description: Resource type to check access for
150+
example: maasauthpolicies
151+
verb:
152+
type: string
153+
description: Action to check (e.g. get, list, create, patch, delete, *)
154+
example: create
155+
namespace:
156+
type: string
157+
description: Namespace scope for the check
158+
example: models-as-a-service
159+
examples:
160+
wildcard_admin_check:
161+
summary: Check if user can do anything
162+
value:
163+
data:
164+
group: ""
165+
resource: "*"
166+
verb: "*"
167+
maas_admin_check:
168+
summary: Check MaaS admin access explicitly
169+
value:
170+
data:
171+
group: maas.opendatahub.io
172+
resource: maasauthpolicies
173+
verb: create
174+
namespace: models-as-a-service
175+
responses:
176+
'200':
177+
description: Access check result
178+
content:
179+
application/json:
180+
schema:
181+
type: object
182+
properties:
183+
data:
184+
type: object
185+
properties:
186+
allowed:
187+
type: boolean
188+
description: Whether the user has the requested access
189+
required:
190+
- allowed
191+
example:
192+
data:
193+
allowed: true
194+
'400':
195+
description: Bad Request (missing token or missing required fields)
196+
content:
197+
application/json:
198+
schema:
199+
$ref: '#/components/schemas/ErrorResponse'
200+
'500':
201+
description: Internal Server Error
202+
content:
203+
application/json:
204+
schema:
205+
$ref: '#/components/schemas/ErrorResponse'
206+
58207
/api/v1/namespaces:
59208
get:
60209
summary: Get Namespaces

packages/maas/frontend/src/app/hooks/useIsMaasAdmin.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ type IsMaasAdminResult = {
66
allowed: boolean;
77
};
88

9-
export const useIsMaasAdmin = (): [boolean, boolean] => {
9+
export const useIsMaasAdmin = (): [boolean, boolean, Error | undefined] => {
1010
const callback = React.useCallback<FetchStateCallbackPromise<IsMaasAdminResult>>(
1111
(opts: APIOptions) => getIsMaasAdmin()(opts),
1212
[],
1313
);
1414

15-
const [result, loaded] = useFetchState<IsMaasAdminResult>(callback, { allowed: false });
15+
const [result, loaded, error] = useFetchState<IsMaasAdminResult>(callback, { allowed: false });
1616

17-
return [result.allowed, loaded];
17+
return [result.allowed, loaded, error];
1818
};

0 commit comments

Comments
 (0)