无法使用 Nexus 3 为 Cloudsmith 中的 npm 存储库做代理

Can't do a proxy for an npm repository in Cloudsmith with Nexus 3

我想为 cloudsmith.io 中的私有存储库配置 Nexus 代理。 当我使用 public npm 注册表配置代理时,一切正常,但是当我使用 Cloudsmith 存储库配置代理时,命令 npm install 失败。

要使用 Cloudsmith(无代理)进行身份验证,.npmrc 文件必须包含以下内容:

registry=https://npm.cloudsmith.io/<my org>/<my repo>/
//npm.cloudsmith.io/<my org>/<my repo>/:username=<my user>
//npm.cloudsmith.io/<my org>/<my repo>/:_password=<my password in base64>

所以我在代理配置上启用了 http 身份验证,但返回了 404。

你知道我是否遗漏了代理配置的某些内容吗? 也许 Nexus 无法处理 Cloudsmith 身份验证。

更新:

Nexus 日志:

2019-06-21 14:10:58,736+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: ignoreCookies
2019-06-21 14:10:58,736+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
2019-06-21 14:10:58,737+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Opening connection {s}->https://npm.cloudsmith.io:443
2019-06-21 14:10:58,840+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connecting to npm.cloudsmith.io/13.249.122.86:443
2019-06-21 14:10:58,840+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory - Connecting socket to npm.cloudsmith.io/13.249.122.86:443 with timeout 20000
2019-06-21 14:10:58,841+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2]
2019-06-21 14:10:58,841+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
2019-06-21 14:10:58,841+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory - Starting handshake
2019-06-21 14:10:59,270+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory - Secure session established
2019-06-21 14:10:59,270+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory -  negotiated protocol: TLSv1.2
2019-06-21 14:10:59,270+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory -  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
2019-06-21 14:10:59,270+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory -  peer principal: CN=*.cloudsmith.io
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory -  peer alternative names: [*.cloudsmith.io, cloudsmith.io]
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.conn.ssl.SSLConnectionSocketFactory -  issuer principal: CN=Amazon, OU=Server CA 1B, O=Amazon, C=US
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connection established 172.19.0.2:48268<->13.249.122.86:443
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-52: set socket timeout to 20000
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Executing request GET /myorganization/javascript/cordova HTTP/1.1
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 >> GET /myorganization/javascript/cordova HTTP/1.1
2019-06-21 14:10:59,272+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 >> Host: npm.cloudsmith.io
2019-06-21 14:10:59,272+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 >> Connection: Keep-Alive
2019-06-21 14:10:59,272+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 >> User-Agent: Nexus/3.16.2-01 (OSS; Linux; 4.4.0-139-generic; amd64; 1.8.0_212)
2019-06-21 14:10:59,272+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 >> Accept-Encoding: gzip,deflate
2019-06-21 14:10:59,804+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << HTTP/1.1 404 Not Found
2019-06-21 14:10:59,804+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Content-Type: application/json
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Content-Length: 71
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Connection: keep-alive
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Date: Fri, 21 Jun 2019 14:10:59 GMT
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Allow: GET, PUT, HEAD, OPTIONS
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << ETag: "2d642f304a79cbf4e5fe6270af0846ca"
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Vary: Cookie
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Server: Cloudsmith MCP
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Content-Security-Policy: default-src 'self'; child-src 'self' https://fast.wistia.net https://giphy.com https://intercom-sheets.com https://js.stripe.com https://player.vimeo.com https://share.intercom.io https://www.google.com/recaptcha/ https://www.intercom-reporting.com https://www.youtube.com; connect-src 'self' https://api-iam.intercom.io https://api.intercom.io https://api-ping.intercom.io https://api.stripe.com https://app.getsentry.com https://bam.nr-data.net https://www.google-analytics.com https://js.intercomcdn.com https://nexus-long-poller-a.intercom.io https://nexus-long-poller-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://rs.fullstory.com https://sentry.io/api/ https://stats.g.doubleclick.net https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://widget.intercom.io https://yt0blqw1vlv7.statuspage.io wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://api.cloudsmith.io https://api-prd.cloudsmith.io https://cloudsmith-package-uploads-prd.s3.amazonaws.com https://cloudsmith-package-uploads-prd.s3-accelerate.amazonaws.com; font-src 'self' data: https://js.intercomcdn.com https://fonts.gstatic.com https://assets.cloudsmith.media; frame-src 'self' https://fast.wistia.net https://giphy.com https://intercom-sheets.com https://js.stripe.com https://player.vimeo.com https://share.intercom.io https://www.google.com/recaptcha/ https://www.intercom-reporting.com https://www.youtube.com; img-src 'self' data: https: https://downloads.intercomcdn.com https://gifs.intercomcdn.com https://gravatar.com https://img.shields.io https://js.intercomcdn.com https://static.intercomassets.com https://uploads.intercomusercontent.com https://assets.cloudsmith.media https://prd.cloudsmith.media https://users.cloudsmith.media; media-src 'self' https://giphy.com https://js.intercomcdn.com https://assets.cloudsmith.media https://prd.cloudsmith.media https://users.cloudsmith.media; object-src 'self'; script-src 'self' 'unsafe-inline' data: https://api.stripe.com https://app.intercom.io https://bam.nr-data.net https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/ https://cdn.ravenjs.com https://connect.facebook.net https://fullstory.com https://js.intercomcdn.com https://js.stripe.com https://maps.googleapis.com https://maps.gstatic.com https://nexus-long-poller-a.intercom.io https://nexus-long-poller-b.intercom.io https://rum-static.pingdom.net https://sentry.io/api/ https://sjs.bizographics.com https://tagmanager.google.com https://tpc.googlesyndication.com https://translate.google.com https://widget.intercom.io https://www.googleadservices.com https://www.google-analytics.com https://www.google.com/recaptcha/ https://www.googletagmanager.com https://www.gstatic.com/recaptcha/ https://assets.cloudsmith.media; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://tagmanager.google.com https://assets.cloudsmith.media; worker-src 'self' blob: https://assets.cloudsmith.media; form-action 'self' https://api-iam.intercom.io https://messenger-apps.intercom.io https://intercom.help https://cloudsmith.io https://www.cloudsmith.io https://prd.cloudsmith.io https://web-prd.cloudsmith.io; report-uri https://sentry.io/api/195170/csp-report/?sentry_key=85cf84319e204994878d7afb03753450
2019-06-21 14:10:59,805+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Public-Key-Pins: pin-sha256="++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="tFOU95aPSUFNfZLpf6OdBnVvAFKxd8zxp4jCbaL3MJ0="; max-age=86400; report-uri="https://cloudsmith.report-uri.io/r/default/hpkp/enforce"
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Strict-Transport-Security: max-age=5184000
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Referrer-Policy: no-referrer-when-downgrade
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Expect-CT: enforce, max-age=86400, report-uri="https://cloudsmith.report-uri.io/r/default/ct/enforce"
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << X-Cache: Error from cloudfront
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << Via: 1.1 24990d51e53375dffbe8411f5e14f579.cloudfront.net (CloudFront)
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << X-Amz-Cf-Pop: ATL51-C1
2019-06-21 14:10:59,806+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.headers - http-outgoing-52 << X-Amz-Cf-Id: _igVXHch2JQA54gLS1Btz7iTlbtc1W4PQ7S_Jrc4sKYvFwvMsJ5VBg==
2019-06-21 14:10:59,807+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Connection can be kept alive for 30000 MILLISECONDS
2019-06-21 14:10:59,807+0000 INFO  [qtp2116157452-1644] admin org.sonatype.nexus.repository.httpclient.internal.HttpClientFacetImpl - Repository status for myorganization-javascript-proxy changed from READY to AVAILABLE - reason n/a for n/a
2019-06-21 14:10:59,807+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-52: set socket timeout to 0

