Code Monkey home page Code Monkey logo

alpine's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

alpine's Issues

FORCE_PASSWORD_CHANGE Exception Not Thrown if LDAP Authentication is Enabled

After an initial deployment of dependency-track its is not possible to authenticate as the default admin due to the FORCE_PASSWORD_CHANGE exception never being thrown and LDAP authentication is attempted instead.

https://github.com/stevespringett/Alpine/blob/master/alpine/src/main/java/alpine/auth/Authenticator.java#L67

 }catch(AlpineAuthenticationException e){
             // If LDAP is enabled, a second attempt to authenticate the credentials will be made against LDAP so we skip this validation exception. 
            if (!LDAP_ENABLED) {
                throw e;
              }
        }

As stated in the code comment all ManagedUser exceptions are suppressed and never thrown if LDAP authentication is enabled.

Suggestion is to create different Exception types for different authentication errors.

Add support for Java 9 Flow API

As of this ticket, Java 9 is still in development, but the Flow API (Reactive Extensions) is expected to be included. Abstract this out so that existing apps built on Alpine continue to work, but under the covers it's using Flow API as an implementation rather than it's own.

Upgrade Surefire Plugin from 2.22.2 to Latest 3.x

Alpine currently uses maven-surefire-plugin v2.22.2, the last 2.x release.

This plugin is not compatible with upcoming Maven 4.0.0 and should be upgraded to 3.x. Currently, the most recent plugin release is v3.2.5

Running a build with parameter: -Dmaven.plugin.validation=verbose provides the following warnings for v2.22.2

 * org.apache.maven.plugins:maven-surefire-plugin:2.22.2
  Declared at location(s):
   * xxx
  Used in module(s):
   * yyy
  Plugin issue(s):
   * Plugin is a Maven 2.x plugin, which will be not supported in Maven 4.x
   * Plugin depends on plexus-container-default, which is EOL
  Mojo issue(s):
   * Mojo surefire:test (org.apache.maven.plugin.surefire.SurefirePlugin)
     - Parameter 'localRepository' uses deprecated parameter expression '${localRepository}': ArtifactRepository type is deprecated and its use in Mojos should be avoided.

I am logging this as an issue rather than simply providing a PR that updates the version in the POM as I am not a dev and @stevespringett reports that a previous attempt to upgrade the plugin gave problems and was aborted.

Log IP / User Agent for invalid ApiKeys and JWTs

Currently when an invalid ApiKey or JWT is provided, only the string Invalid API key asserted or Invalid JWT asserted is logged.

final ApiKeyAuthenticationService apiKeyAuthService = new ApiKeyAuthenticationService(request);
if (apiKeyAuthService.isSpecified()) {
try {
principal = apiKeyAuthService.authenticate();
} catch (AuthenticationException e) {
LOGGER.info(SecurityMarkers.SECURITY_FAILURE, "Invalid API key asserted");
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
return;
}
}
final JwtAuthenticationService jwtAuthService = new JwtAuthenticationService(request);
if (jwtAuthService.isSpecified()) {
try {
principal = jwtAuthService.authenticate();
} catch (AuthenticationException e) {
LOGGER.info(SecurityMarkers.SECURITY_FAILURE, "Invalid JWT asserted");
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
return;
}
}

Suggested change is to log also IP and User Agent, similar to other security events being logged.

I tried a quick PR to do the as in AlpineResource but not sure if injecting a HttpServletRequest here is appropiate. Maybe a global logSecurityEvent utility method should be made supporting all scenario's.

/**
* Logs a security event to the security audit log. Expects one of:
* {@link SecurityMarkers#SECURITY_AUDIT}
* {@link SecurityMarkers#SECURITY_SUCCESS}
* {@link SecurityMarkers#SECURITY_FAILURE}
* @param logger the logger to use
* @param marker the marker to add to the event
* @param message the initial content of the event
* @since 1.0.0
*/
protected void logSecurityEvent(final Logger logger, final Marker marker, final String message) {
if (!(SecurityMarkers.SECURITY_AUDIT == marker ||
SecurityMarkers.SECURITY_SUCCESS == marker ||
SecurityMarkers.SECURITY_FAILURE == marker)) {
return;
}
final StringBuilder sb = new StringBuilder();
sb.append(message).append(" ");
if (getPrincipal() != null) {
sb.append("by: ").append(getPrincipal().getName()).append(" ");
}
sb.append("/ IP Address: ").append(getRemoteAddress()).append(" ");
sb.append("/ User Agent: ").append(getUserAgent());
logger.info(marker, sb.toString());
}

