jakartaee / security

Jakarta Security
https://projects.eclipse.org/projects/ee4j.security
Other
46 stars 39 forks source link

Add programmatic configuation API as alternative of annotation declaration #227

Open hantsy opened 2 years ago

hantsy commented 2 years ago

For example create a configurable bean to allow developers to assemble the authentication mechanism by codes instead of annotations.

@ApplicationScoped
class AuthConfiguration {

   @Produces
   HttpAuthenticationMechanismFactory openIdHttpAuthMechanism() {

   }

}
hantsy commented 2 years ago

Wildfly Elytron Example: https://docs.wildfly.org/19.1/WildFly_Elytron_Security.html#the-programmatic-approach

arjantijms commented 2 years ago

Essentially, since the "configuration API" is CDI, you can add whatever bean you want using the programmatic CDI API already.

Using CDI extensions you can even add the annotation programmatically, but you can also add the HttpAuthenticationMechanism itself using @Produces. Although it's in a slightly different context, you can see a kind of example for that here:

https://arjan-tijms.omnifaces.org/2017/08/dynamically-adding-interceptor-to-build.html

hantsy commented 1 year ago

@arjantijms I have read the post before, it is great.

For a junior Jakarta EE developers, we could prefer to use Spring Security config like fluent APIs directly instead of hook the CDI lifecycle to produce a HttpAuthenticationMechanism.

An example of Spring Security config fragment.

http
    .securityMatcher("/api/**")
    .authorizeHttpRequests(authorize -> authorize
            .anyRequest().hasRole("ADMIN")
    )
    .httpBasic(withDefaults());
OndroMih commented 11 months ago

I think this is also related: https://github.com/jakartaee/security/issues/188

We should think about what we're trying to address here and find the best solution that addresses most issues.

E.g., the usecase I'd like to have a solution for is to be able to select which authentication should be used for a specific user login. An example is to implement a login form with multiple options for the user to choose from: user/password/ Google / Facebook / OAuth, etc. Mostly just a single custom form option and multiple OpenId options.

Another usecase is to biuld multitenant apps, where the authentication mechanism is selected based on the tenant (e.g. the domain used to access the app). E.g. if a user opens department1.mycompany.com, it will use deparment1's OpenId server, if they open department2.mycompany.com, department2's OpenId server is used.

hantsy commented 11 months ago

Found in the old PicketLink docucmentation, https://docs.jboss.org/picketlink/2/latest/reference/html-single/, there are some work like this.

public class HttpSecurityConfiguration {
​
​    public void configureHttpSecurity(@Observes SecurityConfigurationEvent event) {
​        SecurityConfigurationBuilder builder = event.getBuilder();
​
​        builder
​            .http()
​                .forPath("/*.jsf")
​                    .authenticateWith()
​                        .form()
​                            .loginPage("/login.jsf")
​                            .errorPage("/loginFailed.jsf")
​                .forPath("/admin/*")
​                    .authorizeWith()
​                        .role("Administrator");
​    }
​}

Hope there is a configuration like these, not dependent on Servlet spec, but can be applied to Faces, Servlet, Jaxrs, WebSocket, etc.

hantsy commented 11 months ago

Currently Jakarta Security does not have an united configuration for protocols, paths, etc.

  1. Traditional annotations like RolesAllowed, etc only can be applied on class method, can not setup path regex pattern.
  2. The web.xml provides servlet path security config, but it is part of Servlet spec.
  3. For the new HttpAuthenticationMechanism based Basic/Form, OIDC, etc. annotations, there is no simple way to set up the path matchers. And it is too dependent on Servlet spec.
  4. No security config solution for Websocket destinations.
  5. How to process security config in GraphQl/gRPC protocols(when these become part of Jakarta EE)?
arjantijms commented 8 months ago

Currently Jakarta Security does not have an united configuration for protocols, paths, etc.

Well... technically all the authorization config (constraints, translated to permissions) end up in the Policy (see also https://arjan-tijms.omnifaces.org/2015/04/how-java-ee-translates-webxml.html)

But the Policy of Jakarta EE 10 and before is particularly hard to use and even hard to install / set. (see https://arjan-tijms.omnifaces.org/2014/12/java-ee-authorization-jacc-revisited.html)

At least that last aspect will be improved for Jakarta EE 11.

For the new HttpAuthenticationMechanism based Basic/Form, OIDC, etc. annotations, there is no simple way to set up the path matchers. And it is too dependent on Servlet spec.

Having a permission store might be the base of making this aspect more universal: https://github.com/jakartaee/security/issues/296

How to process security config in GraphQl/gRPC protocols(when these become part of Jakarta EE)?

Jakarta Security depends on Jakarta Authentication, which is protocol independent. A ServerAuthModule delegates to a xyzAuthenticationMechanism. We'll have to see still if/how mechanisms for different protocols should be shared or not.

Most urgent in this case perhaps is Jakarta REST being seen as a separate protocol, and even the core protocol (as Jakarta REST is in Core Profile, and Servlet is not). We should either create a common base for Jakarta REST and Jakarta Servlet, or Jakarta Security should support Jakarta REST independently as a core protocol.

Politics play an important role too here. Despite being called the Core Profile, the Core Profile is actually the "MicroProfile overlap Profile", and Jakarta REST is in there not based on Servlet because Quarkus is using Vert.x underneath REST. And Quarkus is currently what's driving many things in Jakarta EE, despite Quarkus not wanting to be Jakarta EE. In a way this is nothing though, and in the early days of EJB and JMS we saw the same conflicts and choices being made just because of some vendor product being particularly important (CMP and queues vs topics were the results of that).