答案是 Sonatype Nexus 希望上游请求受到“401 未授权”响应 + 有效 WWW-Authenticate header 的挑战,而不是“404 未找到”响应。

这是问题所在的指示在日志输出中:

2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED
2019-06-21 14:10:59,271+0000 DEBUG [qtp2116157452-1644] admin org.apache.http.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED

此处,UNCHALLENGED 声明 Nexus 将不会提供凭据,无论是 pre-emptively 还是作为 follow-up 请求。因此,如果目标上游是私有的并且需要身份验证,就像在这种情况下,这将导致代理失败。

要解决此问题,上游需要为受保护端点修复对 return“401 Unauthorized”的响应。这将确保身份验证传递到目标上游。假设您的凭据是正确的,您应该通过身份验证。

还值得注意的是,在撰写本文时,Nexus 不支持 Bearer-based(令牌)身份验证 [1],因此它与 npm login 工作流程不兼容。因此请确保直接在 .npmrc 中将身份验证配置为 username/password。例如:

registry=https://npm.cloudsmith.io/<my org>/<my repo>/
//npm.cloudsmith.io/<my org>/<my repo>/:username=<my user>
//npm.cloudsmith.io/<my org>/<my repo>/:_password=<my password in base64>

[1] https://issues.sonatype.org/browse/NEXUS-12456