Support Permission Annotations

Each REST resource can be annotated with a permission required. This feature needs to be completed including the data model and filter.

Expose database properties outside of WAR

persistence.xml currently is used by Alpine applications to define both the classes needing enhancing as well as datastore properties. Properties include items that should be configurable including URL, driver, and username/password.

For executable WARs (including Docker containers), modifying the WAR is not feasible so configuring the database is not easily achieved.

Move datastore configuration to application properties to resolve this limitation.

Add dynamic JWT Token expiry time

Currently, the expiration time for JWT tokens is hardcoded to 7 days in the code. To enhance security measures, it is recommended to allow specifying the expiration time in minutes or hours dynamically.

public String createToken(final Principal principal, final List<Permission> permissions, final IdentityProvider identityProvider) {
    final Date today = new Date();
    final JwtBuilder jwtBuilder = Jwts.builder();
    jwtBuilder.setSubject(principal.getName());
    jwtBuilder.setIssuer(ISSUER);
    jwtBuilder.setIssuedAt(today);
    jwtBuilder.setExpiration(addDays(today, 7)); // Hardcoded expiration time

    // ... (additional code)

    // Request: Allow dynamic setting of token expiration time (in minutes or hours)
}

Please consider implementing this enhancement for better flexibility and security in managing JWT token expiration times. Feel free to reach out if further clarification.

Feel free to add specific implementation approaches in the comments, and I will try to create a PR by myself as soon as possible.

Best
DoPaNik

Add getTeams() to Principal contract

Rational: Common to ApiKey and UserPrincipal.

OO simplification to avoid this type of ugly code:

            final List<Team> teams;
            if (principal instanceof UserPrincipal) {
                final UserPrincipal userPrincipal = ((UserPrincipal) principal);
                teams = userPrincipal.getTeams();
         
            } else {
                final ApiKey apiKey = ((ApiKey) principal);
                teams = apiKey.getTeams();
            }

Add create and last used timestamps for API Keys

Current Behavior in Dependency Track:

The /team API returns a list of API Keys assigned to a team, but does not provide a timestamp for when each key was created or last accessed. This information is needed to enforce API Key rotation schemas.

...
"apiKeys": [
{
"key": "string"
}
]
Proposed Behavior:

...
"apiKeys": [
{
"key": "string",
"createdAt": "2021-06-09T18:18:21.710Z",
"lastUsed": "2021-06-09T18:18:21.710Z"
}
]

Ignore PartialResultException when querying groups via LDAP from Active Directory

Issue Type:

  • defect report
  • enhancement request

Current Behavior:

The following error occurs while dependency-track queries the group filters:

Error occurred during LDAP synchronizationjavax.naming.PartialResultException: Unprocessed Continuation Reference(s)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2917)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2891)
    at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.getNextBatch(AbstractLdapNamingEnumeration.java:148)
    at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.hasMoreImpl(AbstractLdapNamingEnumeration.java:217)
    at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.hasMore(AbstractLdapNamingEnumeration.java:189)
    at alpine.auth.LdapConnectionWrapper.getGroups(LdapConnectionWrapper.java:138)
    at alpine.tasks.LdapSyncTask.sync(LdapSyncTask.java:97)
    at alpine.tasks.LdapSyncTask.inform(LdapSyncTask.java:62)
    at alpine.event.framework.BaseEventService.lambda$publish$0(BaseEventService.java:96)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

The LDAP server is Active Directory.

Steps to Reproduce (if defect):

Related configuration properties:

alpine.ldap.enabled=true
alpine.ldap.server.url=ldaps://ad-server.hostname
alpine.ldap.domain=domain.net
alpine.ldap.basedn=DC=domain,DC=private
alpine.ldap.security.auth=simple
[email protected]
alpine.ldap.bind.password=pw
alpine.ldap.auth.username.format=%[email protected]
alpine.ldap.attribute.name=userPrincipalName
alpine.ldap.attribute.mail=mail
alpine.ldap.groups.filter=(&(objectClass=group)(objectCategory=Group))
alpine.ldap.user.groups.filter=(member:1.2.840.113556.1.4.1941:={USER_DN})
alpine.ldap.user.provisioning=true
alpine.ldap.team.synchronization=true

