Skip to content

Commit

Permalink
version 3.61.0
Browse files Browse the repository at this point in the history
  • Loading branch information
a-langer committed Jan 26, 2024
1 parent 9137013 commit 7daecfe
Show file tree
Hide file tree
Showing 49 changed files with 1,679 additions and 937 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ LOGGING_MAX_SIZE="${LOGGING_MAX_SIZE:-10M}"
LOGGING_COUNT_FILES="${LOGGING_COUNT_FILES:-10}"

## Nexus
NEXUS_IMAGE="${NEXUS_IMAGE:-ghcr.io/a-langer/nexus-sso:3.58.1}"
NEXUS_IMAGE="${NEXUS_IMAGE:-ghcr.io/a-langer/nexus-sso:3.61.0}"
NEXUS_USER="${NEXUS_USER:-nexus}"
NEXUS_GROUP="${NEXUS_GROUP:-nexus}"
NEXUS_DATA="${NEXUS_DATA:-./nexus_data}"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
nexus-public
old
target
bin
etc/orient
etc/fabric
etc/karaf
Expand Down
19 changes: 10 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@
# docker rmi $(docker images -f "dangling=true" -q)
# docker run --user=0:0 --rm -it -p 8081:8081/tcp sonatype/nexus3:3.37.3 /bin/bash

ARG NEXUS_BASE_IMAGE="sonatype/nexus3:3.58.1"
ARG NEXUS_BASE_IMAGE="sonatype/nexus3:3.61.0"
FROM $NEXUS_BASE_IMAGE
USER root

ARG NEXUS_PLUGIN_VERSION="3.58.1-02"
ARG NEXUS_PLUGIN_VERSION="3.61.0-02"
ENV PLUG_VERSION="${NEXUS_PLUGIN_VERSION}"
ENV NEXUS_PLUGINS="${NEXUS_HOME}/system"

# Override nexus-bootstrap.jar
RUN rm -rf ${NEXUS_PLUGINS}/org/sonatype/nexus/nexus-bootstrap/
COPY nexus-bootstrap/target/nexus-bootstrap-*.jar ${NEXUS_PLUGINS}/org/sonatype/nexus/nexus-bootstrap/${PLUG_VERSION}/nexus-bootstrap-${PLUG_VERSION}.jar
RUN chmod -R 644 ${NEXUS_PLUGINS}/org/sonatype/nexus/nexus-bootstrap/${PLUG_VERSION}/nexus-bootstrap-${PLUG_VERSION}.jar
# Add nexus-pac4j-plugin.jar
RUN rm -rf ${NEXUS_PLUGINS}/com/github/alanger/nexus/plugin/nexus-pac4j-plugin/
COPY nexus-pac4j-plugin/target/nexus-pac4j-plugin-*.jar ${NEXUS_PLUGINS}/com/github/alanger/nexus/plugin/nexus-pac4j-plugin/${PLUG_VERSION}/nexus-pac4j-plugin-${PLUG_VERSION}.jar
RUN chmod -R 644 ${NEXUS_PLUGINS}/com/github/alanger/nexus/plugin/nexus-pac4j-plugin/${PLUG_VERSION}/nexus-pac4j-plugin-${PLUG_VERSION}.jar
RUN echo "reference\:file\:com/github/alanger/nexus/plugin/nexus-pac4j-plugin/${PLUG_VERSION}/nexus-pac4j-plugin-${PLUG_VERSION}.jar = 200" >> /opt/sonatype/nexus/etc/karaf/startup.properties

# Override nexus-repository-services.jar
RUN rm -rf ${NEXUS_PLUGINS}/org/sonatype/nexus/nexus-repository-services/
Expand All @@ -26,9 +27,9 @@ RUN chmod -R 644 ${NEXUS_PLUGINS}/org/sonatype/nexus/nexus-repository-services/$
# Add SSO and urlrewrite configs
COPY etc/nexus-default.properties /opt/sonatype/nexus/etc/nexus-default.properties
COPY etc/jetty/nexus-web.xml /opt/sonatype/nexus/etc/jetty/nexus-web.xml
COPY nexus-bootstrap/src/main/config/ /opt/sonatype/nexus/etc/sso/config/
COPY nexus-bootstrap/src/main/groovy/ /opt/sonatype/nexus/etc/sso/script/
COPY nexus-bootstrap/src/main/static/ /opt/sonatype/nexus/etc/sso/static/
COPY etc/jetty/jetty-sso.xml /opt/sonatype/nexus/etc/jetty/jetty-sso.xml
COPY nexus-pac4j-plugin/src/main/config/ /opt/sonatype/nexus/etc/sso/config/
COPY nexus-pac4j-plugin/src/main/groovy/ /opt/sonatype/nexus/etc/sso/script/
RUN chown nexus:nexus -R /opt/sonatype/nexus/etc/sso/

