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?