The error occurs, when a user tries to login.
Unfortunately, I cannot share the Active Directory Server configuration.
I think the error should occur for every Active Directory response that has a Referral.

Expected Behavior:

Add a configuration option to let alpine ignore this Exception.

Environment:

  • Dependency-Track Version: 3.3.1
  • Distribution: [ Docker ]

Other Details:

According to https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html, the value of Context.REFERRAL is by default set to IGNORE which means that the LDAP server should not send referrals. However, Active Directory does not support this (see last sentence on the page), and thus the exception is thrown when calling ne.hasMore.

compile on windows

Hi,

In order to compile on windows, data-nucleus plugin needs fork option to be false. Otherwise it breaks the build by an too many arguments error. Could you please add a profile for windows builds.

org.apache.maven.plugins maven-compiler-plugin ${maven.compiler.plugin.version} ${maven.compiler.source} ${maven.compiler.target} -Xlint:all -Xlint:-processing -Xlint:-serial -Werror org.apache.maven.plugins maven-surefire-plugin ${maven.surefire.plugin.version} org.datanucleus datanucleus-maven-plugin ${maven.datanucleus.plugin.version} JDO Alpine true false compile enhance

java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 2

GA-Releases of Java 10 and newer will trigger this error because their version contain only the major version and no minor or patch level.

GA-Release

java -version
java version "15" 2020-09-15
Java(TM) SE Runtime Environment (build 15+36-1562)
Java HotSpot(TM) 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)

first patch level

java -version
java version "11.0.8" 2020-07-14 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.8+10-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode)

stacktrace from Dependency Track 3.8

2020-10-21 12:15:33,402 [] WARN [org.eclipse.jetty.util.component.AbstractLifeCycle] FAILED ListenerHolder@589da3f3{FAILED}: org.dependencytrack.event.EventSubsystemInitializer: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError: null
	at alpine.Config.<clinit>(Config.java:60)
	at alpine.util.ThreadUtil.determineNumberOfWorkerThreads(ThreadUtil.java:43)
	at alpine.event.framework.EventService.<clinit>(EventService.java:51)
	at org.dependencytrack.event.EventSubsystemInitializer.<clinit>(EventSubsystemInitializer.java:60)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:64)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
	at org.eclipse.jetty.server.handler.ContextHandler$StaticContext.createInstance(ContextHandler.java:2787)
	at org.eclipse.jetty.servlet.ServletContextHandler$Context.createInstance(ServletContextHandler.java:1280)
	at org.eclipse.jetty.server.handler.ContextHandler$StaticContext.createListener(ContextHandler.java:2798)
	at org.eclipse.jetty.servlet.ListenerHolder.doStart(ListenerHolder.java:92)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
	at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:350)
	at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1445)
	at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1409)
	at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:825)
	at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:275)
	at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:524)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
	at org.eclipse.jetty.server.Server.start(Server.java:407)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:110)
	at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
	at org.eclipse.jetty.server.Server.doStart(Server.java:371)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
	at alpine.embedded.EmbeddedJettyServer.main(EmbeddedJettyServer.java:93)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 2
	at alpine.util.JavaVersion.<init>(JavaVersion.java:49)
	at alpine.util.JavaVersion.<init>(JavaVersion.java:36)
	at alpine.util.SystemUtil.<clinit>(SystemUtil.java:48)

Add ability to customize the Micrometer `MeterRegistry`

Micrometer allows for customization of its MeterRegistry via MeterFilters.

Filters can be used for various things, but one important capability is to omit, rewrite, or add tags to all metrics.

In order for MeterFilters to work, they need to be registered before all Meters. Because Alpine does a large chunk of initialization at class loading time, it is currently not possible to add filters in a way that guarantees that they'll be applied to all Meters.

ExecutorService metrics for example are registered in a static { } block. If the EventService class is loaded prior to the class adding filters to the registry, the filters will not be applied to ExecutorService metrics.

EXECUTOR = Executors.newFixedThreadPool(ThreadUtil.determineNumberOfWorkerThreads(), factory);
INSTANCE.setExecutorService(EXECUTOR);
INSTANCE.setLogger(LOGGER);
Metrics.registerExecutorService(EXECUTOR, EXECUTOR_NAME);

Provide a mechanism similar to Spring Boot's MeterRegistryCustomizer.

