Open Dudeplayz opened 1 year ago
I've spent a few hours trying to get OIDC working with Quakus + Hilla.
For notes, I've set up my config as such:
quarkus.oidc.auth-server-url=https://
quarkus.oidc.client-id=code
quarkus.oidc.credentials.secret=woof
quarkus.oidc.application-type=web_app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.oidc.authentication.scopes=openid,profile,email
quarkus.oidc.authentication.user-info-required=true
quarkus.oidc.roles.role-claim-path=groups
This has enabled the app to automatically redirect to the OAuth RS to authorize, and the application receives and stores the auth.
I've had to add an Endpoint, one I'm calling AuthenticationApi
with the following code:
@BrowserCallable
@AnonymousAllowed
@AllArgsConstructor
public class AuthenticationApi {
private final SingleSignOnContext context;
private final UserInfo userInfo;
private final SecurityIdentity securityIdentity;
public @Nonnull SingleSignOnData fetchAll() {
return context.getSingleSignOnData();
}
public String token() {
return Optional.ofNullable(securityIdentity.getCredential(AccessTokenCredential.class)).map(token -> token.getToken()).orElse(null);
}
public @Nonnull List<@Nonnull String> getRegisteredProviders() {
return context.getRegisteredProviders();
}
public OidcUser getAuthenticatedUser() {
return context.getSingleSignOnData().isAuthenticated() ? OidcUser.fromUserInfo(userInfo) : null;
}
}
Of interest is the token
method, as I need to get the token to bootstrap the HTTPXmlRequests made to the API from the react front-end, using a middleware:
import { Middleware, MiddlewareContext, MiddlewareNext } from '@hilla/frontend';
import { AuthenticationApi } from 'Frontend/generated/endpoints';
export const AuthenticatedRequestMiddleware: Middleware = async function(
context: MiddlewareContext,
next: MiddlewareNext
) {
if (!context.request.url.includes("AuthenticationApi")) {
const token = await AuthenticationApi.token()
context.request.headers.append("Authorization", "Bearer " + token)
}
return await next(context);
};
With the above, sadly, it's making a new call to get the token, so I should store it in a cache (or swr
).
The conundrum however appears at the controller level: per Quarkus' documentation, the @PermitAll
annotation: Specifies that all security roles are allowed to invoke the specified methods. @PermitAll lets everybody in, even without authentication.
, which is in contrast to what Hilla does: @PermitAll Allows any authenticated user to call a method via the request.
I suppose the only way around this right now is to use RBAC: @RolesAllowed("dcc-editor")
. which does work. I may need to create a custom Annotation to hide the above.
Hi @UbiquitousBear, thank you for giving a try to quarkus-hilla and for the feedback.
To better understand the problem, is the issue related to calls to QuarkusEndpointController.serveEndpoint()
or to the specific methods in the @BrowserCallable
annotated class?
If the problem is the @BrowserCallable
methods blocked by Quarkus security and redirected to the Identity Provider, you should permit access to the QuarkusEndpointController
path
quarkus.http.auth.permission.hilla.paths=/connect/*
quarkus.http.auth.permission.hilla.policy=permit
This should probably be done automatically by quarkus-hilla in some way.
@mcollovati To clarify, I believe there's two different definitions for @PermitAll
: which makes things confusing - that said, what I've done so far is to force OIDC on all endpoints, which seems to fit the job for me, then use @RolesAllowed
. Using @PermitAll
doesn't seem to permit unauthenticated calls, but I need to play around a bit more.
On a different note, is it possible to define a custom annotation as such:
@BrowserCallable
@RolesAllowed("dcc-editor")
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthenticatedApiEndpoint {}
Any use this on Endpoints/BrowserCallables
? It'd mean I don't need to replicate @BrowserCallable and @RolesAllowed("dcc-editor")
across endpoints. I've tried using this, but getting a 404 from Quarkus - presumably because the endpoint isn't beaned (dev-ui doesn't show it as an endpoint).
I believe there's two different definitions for @PermitAll
That's indeed true. What we can do is to introduce a build step that converts the @PermitAll
annotation to @RolesAllowed("**")
on classes annotated with @BrowserCallable
or @EndpointExposed
.
About the meta annotations, I don't know if this works out-of-the-box in a plain Hilla project.
You can try to add the @Stereotype
annotation to your definition and see if in this way the bean is discovered
@mcollovati what are we defining as Stateless here; that requests are made without the sessions cookie?
@UbiquitousBear we define it as not be bound to a server side session/context (e.g. this definition) in terms of authentication/authorization. I named the ticket this way, because I wasn't sure what other auth mechanisms are available, so it is a bit missleading. Cookie/Header based auth per request is basically always stateless, as long it is not bound to a specific server side session or context. Hilla is designed to be stateless and as we are replacing Spring Boot internals with equivalent Quarkus code, it should work. We just haven't tested it ourself nor added tests for it. So we can't guarantee for it.
In the first, check if it working OOB.