Hi Chaz-

The specific JAAS changes are noted in the release notes and are not related to 
callAs/runAs changes.

All Java JDK JAAS users will run into problems trying to write compatible JAAS 
API invocations that cross JDK 11 -> JDK 21 since Subject.current() was not 
back-ported to JDK 11.

Your approach of using reflection is interesting.. I was planning on separate 
jar files that are linked in classpath at boot time. I’ll dig more into a 
reflection approach to see if there is a way to better support multiple 
versions of the JDK.

Thanks,
Matt Pavlovich

> On Jul 29, 2025, at 12:28 PM, Chaz Kettleson 
> <apache-karaf-...@pyr3x.com.INVALID> wrote:
> 
> On Tue, Jul 29, 2025 at 05:22:38PM +0200, Jean-Baptiste Onofré wrote:
>> Hi everyone,
>> 
>> I submit the Apache Karaf 4.4.8 release to your vote.
>> 
>> This release is a maintenance release on the 4.4.x series bringing
>> fixes and updates, especially:
>> - SecurityContext returns RolePrincipal instead of UserPrincipal in JAX-RS
>> - Several improvements on JAAS layer
>> - New BoM (light)
>> - Java26 support
>> - Full build using JDK11 (including javase 11 in the resolver)
>> - A bunch of dependency updates
>> 
>> You can take a look on the Release Notes for details:
>> https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12311140&version=12354828
>> 
>> Maven Staging Repository:
>> https://repository.apache.org/content/repositories/orgapachekaraf-1195/
>> 
>> Dist Staging Repository:
>> https://dist.apache.org/repos/dist/dev/karaf/4.4.8/
>> 
>> Git tag:
>> karaf-4.4.8
>> 
>> Please vote to approve this release:
>> [ ] +1 Approve the release
>> [ ] -1 Don't approve the release (please provide specific comments)
>> 
>> This vote will be open for at least 72 hours.
>> 
>> Regards
>> JB
> 
> Hello,
> 
> Currently I use the karaf service guard with an acl for my service. This
> works for the shell, as well as my JAX-RS setup (allowing both a REST
> and CLI based authc/authz with a centralized policy). While I use Shiro
> on the REST side, I wrap the invocations with an interceptor to populate
> what Karaf wants for doing lookups.
> 
> @Slf4j
> public class JaasSubjectDoAsInterceptor extends 
> AbstractPhaseInterceptor<Message> {
> 
>  public JaasSubjectDoAsInterceptor() {
>    super(Phase.PRE_INVOKE);
>  }
> 
>  @Override
>  public void handleMessage(final Message message) {
>    final org.apache.shiro.subject.Subject shiroSubject = 
> SecurityUtils.getSubject();
>    if (shiroSubject == null
>        || !(shiroSubject.getPrincipal() instanceof RichPrincipal 
> userPrincipal)) {
>      return;
>    }
>    SecurityUtilities.runAs(
>        SecurityUtilities.toJaasSubject(userPrincipal),
>        () -> {
>          message.getInterceptorChain().doIntercept(message);
>          return null;
>        });
>  }
> }
> 
> where SecurityUtilities.runAs:
> 
>  public static <T> T runAs(final Subject subject, final PrivilegedAction<T> 
> action) {
>    if (CALL_AS_METHOD.isPresent()) {
>      try {
>        // Java 21+ path: invoke Subject.callAs(subject, action)
>        @SuppressWarnings("unchecked")
>        final T result = (T) CALL_AS_METHOD.get().invoke(null, subject, 
> action);
>        return result;
>      } catch (final ReflectiveOperationException ex) {
>        // Fallback to legacy doAs on error
>      }
>    }
> 
>    // Pre-Java 21 fallback or callAs failed: use legacy Subject.doAs(...)
>    return Subject.doAs(subject, action);
>  }
> 
> I also have SecurityUtilities.toJaasSubject:
> 
>  public static Subject toJaasSubject(@NonNull final RichPrincipal 
> richPrincipal) {
>    final Set<Principal> principals = new HashSet<>();
> 
>    // Add the main user principal (identity) to the JAAS Subject
>    principals.add(new UserPrincipal(richPrincipal.name()));
> 
>    // Add roles as RolePrincipals
>    richPrincipal.roles().forEach(role -> principals.add(new 
> RolePrincipal(role)));
> 
>    // Add permissions as RolePrincipals (assuming permissions are handled 
> similarly)
>    richPrincipal
>        .permissions()
>        .forEach(permission -> principals.add(new RolePrincipal(permission)));
> 
>    // Construct the JAAS Subject with principals, no public/private 
> credentials
>    return new Subject(true, principals, Set.of(), Set.of());
>  }
> 
> This allows me to authenticate to the REST service and still use the
> service guard to check for my authorization (roles) because of populated
> the JAASSubject with roles from User/Roles Karaf expects.
> 
> I do something similar when accessing the Subject from the service as
> in:
> 
>  public static Optional<Subject> getCurrentSubject() {
>    if (CURRENT_METHOD.isPresent()) {
>      try {
>        // Java 21+ path: invoke Subject.current()
>        final Subject subject = (Subject) CURRENT_METHOD.get().invoke(null);
>        return Optional.ofNullable(subject);
>      } catch (final ReflectiveOperationException e) {
>        // Fallback to empty on error
>        return Optional.empty();
>      }
>    } else {
>      // Pre-Java 21 fallback: use legacy method
>      final Subject subject = 
> Subject.getSubject(AccessController.getContext());
>      return Optional.ofNullable(subject);
>    }
>  }
> 
> Another future proof using Subject.current().
> 
> Question:
> 
> Are the changes proposed here going to break all this for me?

Reply via email to