Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pipeline {

parameters {
choice(name: 'nodeLabel', choices: ['ubuntu', 's390x', 'arm', 'Windows'])
choice(name: 'jdkVersion', choices: ['jdk_17_latest', 'jdk_21_latest', 'jdk_24_latest', 'jdk_17_latest_windows', 'jdk_21_latest_windows', 'jdk_24_latest_windows'])
choice(name: 'jdkVersion', choices: ['jdk_17_latest', 'jdk_21_latest', 'jdk_25_latest', 'jdk_17_latest_windows', 'jdk_21_latest_windows', 'jdk_25_latest_windows'])
booleanParam(name: 'deployEnabled', defaultValue: false)
booleanParam(name: 'sonarEnabled', defaultValue: false)
booleanParam(name: 'testsEnabled', defaultValue: true)
Expand Down Expand Up @@ -72,12 +72,12 @@ pipeline {
}
}

stage('Build JDK 24') {
stage('Build JDK 25') {
tools {
jdk "jdk_24_latest"
jdk "jdk_25_latest"
}
steps {
echo 'Building JDK 24'
echo 'Building JDK 25'
sh 'java -version'
sh 'mvn -version'
sh 'mvn -U -B -e clean install -DskipTests'
Expand Down
4 changes: 4 additions & 0 deletions activemq-broker/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-compat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-openwire-legacy</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
*/
package org.apache.activemq.broker.jmx;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.Principal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.activemq.broker.util.AuditLogEntry;
import org.apache.activemq.broker.util.AuditLogService;
import org.apache.activemq.broker.util.JMXAuditLogEntry;
import org.apache.activemq.compat.sm.SecurityManagerShim;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
Expand All @@ -33,12 +32,12 @@
import javax.management.ReflectionException;
import javax.management.StandardMBean;
import javax.security.auth.Subject;

import org.apache.activemq.broker.util.AuditLogEntry;
import org.apache.activemq.broker.util.AuditLogService;
import org.apache.activemq.broker.util.JMXAuditLogEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
* MBean that looks for method/parameter descriptions in the Info annotation.
Expand Down Expand Up @@ -205,8 +204,7 @@ public Object invoke(String s, Object[] objects, String[] strings) throws MBeanE
objects = (objects == null) ? new Object[]{} : objects;
JMXAuditLogEntry entry = null;
if (audit != OFF) {
// [AMQ-9563] TODO: JDK 21 use Subject.current() instead
Subject subject = Subject.getSubject(AccessController.getContext());
Subject subject = SecurityManagerShim.currentSubject();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need the shim? I'm wondering if we just ship two AnnotatedBean classes using MR jar and switch the JAAS API implementation when getting the Subject.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are no other SM / related API usage to handle then you wouldn't need it all, just the Subject method.

However I'm not seeing how duplicating a sizable complex class that may need to be updated, just to change a couple lines, would really be better than having 2 new tiny classes , that likely won't ever change, to do the switch out and avoid the need to duplicate the complex class?

For sure the classes don't need to be in their own module if that's what you dislike about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only need a small part of the Shim around handling Subject then we should just use that piece for now to keep the changes minimal.

String caller = "anonymous";
if (subject != null) {
caller = "";
Expand Down
2 changes: 1 addition & 1 deletion activemq-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
<argLine>${surefire.argLine}</argLine>
<runOrder>alphabetical</runOrder>
<systemPropertyVariables>
<org.apache.activemq.default.directory.prefix>target</org.apache.activemq.default.directory.prefix>
<org.apache.activemq.default.directory.prefix>target/</org.apache.activemq.default.directory.prefix>
<!-- Uncomment the following if you want to configure custom logging
(using src/test/resources/log4j.properties) while running mvn:test Note: if you want
to see log messages on the console window remove "redirectTestOutputToFile" from
Expand Down
87 changes: 87 additions & 0 deletions activemq-compat/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>6.2.1-SNAPSHOT</version>
</parent>

<artifactId>activemq-compat</artifactId>
<packaging>bundle</packaging>
<name>ActiveMQ :: Compat</name>
<description>The ActiveMQ Compatibility (MRJAR)</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
!java.*,
!javax.naming*,
!javax.net*,
!javax.security*,
!org.apache.activemq*,
*
</Import-Package>
<Multi-Release>true</Multi-Release>
<_noee>true</_noee>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>jdk24-plus</id>
<activation>
<jdk>[24,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>java24-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>24</release> <!-- Specific Java version for alternative classes -->
<compileSourceRoots>${project.basedir}/src/main/java24</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.compat.sm;

import javax.security.auth.Subject;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;

/*
* SecurityManager related shim.
* This specific class uses legacy methods toward usage on Java 17 - 23.
*
* The API of this class must be kept the same as the Java 24+ implementation
* variant of this class which can be found at:
* src/main/java24/org/apache/activemq/artemis/utils/sm/SecurityManagerShim.java
Comment on lines +31 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the Javadoc in this class is inaccurate now as you havent updated it to reflect how/where it is being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, JIRA was out yesterday, but I can create the issue. Need to check with @jbonofre if there is a parent issue I need to create a sub-task.
And also yes, I need to update the entire javadoc. That was a plain copy to follow up on the email thread.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the ASF has been under DDoS attack for the last couple days, but Jira would usually load after another attempt or two if it failed initially.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeanouii no need to do a JIRA. Keep the convo here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Jira is for issue and commit tracking, not discussion of the code. Changes to make things work on Java 24+ when they don't currently, seems pretty clearly deserving of being committed against a Jira. Almost everything should be.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is definitely going to need a Jira before it is merged but that can be done before it is ready to merge

*
* Did not use a shared interface since the shim seems unlikely to be changed much,
* other than future removals, and doing so would need singleton instance indirection
* at every call site to access the purely static onward methods being called.
*/
@SuppressWarnings("removal")
public class SecurityManagerShim {

/**
* Returns the current associated subject.
* <p>
* On Java 17-23, retrieves the current AccessControlContext by calling
* {@code AccessController.getContext()} and then returns result of method
* {@code Subject.getSubject(accessControlContext)}.
* <p>
* On Java 24+, returns result of method {@code Subject.current()}.
*
* @return the current associated subject, or null if none was found.
*/
public static Subject currentSubject() {
AccessControlContext accessControlContext = AccessController.getContext();
if (accessControlContext != null) {
return Subject.getSubject(accessControlContext);
}
return null;
}

/**
* Perform work as a particular {@code Subject}.
* <p>
* On Java 17-23, wraps the given {@code callable} as a {@code PrivilegedExceptionAction} and executes it
* via {@code Subject.doAs(final Subject subject, final java.security.PrivilegedExceptionAction<T> action)}.
* <p>
* On Java 24+, returns result of calling {@code Subject.callAs(final Subject subject,
* final Callable<T> action)}.
* <p>
* Any exceptions thrown by the {@code callable.call()} will result in a {@code CompletionException} being
* thrown with the original exception as its cause.
*
* @param subject the {@code Subject} that the given {@code callable} will run as, may be null.
* @param callable the {@code Callable} to be run, must not be {@code null}.
* @param <T> the type of value returned by the {@code callable}.
* @return the value returned by the {@code callable}.
* @throws NullPointerException if {@code callable} is {@code null}.
* @throws CompletionException if {@code callable.call()} throws an exception.
* The cause is set to the exception thrown by {@code callable.call()}.
*/
public static <T> T callAs(final Subject subject, final Callable<T> callable) throws CompletionException {
// Subject is allowed to be null
Objects.requireNonNull(callable, "callable must be provided");

try {
final PrivilegedExceptionAction<T> pa = () -> callable.call();

return Subject.doAs(subject, pa);
} catch (PrivilegedActionException e) {
throw new CompletionException(e.getCause());
} catch (Exception e) {
throw new CompletionException(e);
}
}

/**
* Returns whether a SecurityManager is enabled.
* <p>
* On Java 17-23, returns whether result of check: {@code System.getSecurityManager() != null}.
* <p>
* On Java 24+, returns false as a SecurityManager can never be present.
*
* @return true if a SecurityManager is present, or false otherwise.
*/
public static boolean isSecurityManagerEnabled() {
return System.getSecurityManager() != null;
}

/**
* Returns the current AccessControlContext.
* <p>
* On Java 17-23, returns the result of {@code AccessController.getContext()}.
* <p>
* On Java 24+, always returns null.
*
* @return the current AccessControlContext, or null if none.
*/
public static Object getAccessControlContext() {
return AccessController.getContext();
}

/**
* Performs the specified {@code PrivilegedAction}.
* <p>
* On Java 17-23, returns the result of passing the given {@code action} to the
* {@code AccessController.doPrivileged(PrivilegedAction<T> action)} method.
* <p>
* On Java 24+, returns the result of running {@code action.run()} directly.
* <p>
* If the action's {@code run} method throws an unchecked exception it will
* propagate through this method.
*
* @param action the {@code PrivilegedAction} to be run, must not be {@code null}.
* @param <T> the type of value returned by the {@code action}.
* @return the value returned by the {@code action}.
* @throws NullPointerException if {@code action} is {@code null}.
*/
public static<T> T doPrivileged(final PrivilegedAction<T> action) {
Objects.requireNonNull(action, "action must be provided");

return AccessController.doPrivileged(action);
}

/**
* Performs the specified {@code PrivilegedAction}.
* <p>
* On Java 17-23, returns the result of calling the
* {@code AccessController.doPrivileged(PrivilegedAction<T> action, AccessControlContext context)}
* method with the given {@code action} and {@code accessControlContext}.
* <p>
* On Java 24+, returns the result of running {@code action.run()} directly,
* ignoring the accessControlContext parameter.
*
* If the action's {@code run} method throws an unchecked exception it will
* propagate through this method.
*
* @param action the {@code PrivilegedAction} to be run, must not be {@code null}.
* @param accessControlContext the {@code AccessControlContext} object, may be null.
* @param <T> the type of value returned by the {@code action}.
* @return the value returned by the {@code action}.
* @throws NullPointerException if {@code action} is {@code null}.
*/
public static<T> T doPrivileged(final PrivilegedAction<T> action, final Object accessControlContext) {
// AccessControlContext may be null
Objects.requireNonNull(action, "action must be provided");

final AccessControlContext acc = AccessControlContext.class.cast(accessControlContext);

return AccessController.doPrivileged(action, acc);
}

/**
* Performs the specified {@code PrivilegedExceptionAction}.
* <p>
* On Java 17-23, returns the result of calling
* {@code AccessController.doPrivileged(PrivilegedExceptionAction<T> action)}
* with the given {@code exceptionAction}.
* <p>
* On Java 24+, returns the result of running {@code exceptionAction.run()} directly.
* <p>
* If the action's {@code run} method throws an unchecked exception it will
* propagate through this method.
*
* @param exceptionAction the {@code PrivilegedExceptionAction} to be run, must not be {@code null}.
* @param <T> the type of value returned by the {@code exceptionAction}.
* @return the value returned by the {@code action}.
* @throws NullPointerException if {@code exceptionAction} is {@code null}.
* @throws PrivilegedActionException if {@code exceptionAction.run()} throws a checked exception.
* The cause is set to the exception thrown {@code callable.call()}.
*/
public static <T> T doPrivileged(final PrivilegedExceptionAction<T> exceptionAction) throws PrivilegedActionException {
Objects.requireNonNull(exceptionAction, "exceptionAction must be provided");

return AccessController.doPrivileged(exceptionAction);
}

}
Loading