Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes npm auth #3774

Merged
merged 4 commits into from
Jul 7, 2017
Merged

Fixes npm auth #3774

merged 4 commits into from
Jul 7, 2017

Conversation

arcanis
Copy link
Member

@arcanis arcanis commented Jun 30, 2017

This commit should fix #3765. I'm not completely satisfied with hardcoding our registry, maybe that could extended at a later point with an option to "inherit" the auth token from npm. Not sure it would be useful, tho.

@arcanis arcanis requested review from BYK and bestander June 30, 2017 11:00
@bestander
Copy link
Member

We definitely should extract the npmrc/yarnrc config parsing from npm-registry and yarn-registry.
There is a lot of confusion that those classes though in inheritance relationship read the config files exclusively.

@bestander
Copy link
Member

@arcanis, how did you test the PR?
I suppose e2e test will be coming within the follow-up task #3769, right?

const authToken = this.getRegistryOrGlobalOption(registry, '_authToken');
if (authToken) {
return `Bearer ${String(authToken)}`;
if (baseRegistry === `https://registry.yarnpkg.com/`) {
Copy link
Member

Choose a reason for hiding this comment

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

we have constants for these values

Copy link
Member

Choose a reason for hiding this comment

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

So if package comes from registry.yarnpkg.com then you want to add registry.npmjs.org to the list of registries in the attempt of getting username and password.

That looks like a lazy patch, it would be better to set up getRegistryOrGlobalOption to return same data for yarnpkg and npmjs rather than patch every callsite


const headers = Object.assign(
{
Accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
},
opts.headers,
);
if (this.token || (alwaysAuth && isRequestToRegistry(requestUrl, registry, customHostSuffix))) {

if (alwaysAuth || (packageName || pathname)[0] === `@`) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the reason for this change

Copy link
Member

Choose a reason for hiding this comment

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

From @arcanis:

this.token is undefined
So the codepath is not executed if alwaysAuth is not set
The condition I put tries to set an auth token if alwaysAuth is enabled, or if the package is scoped

Copy link
Member

Choose a reason for hiding this comment

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

This should go into the code as a comment. Also a helper function named isScoped or needsAuth (or both?) would make the code more readable.

Copy link
Member

Choose a reason for hiding this comment

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

Also I think the this.token check here was to memoize the token. We may wanna keep that behavior.

Copy link
Member

@bestander bestander left a comment

Choose a reason for hiding this comment

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

I am not super excited about the fix getting into master this way, let's fix the leaky abstraction that requires us to hardcode domains here and add an automated test.

However I'd like to stabilize 0.27 so I'll cherry-pick this commit there and release a patch today.


const headers = Object.assign(
{
Accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
},
opts.headers,
);
if (this.token || (alwaysAuth && isRequestToRegistry(requestUrl, registry, customHostSuffix))) {

if (alwaysAuth || (packageName || pathname)[0] === `@`) {
Copy link
Member

Choose a reason for hiding this comment

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

This should go into the code as a comment. Also a helper function named isScoped or needsAuth (or both?) would make the code more readable.


const headers = Object.assign(
{
Accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
},
opts.headers,
);
if (this.token || (alwaysAuth && isRequestToRegistry(requestUrl, registry, customHostSuffix))) {

if (alwaysAuth || (packageName || pathname)[0] === `@`) {
Copy link
Member

Choose a reason for hiding this comment

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

Also I think the this.token check here was to memoize the token. We may wanna keep that behavior.

if (auth) {
return `Basic ${String(auth)}`;
}
for (const registry of registries) {
Copy link
Member

Choose a reason for hiding this comment

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

Is this trying to get an auth token for the first matching registry? If so, I find that a bit dangerous. Should we keep a mapping of registry: token pairs and use the appropriate one when communicating. This would also leak tokens to other registries which may be an important security threat.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hence the check to make sure that the npm fallback is only added when the registry is the Yarn registry. The token won't be sent for any other hostname (wich is another issue).

That being said, the whole "multi-registry" logic is flawed, since we only support a single registry implementation (and adding more of them wouldn't make much sense, since it would complexify the codebase for little gain). I'd like to rework it so that we only support a single registry implementation, the npm one, and then make possible to configure what needs to be generic (mostly the hostname). But that's a second step.

Copy link
Member

Choose a reason for hiding this comment

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

I'm +1 to this until we do the refactor. The code can use a short comment explaining this safe-guard.

@BYK
Copy link
Member

BYK commented Jul 5, 2017

Sup @arcanis? :)

Copy link
Member

@BYK BYK left a comment

Choose a reason for hiding this comment

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

LGTM, great work!

May be we should plan adding tests for this now? We don't have to do e2e tests for this, right?

if (this.token || (alwaysAuth && isRequestToRegistry(requestUrl, registry, customHostSuffix))) {

const packageIdent = packageName || pathname;
const isScoppedPackage = packageIdent.match(/^@|\/@/);
Copy link
Member

Choose a reason for hiding this comment

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

What does the second part cover? (sorry, not very familiar with scoped packages except for the @user/package pattern.

Copy link
Member Author

@arcanis arcanis Jul 6, 2017

Choose a reason for hiding this comment

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

In some cases packageIdent will be @user/package, and in other cases it will be https://example.org/@user/package.tgz

const password = this.getRegistryOrGlobalOption(registry, '_password');
if (username && password) {
const pw = new Buffer(String(password), 'base64').toString();
return 'Basic ' + new Buffer(String(username) + ':' + pw).toString('base64');
Copy link
Member

Choose a reason for hiding this comment

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

Wow, no idea we did double base64 for the password part.

@arcanis
Copy link
Member Author

arcanis commented Jul 6, 2017

The main issue with e2e test is that it would require a private package somewhere. I have my own test package on my account, but I obviously cannot use it in the Yarn testsuite 😄

Ideally, we should create a new private package on the yarnpkg organization (we might need to upgrade the plan, cc @bestander, do you know who holds the keys of this account?), create a new yarnpkg-test user, and give to this user the read-only rights to access the test package (npm access). From there we should be able to safely put the auth token for this user inside our tests (unfortunately it will still allow malicious users to publish under this user namespace, but that shouldn't make much difference since they won't have push access to any existing project).

That, or we build a stub registry server.

@BYK
Copy link
Member

BYK commented Jul 6, 2017

That, or we build a stub registry server.

This. Or even better: we just do integration tests via mocks.

@bestander
Copy link
Member

I think we should have an end to end installation without stubs at least for one package.
It should take a few minutes to register @yarnpkg test org and create a package there.
The login won't be secure but what are the risks, malicious parties will be able to install that package?

Copy link
Member

@bestander bestander left a comment

Choose a reason for hiding this comment

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

Approving to unblock but add a test so that this does not drag us.

@BYK
Copy link
Member

BYK commented Jul 7, 2017

@bestander I'll merge this then since we have filed #3842

@BYK BYK merged commit 5ff6922 into yarnpkg:master Jul 7, 2017
@daniel-nagy
Copy link

This has broken installing private modules from our company's Bitbucket server.

"private-module": "git+ssh://git@git:7999/project/private-module.git"

I rolled back to version 0.27.4 and it correctly installs the package.

@bestander
Copy link
Member

@daniel-nagy please raise a new issue.
Can you provide an example URL publicly for us to test?

@BYK
Copy link
Member

BYK commented Jul 13, 2017

@daniel-nagy @bestander #3907

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[email protected] consistently 404s on private packages
4 participants