Configuration for LDAP

I am not arrived to configure LDAP in the application.properties file.
however, I can do a search via ldapsearch

ldapsearch -l 0 -d 0 -vvvv -H ldap://myldap:389/ -b "ou=people,dc=domain,dc=com" -D "uid=myaccess,ou=functionalaccounts,dc=domain,dc=com" -W  "uid=myid"

Can you help me ?

Add support for JWT authorization via cookie

Currently, JWT authorization is limited to use of the 'Authorization' header where the JWT token is the Bearer. This ticket is to add an enhancement for allowing the JWT to also appear in a cookie named 'Authorization-Token'. If this cooke exists, the value was be used, if the cookie does not exist, the existing logic to check the 'Authorization' header should be used.

Treat API key as secret and store them securely

Team API keys should be treated as a secret and not stored in plaintext, instead stored as and compared against the hash. They should not be available on UI like currently in Dependency-Track, except once when generating them. Instead they should get a name and only the name be displayed in UI, to allow identify & delete them.

Save and load `SecretKey` using encoded byte array instead of Java Object Serialization

The SecretKey used for data encryption is currently stored and loaded using Java's object serialization (ObjectInputStream and ObjectOutputStream). This is contrasted by the public-private-keypair that is stored in encoded form as byte array.

public void save(final SecretKey key) throws IOException {
final File keyFile = getKeyPath(key);
keyFile.getParentFile().mkdirs(); // make directories if they do not exist
try (OutputStream fos = Files.newOutputStream(keyFile.toPath());
ObjectOutputStream oout = new ObjectOutputStream(fos)) {
oout.writeObject(key);
}
}

private SecretKey loadSecretKey() throws IOException, ClassNotFoundException {
final File file = getKeyPath(KeyType.SECRET);
SecretKey key;
try (InputStream fis = Files.newInputStream(file.toPath());
ObjectInputStream ois = new ObjectInputStream(fis)) {
key = (SecretKey) ois.readObject();
}
return this.secretKey = key;
}

By using Java Object Serialization, it's not possible to supply a key that has been generated outside of Alpine, or more generally outside of Java (e.g. via openssl rand 32).

For deployment scenarios where multiple applications or instances based on Alpine are working on the same data, it is necessary to generate the keys prior to deployment, and share it across instances.

The secret key saving and loading should be rewritten to handle generic byte arrays, like so:

public void saveEncoded(final SecretKey key) throws IOException {
    final File keyFile = getKeyPath(key);
    keyFile.mkdirs();
    try (OutputStream fos = Files.newOutputStream(keyFile.toPath())) {
        fos.write(key.getEncoded());
    }
}

SecretKey loadEncodedSecretKey() throws IOException {
    final File file = getKeyPath(KeyType.SECRET);
    try (InputStream fis = Files.newInputStream(file.toPath())) {
        final byte[] encodedKey = fis.readAllBytes();
        return this.secretKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }
}

I figure there will need to be some automatic migration logic for existing instances using Alpine, such that the legacy key format would automatically be converted to the new one.

Load postgresql jdbc driver failed

We know the alpine supports the JDK 8 well, how to support the JDK 11? This issue is in JDK 11.

