u1timate
Published on 2024-06-13 / 83 Visits
0

自定义nexus插件

环境准备

  • Java 8
  • 引用官方提供的java项目骨架
  • nexus oss 3.29.2-02 (api版本类似) https://sonatype-download.global.ssl.fastly.net/repository/downloads-prod-group/3/nexus-3.29.2-02-unix.tar.gz
git clone https://github.com/sonatype-nexus-community/nexus-format-archetype
cd nexus-format-archetype
mvn clean install

根据骨架的pom文件,编写新项目的创建命令,这里的pom文件信息如下

image-ygbp.png

根据这个文件信息生成创建命令

# 退出nexus-format-archetype目录
# 新建项目
mkdir nexus-audit-plugin
cd nexus-audit-plugin

mvn archetype:generate -DarchetypeGroupId=org.sonatype.nexus.archetype -DarchetypeArtifact
Id=format-plugin -DarchetypeVersion=1.0.61-SNAPSHOT -DgroupId=com.sec.nexus -DartifactId=nexus-audit-plugin -DpluginFormat=audit -DpluginClass=Audit -Dversion=1.0-SNAPSHOT

如果提示没有找到 org.sonatype.nexus.archetype,可能是mvn install没有安装成功, 手动移到目录中。

开发说明

这里默认创建的模板是基于 AuditRecipeSupport类实现的。该类是一个抽象类,提供了审计功能的支持。它通常用于实现需要审计功能的Nexus插件或扩展。通过继承这个类,我们可以方便地记录和管理审计日志,跟踪系统中的重要操作和事件。

import org.sonatype.nexus.repository.audit.AuditRecipeSupport;
import org.sonatype.nexus.repository.Repository;

public class CustomAuditRecipe extends AuditRecipeSupport {
    public CustomAuditRecipe(Repository repository) {
        super(repository);
    }

    @Override
    protected void doSomething() {
        // 自定义的审计逻辑
        auditLog.info("Package uploaded to repository: {}", getRepository().getName());
    }
}

我们这里使用 ContributedHandler 是一个接口,主要用于扩展Nexus Repository的功能。通过实现这个接口,我们可以创建自定义的处理器,并将其插入到Nexus的请求处理链中。具体来说,ContributedHandler 可以用于以下场景:

  1. 自定义请求处理:可以拦截和处理Nexus中的HTTP请求,添加自定义的逻辑。例如,可以在请求到达特定仓库之前进行验证或修改请求。
  2. 扩展现有功能:可以在现有的Nexus功能基础上添加新的功能,而不需要修改Nexus的核心代码。

示例代码如下

import org.sonatype.nexus.repository.view.Request;
import org.sonatype.nexus.repository.view.Response;
import org.sonatype.nexus.repository.view.handlers.ContributedHandler;

public class LoggingHandler implements ContributedHandler {
    private static final Logger LOG = LoggerFactory.getLogger(LoggingHandler.class);

    @Override
    public Response handle(Request request, Context context) throws Exception {
        LOG.info("Received request for path: {}", request.getPath());
        // 继续处理请求
        return context.proceed(request);
    }
}

根据文档 ContributedHandler 继承自 Handler 接口,而 Handler 接口中有一个核心方法

@Nonnull
Response handle(@Nonnull Context context) throws Exception;
  • 这是 Handler 接口中的唯一方法,也是 ContributedHandler 需要实现的方法。
  • 该方法用于处理传入的请求,并返回一个 Response 对象。
  • Context 对象包含了请求的上下文信息,包括请求和响应对象。

实现

实现对maven拉取包的记录

import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.repository.Repository;
import org.sonatype.nexus.repository.types.ProxyType;
import org.sonatype.nexus.repository.view.Context;
import org.sonatype.nexus.repository.view.Payload;
import org.sonatype.nexus.repository.view.Response;
import org.sonatype.nexus.repository.maven.MavenPath;



import static java.lang.String.format;

@Named
@Singleton
public class ScannerHandler implements ContributedHandler {
  private static final Logger LOG = LoggerFactory.getLogger(ScannerHandler.class);

  private final ConfigurationHelper configurationHelper;
  private final MavenScanner mavenScanner;
  private final NpmScanner npmScanner;
  private final PypiScanner pypiScanner;

//  private SnykClient snykClient;
  private SnykSecurityCapabilityConfiguration configuration;

  @Inject
  public ScannerHandler() {
 
  }

  @Nonnull
  @Override
  public Response handle(@Nonnull Context context) throws Exception {
    Response response = context.proceed();
  
    Repository repository = context.getRepository();
    if (!ProxyType.NAME.equals(repository.getType().getValue())) {
      LOG.warn("Only proxy repositories are supported: {} - {}", repository.getName(), repository.getType());
      return response;
    }
    Payload payload = response.getPayload();
    String repositoryFormat = repository.getFormat().getValue();
    switch (repositoryFormat) {
      case "maven2": {
        Object mavenPathAttribute = context.getAttributes().get(MavenPath.class.getName());
        if (!(mavenPathAttribute instanceof MavenPath)) {
          LOG.warn("Could not extract maven path from {}", context.getRequest().getPath());
          return null;
        }
        String clientIp = "";
        MavenPath mavenPath = (MavenPath) mavenPathAttribute;
        MavenPath parsedMavenPath = mavenPathParser.parsePath(mavenPath.getPath());
        MavenPath.Coordinates coordinates = parsedMavenPath.getCoordinates();
        LOG.info(">>>coordinates: {},{},{},{},{}", coordinates.getGroupId(),clientIp, coordinates.getArtifactId(), coordinates.getVersion());

        break;
      }
      default:
        LOG.error("format {} is not supported", repositoryFormat);
        return response;
    }
    return response;
  }

在处理不同类型的仓库格式时,除了 maven2npm,还有许多其他常见的仓库格式,如 nugetpypidockerrubygems

@Inject 是依赖注入框架(如Guice)中的一个注解,用于标记构造函数、方法或字段,以便框架在运行时自动注入依赖项。通过使用 @Inject 注解,您可以让依赖注入框架自动创建和注入所需的依赖对象,而无需手动实例化它们。

在该示例代码中,@Inject 注解标记了 ScannerHandler 类的构造函数,这意味着依赖注入框架会自动为 ScannerHandler 提供所需的依赖项。

等同代码如下

// 手动创建依赖项

// 手动注入依赖项
ScannerHandler scannerHandler = new ScannerHandler();

结合使用 @Named@Singleton,可以创建一个命名的单例类,在依赖注入时既能保证单例模式,又能通过名称进行区分。希望这些信息对您有所帮助。

运行打包

mvn clean package

集成jar包

临时集成测试

3.29版本

移动到 nexus-3.29.2-02/deploy目录下

最新版本


./nexus run
bundle:list
bundle:install file:////tmp/nexus-security-plugin.jar
# 激活
bundle:start <org.sonatype.nexus.plugins:nexus-repository-foo ID>

测试结果如下:

image-qsxs.png

永久安装

复制nexus-repository-foo-1.0.0.jar) 到 <nexus_dir>/deploy目录下, 该文件夹由 Nexus Repository 监控,如果 Nexus Repository 正在运行,则插件应在复制到此处后 60 秒内加载。

参考

nexus-repository 3.29.2-02 javadoc (org.sonatype.nexus)

snyk/nexus-snyk-security-plugin: Allow Nexus users to test their applications against the Snyk vulnerability database (github.com)

nexus-development-guides/docs/plugin-install.md at master · sonatype-nexus-community/nexus-development-guides (github.com)