ENV INSTALL4J_ADD_VM_PARAMS="-Xms512m -Xmx2048m -Djava.util.prefs.userRoot=/nexus-data/javaprefs"
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![license](https://img.shields.io/badge/license-EPL1-brightgreen.svg)](https://github.com/a-langer/nexus-sso/blob/main/LICENSE "License of source code")
[![image](https://ghcr-badge.deta.dev/a-langer/nexus-sso/latest_tag?trim=major&label=latest)][0]
[![image-size](https://ghcr-badge.deta.dev/a-langer/nexus-sso/size?tag=3.58.1)][0]
[![image-size](https://ghcr-badge.deta.dev/a-langer/nexus-sso/size?tag=3.61.0)][0]
[![JitPack](https://jitpack.io/v/a-langer/nexus-sso.svg)][1]

Patch for [Nexus OSS][2] with authorization via [SSO][9] and [tokens][10]. By default this features available only in PRO version ([see comparison][5]), but this patch provides them an alternative implementation without violating the license.
Expand All @@ -23,19 +23,19 @@ Solution implement as Docker [container][0] (based on [official image][3] with S

## Supported features and examples of usage

> **Note**: Since version `3.61.0` for SSO and User Tokens, it is enough to have three realms: "**Local Authenticating Realm**", "**SSO Pac4j Realm**" and "**SSO Token Realm**". Other realms are not required and may lead to conflicts.
List of features this patch adds:

* **SAML/SSO** - authentication via Single Sign-On (SSO) using a SAML identity provider such as [Keycloak][12], [Okta][13], [ADFS][14] and others. Nexus uses access system based on [Apache Shiro][6], this patch extends it with a [Pac4j][8] and [buji-pac4j][7] libraries, which can be configured with [shiro.ini](./etc/sso/config/shiro.ini) (see [SAML.md](./docs/SAML.md) and documentation of Apache Shiro and Pac4j for more detail informations). SSO users are created as internal Nexus accounts the first time they sign-in and are updated every next time. Example of usage SSO:
* **SAML/SSO** - authentication via Single Sign-On (SSO) using a SAML identity provider such as [Keycloak][12], [Okta][13], [ADFS][14] and others. Nexus uses access system based on [Apache Shiro][6], this patch extends it with a [Pac4j][8] and [buji-pac4j][7] libraries, which can be configured with [shiro.ini](./nexus-pac4j-plugin/src/main/config/shiro.ini) (see [SAML.md](./docs/SAML.md) and documentation of Apache Shiro and Pac4j for more detail informations). SSO users are created as internal Nexus accounts the first time they sign-in and are updated every next time. Example of usage SSO:
* Enable "**SSO Pac4j Realm**" in the server administration panel.
* Go to menu "Sign in", press to button "Sign in with SSO".
* You will be redirected to the login page of identity provider.
* Type you credentials (login, password, 2FA, etc.).
* You will be redirected to the main page of Nexus, roles and permissions will be mapped with your account as configured.

* **User Auth Tokens** - are applied when security policies do not allow the users password to be used, such as for storing in plain text (in settings Docker, Maven and etc.) or combined with **SAML/SSO**. Each user can set a personal token that can be used instead of a password. The creation of tokens is implemented through the "NuGet API Key" menu (privilegies `nx-apikey-all` required), however, the tokens themselves apply to all types of repositories.

> **Note**: For SSO and user tokens, it is enough to have two realms: "Local Authenticating Realm" and "Local Authorizing Realm". Other realms are not required and may lead to conflicts.
Example of usage user token:
* **User Auth Tokens** - are applied when security policies do not allow the users password to be used, such as for storing in plain text (in settings Docker, Maven and etc.) or combined with **SAML/SSO**. Each user can set a personal token that can be used instead of a password. The creation of tokens is implemented through the "NuGet API Key" menu (privilegies `nx-apikey-all` required), however, the tokens themselves apply to all types of repositories. Example of usage user token:
* Enable "**SSO Token Realm**" in the server administration panel.
* Go to menu "Nexus -> Manage your user account -> NuGet API Key", press "Access API key".
* Type your **username** if using SSO login, otherwise type password, then press "Authenticate".
* Copy "Your NuGet API Key", press "Close" and "Sign out".
Expand Down Expand Up @@ -90,14 +90,14 @@ List of features this patch adds:
## Additional settings (tips and tricks)

* [Docker compose](./compose.yml) configuration may be extended with [compose.override.yml](./_compose.override_prod.yml) (for example, pass additional files to the container).
* SAML/SSO authentication may be configured with environment variables in [.env](./.env) file, for more flexible settings, can make changes directly to [shiro.ini](./etc/sso/config/shiro.ini) ([variable interpolation][16] supported). However, this also requires that the configuration files of service provider (ex., [sp-metadata.xml](./etc/sso/config/sp-metadata.xml)) and identity provider (ex., [metadata-okta.xml](./etc/sso/config/metadata.xml) or [metadata-keycloak.xml](./etc/sso/config/metadata-keycloak.xml)) will be passed to the container. Examples of creating SAML configurations see in "[Keycloak SAML integration with Nexus application][15]" (except "Configure Sonatype Platform", instead follow [SAML.md](./docs/SAML.md)).
* SAML/SSO authentication may be configured with environment variables in [.env](./.env) file, for more flexible settings, can make changes directly to [shiro.ini](./nexus-pac4j-plugin/src/main/config/shiro.ini) ([variable interpolation][16] supported). However, this also requires that the configuration files of service provider (ex., [sp-metadata.xml](./nexus-pac4j-plugin/src/main/config/sp-metadata.xml)) and identity provider (ex., [metadata-okta.xml](./nexus-pac4j-plugin/src/main/config/metadata.xml) or [metadata-keycloak.xml](./nexus-pac4j-plugin/src/main/config/metadata-keycloak.xml)) will be passed to the container. Examples of creating SAML configurations see in "[Keycloak SAML integration with Nexus application][15]" (except "Configure Sonatype Platform", instead follow [SAML.md](./docs/SAML.md)).
* Nginx SSL is pre-configured, to enable it, need copy file [_ssl.conf](./etc/nginx/_ssl.conf) to `ssl.conf` and pass to directory `${NEXUS_ETC}/nginx/tls/` two files:
* `site.crt` - PEM certificate of domain name.
* `site.key` - key for certificate.
* [UrlRewriteFilter][17] is used to route HTTP requests within the application and can be further configured using [urlrewrite.xml](./etc/sso/config/urlrewrite.xml) (for example override or protect API endpoint). Status of UrlRewriteFilter available in `http://localhost:8081/rewrite-status`. Also it supports hot-reload, to apply the any settings without restarting the container, run the command:
* [Jetty Rewrite Handler][17] is used to route HTTP requests within the application and can be further configured using [jetty-sso.xml](./etc/jetty/jetty-sso.xml) (for example override or protect API endpoint). Also it supports hot-reload, to apply the any settings of plugin without restarting the container, run the command:

```bash
docker compose exec -- nexus curl -sSfkI http://localhost:8081/rewrite-status/?conf=etc/sso/config/urlrewrite.xml
docker compose exec -- nexus curl -k http://localhost:8081/rewrite-status
```

> **Note**: Hot-reload not working for environment variables defined in [.env](./.env), this changes take effect only after the container is restarted.
Expand Down Expand Up @@ -158,6 +158,6 @@ Need installed Maven and Docker with [Compose][4] and [BuildKit][4.1] plugins:
[14]: https://docs.microsoft.com/en-us/power-apps/maker/portals/configure/configure-saml2-settings "ADFS SAML"
[15]: https://support.sonatype.com/hc/en-us/articles/1500000976522-Keycloak-SAML-integration-with-Nexus-Applications "Keycloak-SAML + Nexus"
[16]: https://commons.apache.org/proper/commons-configuration/userguide/howto_basicfeatures.html "Variable interpolation"
[17]: https://tuckey.org/urlrewrite/manual/4.0/index.html "Url Rewrite Filter"
[17]: https://eclipse.dev/jetty/documentation/jetty-9/index.html "Jetty Rewrite Handler"
[18]: https://gist.github.com/abdennour/74c5de79e57a47f3351217d674238da8?permalink_comment_id=4188452#gistcomment-4188452 "Nginx for Docker registry"
[19]: https://github.com/sonatype/nexus-public/releases "Nexus release notes"
6 changes: 3 additions & 3 deletions _compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ services:
volumes:
- ${NEXUS_ETC}/logback:/opt/sonatype/nexus/etc/logback:ro
- ${NEXUS_ETC}/jetty/nexus-web.xml:/opt/sonatype/nexus/etc/jetty/nexus-web.xml:ro
- ${NEXUS_ETC}/jetty/jetty-sso.xml:/opt/sonatype/nexus/etc/jetty/jetty-sso.xml:ro
- ${NEXUS_ETC}/nexus-default.properties:/opt/sonatype/nexus/etc/nexus-default.properties:ro
- ./nexus-bootstrap/src/main/config:/opt/sonatype/nexus/etc/sso/config:ro
- ./nexus-bootstrap/src/main/static:/opt/sonatype/nexus/etc/sso/static:ro
- ./nexus-bootstrap/src/main/groovy:/opt/sonatype/nexus/etc/sso/script:ro
- ./nexus-pac4j-plugin/src/main/config:/opt/sonatype/nexus/etc/sso/config:ro
- ./nexus-pac4j-plugin/src/main/groovy:/opt/sonatype/nexus/etc/sso/script:ro
ports:
- "${NEXUS_HTTP_PORT:-8081}:8081" # Nexus: http://localhost:8081/ (remove it from production environment)
- "${ORIENTDB_BINARY_PORT:-2424}:2424" # OrientDB: tcp://localhost:2424 (remove it from production environment)
8 changes: 4 additions & 4 deletions docs/SAML.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Description of configuration:

- [sp-metadata.xml](../etc/sso/config/sp-metadata.xml) - this is the configuration of service provider (hereinafter **SP**), made specifically for the Nexus application. The only thing that may be required is to correct "**entityID**" and "**Location**" depending on the DNS name and protocol you use, endpoint will always be "**/callback?client_name=SAML2Client**". Example for DNS `myNexusDomain`:
- [sp-metadata.xml](../nexus-pac4j-plugin/src/main/config/sp-metadata.xml) - this is the configuration of service provider (hereinafter **SP**), made specifically for the Nexus application. The only thing that may be required is to correct "**entityID**" and "**Location**" depending on the DNS name and protocol you use, endpoint will always be "**/callback?client_name=SAML2Client**". Example for DNS `myNexusDomain`:

```xml
<md:EntityDescriptor ... entityID="http(s)://myNexusDomain/callback?client_name=SAML2Client" validUntil="2042-03-17T05:02:50.999Z">
Expand All @@ -24,7 +24,7 @@ Description of configuration:
</md:EntityDescriptor>
```

- The value of the attribute "**entityID**" in sp-metadata.xml should be the same as the attribute "**serviceProviderEntityId**" and "**callbackUrl**" in [shiro.ini](../etc/sso/config/shiro.ini) (also depending on the DNS name you use), ex:
- The value of the attribute "**entityID**" in sp-metadata.xml should be the same as the attribute "**serviceProviderEntityId**" and "**callbackUrl**" in [shiro.ini](../nexus-pac4j-plugin/src/main/config/shiro.ini) (also depending on the DNS name you use), ex:

```ini
# Same as the attribute entityID
Expand All @@ -35,15 +35,15 @@ Description of configuration:

> **_NOTE:_** ADFS does not support URI parameter in entityID, remove "_?client_name=SAML2Client_" from **Client ID** in the ADFS settings, from **serviceProviderEntityId** in shiro.ini and from **entityID** in sp-metadata.xml.

- [metadata.xml](../etc/sso/config/metadata.xml) - this is the configuration of the identity provider (hereinafter **IdP**), it needs to be downloaded from Okta/Keycloak/ADFS/Etc and passed into the Nexus container. Additionally, you must specify the "**SP Entity ID**/**Client ID**" and "**Single sign-on URL**/**Client SAML endpoint**" attributes in the IdP settings, whose value must match the "**entityID**" from sp-metadata.xml.
- [metadata.xml](../nexus-pac4j-plugin/src/main/config/metadata.xml) - this is the configuration of the identity provider (hereinafter **IdP**), it needs to be downloaded from Okta/Keycloak/ADFS/Etc and passed into the Nexus container. Additionally, you must specify the "**SP Entity ID**/**Client ID**" and "**Single sign-on URL**/**Client SAML endpoint**" attributes in the IdP settings, whose value must match the "**entityID**" from sp-metadata.xml.
- By default, "Nexus SSO" is already pre-configured for authorization through [Okta](https://www.okta.com/) with HTTP protocol on localhost (the endpoint `http://localhost/callback?client_name=SAML2Client`, see [Okta settings](./Okta-Nexus-SAML.png)). To configure authorization through another IdP-server is required:
1. Configure new SAML client in the IdP server with DNS name for your Nexus instance and download **metadata.xml**.
2. Replace the protocol and DNS name in **sp-metadata.xml** and **shiro.ini** (as show above).
3. Pass **metadata.xml**, **sp-metadata.xml** and **shiro.ini** to the Nexus container, see [_compose.override_prod.yml](../_compose.override_prod.yml) for an example.

## Attributes mapping

The names of user attributes depend on the structure of the profile in IdP. User attribute mapping can be configured in [shiro.ini](../etc/sso/config/shiro.ini):
The names of user attributes depend on the structure of the profile in IdP. User attribute mapping can be configured in [shiro.ini](../nexus-pac4j-plugin/src/main/config/shiro.ini):

```properties
# User roles attribute (list of roles)
Expand Down
81 changes: 81 additions & 0 deletions etc/jetty/jetty-sso.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC '-//Jetty//Configure//EN' 'http://www.eclipse.org/jetty/configure_9_0.dtd'>
<!--
https://support.sonatype.com/hc/en-us/articles/360014161874-How-to-Restrict-Access-to-Nexus-Repository-3-by-IP-Address
https://eclipse.dev/jetty/documentation/jetty-9/index.html
https://eclipse.dev/jetty/javadoc/jetty-9/org/eclipse/jetty/rewrite/handler/RewriteHandler.html
https://eclipse.dev/jetty/javadoc/jetty-9/org/eclipse/jetty/server/handler/IPAccessHandler.html
-->
<Configure id="Server" class="org.eclipse.jetty.server.Server">

<!-- ======================================================================= -->
<!-- Configure rewrite handler https://stackoverflow.com/a/38919633/19707292 -->
<!-- ======================================================================= -->
<Call name="insertHandler">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
<Set name="rewriteRequestURI">
<Property name="jetty.rewrite.rewriteRequestURI" default="true" />
</Set>
<Set name="rewritePathInfo">
<Property name="jetty.rewrite.rewritePathInfo" default="false" />
</Set>
<Set name="originalPathAttribute">
<Property name="jetty.rewrite.originalPathAttribute" default="requestedPath" />
</Set>
<!-- Set DispatcherTypes -->
<Set name="dispatcherTypes">
<Array type="javax.servlet.DispatcherType">
<Item>
<Call class="javax.servlet.DispatcherType" name="valueOf">
<Arg>REQUEST</Arg>
</Call>
</Item>
<Item>
<Call class="javax.servlet.DispatcherType" name="valueOf">
<Arg>ASYNC</Arg>
</Call>
</Item>
</Array>
</Set>
<Get id="Rewrite" name="ruleContainer" />
<!-- SSO logout endpoint, required only for DELETE method -->
<!-- <Call name="addRule">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
<Set name="pattern">/service/rapture/session</Set>
<Set name="replacement">/pac4jLogout</Set>
</New>
</Arg>
</Call> -->
<!-- SSO reload endpoint for compatibility with UrlRewriteFilter -->
<Call name="addRule">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
<Set name="regex">/rewrite-status.*</Set>
<Set name="replacement">/service/rest/rewrite-status</Set>
</New>
</Arg>
</Call>
</New>
</Arg>
</Call>

<!-- Access reload endpoint https://github.com/jetty/jetty.project/issues/1072#issuecomment-258478908 -->
<Call name="insertHandler">
<Arg>
<New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
<Set name="white">
<Array type="String">
<Item>127.0.0.1|/service/rest/rewrite-status</Item>
<Item>127.0.0.1|/rewrite-status</Item>
<Item>127.0.0.1|/service/rest/rewrite-status/*</Item>
<Item>127.0.0.1|/rewrite-status/*</Item>
</Array>
</Set>
<Set name="whiteListByPath">true</Set>
</New>
</Arg>
</Call>

</Configure>
Loading

0 comments on commit 7daecfe

Please sign in to comment.