2020-11-30 22:37:11,083 [] INFO [org.eclipse.jetty.util.log] Logging initialized @327ms to org.eclipse.jetty.util.log.Slf4jLog
2020-11-30 22:37:11,244 [] WARN [org.eclipse.jetty.server.Server] ErrorPageMapper not supported for Server level Error Handling
2020-11-30 22:37:11,245 [] INFO [org.eclipse.jetty.server.Server] jetty-9.4.34.v20201102; built: 2020-11-02T14:15:39.302Z; git: e46af88704a893fc12cb0e3bf46e2c7b48a009e7; jvm 1.8.0-262-b10
2020-11-30 22:37:28,691 [] INFO [org.eclipse.jetty.server.session] DefaultSessionIdManager workerName=node0
2020-11-30 22:37:28,691 [] INFO [org.eclipse.jetty.server.session] No SessionScavenger set, using defaults
2020-11-30 22:37:28,693 [] INFO [org.eclipse.jetty.server.session] node0 Scavenging every 660000ms
2020-11-30 22:43:20,787 [] INFO [org.eclipse.jetty.util.log] Logging initialized @317ms to org.eclipse.jetty.util.log.Slf4jLog
2020-11-30 22:43:20,943 [] WARN [org.eclipse.jetty.server.Server] ErrorPageMapper not supported for Server level Error Handling
2020-11-30 22:43:20,945 [] INFO [org.eclipse.jetty.server.Server] jetty-9.4.34.v20201102; built: 2020-11-02T14:15:39.302Z; git: e46af88704a893fc12cb0e3bf46e2c7b48a009e7; jvm 1.8.0-262-b10
2020-11-30 22:43:37,914 [] INFO [org.eclipse.jetty.server.session] DefaultSessionIdManager workerName=node0
2020-11-30 22:43:37,914 [] INFO [org.eclipse.jetty.server.session] No SessionScavenger set, using defaults
2020-11-30 22:43:37,916 [] INFO [org.eclipse.jetty.server.session] node0 Scavenging every 660000ms
2020-11-30 23:24:41,602 [] INFO [org.eclipse.jetty.server.handler.ContextHandler] Started o.e.j.w.WebAppContext@4baf3987{/,file:///C:/Users/mxiao/AppData/Local/Temp/jetty-0_0_0_0-8080-dependency-track-embedded_war--any-3787831117176657565/webapp/,AVAILABLE}{file:/C:/Users/mxiao/code/dependency-track/target/dependency-track-embedded.war}
2020-11-30 23:24:41,626 [] INFO [org.eclipse.jetty.server.AbstractConnector] Started ServerConnector@343f4d3d{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2020-11-30 23:24:41,627 [] INFO [org.eclipse.jetty.server.Server] Started @2481160ms
2020-12-01 00:05:18,635 [] INFO [org.eclipse.jetty.server.AbstractConnector] Stopped ServerConnector@343f4d3d{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2020-12-01 00:05:18,635 [] INFO [org.eclipse.jetty.server.session] node0 Stopped scavenging
2020-12-01 00:05:18,665 [] INFO [org.eclipse.jetty.server.handler.ContextHandler] Stopped o.e.j.w.WebAppContext@4baf3987{/,file:///C:/Users/mxiao/AppData/Local/Temp/jetty-0_0_0_0-8080-dependency-track-embedded_war-
-any-3787831117176657565/webapp/,STOPPED}{file:/C:/Users/mxiao/code/dependency-track/target/dependency-track-embedded.war}
2020-12-01 00:07:26,922 [] INFO [org.eclipse.jetty.util.log] Logging initialized @425ms to org.eclipse.jetty.util.log.Slf4jLog
2020-12-01 00:07:27,025 [] WARN [org.eclipse.jetty.server.Server] ErrorPageMapper not supported for Server level Error Handling
2020-12-01 00:07:27,026 [] INFO [org.eclipse.jetty.server.Server] jetty-9.4.34.v20201102; built: 2020-11-02T14:15:39.302Z; git: e46af88704a893fc12cb0e3bf46e2c7b48a009e7; jvm 11+28
2020-12-01 00:07:47,168 [] INFO [org.eclipse.jetty.server.session] DefaultSessionIdManager workerName=node0
2020-12-01 00:07:47,169 [] INFO [org.eclipse.jetty.server.session] No SessionScavenger set, using defaults
2020-12-01 00:07:47,170 [] INFO [org.eclipse.jetty.server.session] node0 Scavenging every 600000ms
2020-12-01 00:07:47,189 [] WARN [org.eclipse.jetty.webapp.WebAppContext] Failed startup of context o.e.j.w.WebAppContext@616fe72b{/,file:///C:/Users/mxiao/AppData/Local/Temp/jetty-0_0_0_0-8080-dependency-track-embedded_war-_-any-6145086392483730595/webapp/,UNAVAILABLE}{file:/C:/Users/mxiao/code/dependency-track/target/dependency-track-embedded.war}
java.lang.IllegalArgumentException: object is not an instance of declaring class
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at alpine.Config.expandClasspath(Config.java:510)
at alpine.Config.expandClasspath(Config.java:492)
at org.dependencytrack.upgrade.UpgradeInitializer.contextInitialized(UpgradeInitializer.java:56)
at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:1068)
at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:572)
at org.eclipse.jetty.server.handler.ContextHandler.contextInitialized(ContextHandler.java:997)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:746)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:379)
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1457)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1422)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:911)
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:288)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:524)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
at org.eclipse.jetty.server.Server.start(Server.java:423)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:110)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
at org.eclipse.jetty.server.Server.doStart(Server.java:387)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at alpine.embedded.EmbeddedJettyServer.main(EmbeddedJettyServer.java:98)
2020-12-01 00:07:47,219 [] INFO [org.eclipse.jetty.server.AbstractConnector] Started ServerConnector@68567e20{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2020-12-01 00:07:47,220 [] INFO [org.eclipse.jetty.server.Server] Started @20726ms

Migrate to Jakarta EE namespace

The current stack is based on:

  • Java EE (javax.servlet.* namespace)
  • Jersey 2.x
  • Jetty 9.x

Community support for Jetty 9.x has ended as of June 1st 2022. There will still be security patches, but it's a good indicator that we should look into updating it. Jetty 11, the latest major release of Jetty, does not support legacy Java EE APIs anymore and is based on the new Jakarta EE APIs instead.

The move to Jakarta requires an upgrade of Jersey to 3.x (migration guide here).

I'm sure there are more dependencies and breaking changes that will pop up once work on this is started.

Add metrics and related endpoints

Add metrics and related endpoints similar to what DropWizard or SpringBoot provides.

  • /auditevents - should return the contents of dependency-track-audit.log
  • /env - should return all environment variables and Java system properties
  • /health - should return various high-level health info
  • /logfile - should return the contents of dependency-track.log
  • /metrics - should return details metrics to measure system performance

Alpine should contain an AbstractMetricsResource with implementations of the above endpoints. Each application that is built on Alpine would simply extend AbstractMetricsResource so that the app can specify what permissions are necessary for each.

NOTE: It may be possible to simply include Dropwizard Metrics for /health and /metrics capabilities as the module seems to be standalone with minimal dependencies.

Add an OIDC default group

It's quite possible that the group management for some applications may happen mostly inside the application itself - not every organisation has the slick automation (xor the slow bureacracy) to manage teams purely in AD / Okta / etc.

For organisations that are happy to manage users within an application, it would be useful to be able to assign a default group to give a good first-login experience, that allows application administrators to grab that user and level their permissions or team memberships appropriately.

Suggest the framework adds a new environment variable:

  • OIDC_TEAMS_DEFAULT (string, cannot be present if OIDC_TEAMS_CLAIM is is present)

And any user profile's groups list will be set as a list containing this string.

Provide a means to disable or otherwise configure the DataNucleus L2 cache

As identified in DependencyTrack/dependency-track#218 and DependencyTrack/dependency-track#903, the DataNucleus L2 cache is one of the areas that can prevent Alpine-based applications from being horizontally scalable or HA.

The L2 cache is currently enabled per default. This means that all objects written to the datastore will be cached in-memory:

Objects are placed in the L2 cache when you commit() the transaction of a PersistenceManager. This means that you only have datastore-persisted objects in that cache. Also, if an object is deleted during a transaction then at commit it will be removed from the L2 cache if it is present.

While this behavior works fine for normal CRUD-type applications, it does not for applications like Dependency-Track, that regularly iterate over multiple hundreds of thousands (or millions) of records, and modify them. With record sets in such high numbers, the cost-to-benefit ratio is simply not good.

For applications like Dependency-Track, global usage of the L2 cache is skyrocketing RAM usage, and puts unnecessary pressure on the GC.

Additionally, the L2 cache is only effective when records are fetched by their primary key. In modern applications, lookups by primary key are very rare, as most of them use secondary IDs intended for external consumption (e.g. UUIDs).

In order to support horizontal scalability, high availability, and a generally reduced resource footprint, it should be possible to globally disable the DataNucleus L2 cache.

As a nice-to-have, additional configuration options may be introduced to allow for usage of distributed caches like Redis or Hazelcast (which is supported by DN). Users wishing to utilize these integrations may do so.

Update to Java 17

Besides the performance improvements and syntactic sugar introduced in Java 17 over Java 11, we should try to stay current by using the latest LTS release. There are some minor roadblocks when building with Java 17 right now. The main blocker right now is DataNucleus not supporting Java 17 in a stable version yet.

I tried to move Alpine and Dependency-Track to Java 17, here's what I've found so far:

  • Update to DataNucleus 6
    • Bytecode Enhancement for Java >= 16 is available since 6.0.0-m1 (datanucleus/datanucleus-core#359)
    • With 6.0.0-m4, build and test run fine. Dependency-Track works as expected as well. Doesn't look like there's much migration work to be done.
  • The --illegal-access flag has been deprecated and doesn't have an effect anymore. This change mostly affects tests as far as I could tell. For example those that try to modify environment variables in some way:
    ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.054 s <<< FAILURE! - in alpine.common.util.ThreadUtilTest
    [ERROR] determineNumberOfWorkerThreadsTest(alpine.common.util.ThreadUtilTest)  Time elapsed: 0.008 s  <<< ERROR!
    java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module @7530d0a
    
    • This is fixable by adding the following configuration to the surefire plugin:
      <argLine>--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED</argLine>

Incorrect Package for java.naming.ldap.factory.socket, DependencyTrack LDAP Connection failures.

env.put("java.naming.ldap.factory.socket", "alpine.crypto.RelaxedSSLSocketFactory");

dtrack-apiserver_1 | javax.naming.CommunicationException: <domain>:<port> dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.Connection.<init>(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapClient.<init>(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapClient.getInstance(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtx.connect(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtx.<init>(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxFromUrl(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(Unknown Source) dtrack-apiserver_1 | at java.naming/javax.naming.spi.NamingManager.getInitialContext(Unknown Source) dtrack-apiserver_1 | at java.naming/javax.naming.InitialContext.getDefaultInitCtx(Unknown Source) dtrack-apiserver_1 | at java.naming/javax.naming.InitialContext.init(Unknown Source) dtrack-apiserver_1 | at java.naming/javax.naming.InitialContext.<init>(Unknown Source) dtrack-apiserver_1 | at java.naming/javax.naming.directory.InitialDirContext.<init>(Unknown Source) dtrack-apiserver_1 | at alpine.server.auth.LdapConnectionWrapper.createDirContext(LdapConnectionWrapper.java:128) dtrack-apiserver_1 | at alpine.server.tasks.LdapSyncTask.inform(LdapSyncTask.java:59) dtrack-apiserver_1 | at alpine.event.framework.BaseEventService.lambda$publish$0(BaseEventService.java:99) dtrack-apiserver_1 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) dtrack-apiserver_1 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) dtrack-apiserver_1 | at java.base/java.lang.Thread.run(Unknown Source) dtrack-apiserver_1 | Caused by: java.lang.ClassNotFoundException: alpine.crypto.RelaxedSSLSocketFactory dtrack-apiserver_1 | at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source) dtrack-apiserver_1 | at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source) dtrack-apiserver_1 | at java.base/java.lang.ClassLoader.loadClass(Unknown Source) dtrack-apiserver_1 | at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:511) dtrack-apiserver_1 | at java.base/java.lang.ClassLoader.loadClass(Unknown Source) dtrack-apiserver_1 | at java.base/java.lang.Class.forName0(Native Method) dtrack-apiserver_1 | at java.base/java.lang.Class.forName(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.VersionHelper.loadClass(Unknown Source) dtrack-apiserver_1 | at java.naming/com.sun.jndi.ldap.Connection.createSocket(Unknown Source) dtrack-apiserver_1 | ... 21 common frames omitted

Add support for logging in JSON format

To make parsing in centralized logging solutions like ELK or Splunk easier, applications built on Alpine should be able to emit their logs in JSON format, instead of raw text.

The logback configuration file to use can be overridden at runtime, via -DlogbackConfigurationFile=..., so users can already adjust the logging behavior to their choosing. However, logback does not have built-in JSON support, so an additional extension is required.

Use USERS_SEARCH_FILTER to search for LDAP User

At the moment, when searching for a user in LDAP, the search is executed using only the filter {ATTRIBUTE_NAME}={USERNAME}.
I don't understand why the USERS_SEARCH_FILTER is not used in this case.
That should allow to avoid some hicups in badly designed organizations...
What do you think?

mvn clean install is not running out of the box

A mvn clean install results in the following error message.

[ERROR] Failed to execute goal on project alpine-parent: Could not resolve dependencies for project us.springett:alpine-parent:pom:1.5.1-SNAPSHOT: The following artifacts could not be resolved: com.fasterxml.jackson.core:jackson-annotations:jar:2.9.9.1, com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.9.9.1, com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.9.9.1: Could not find artifact com.fasterxml.jackson.core:jackson-annotations:jar:2.9.9.1 in central (https://repo.maven.apache.org/maven2) -> [Help 1]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.