Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F9749653
D7843.id28340.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Subscribers
None
D7843.id28340.diff
View Options
diff --git a/assets/src/bundles/save/index.js b/assets/src/bundles/save/index.js
--- a/assets/src/bundles/save/index.js
+++ b/assets/src/bundles/save/index.js
@@ -372,11 +372,16 @@
validUrl = isGitRepoUrl(originUrl);
}
+ let customValidity = '';
if (validUrl) {
- input.setCustomValidity('');
+ if ((originUrl.password !== '' && originUrl.password !== 'anonymous')) {
+ customValidity = 'The origin url contains a password and cannot be accepted for security reasons';
+ }
} else {
- input.setCustomValidity('The origin url is not valid or does not reference a code repository');
+ customValidity = 'The origin url is not valid or does not reference a code repository';
}
+ input.setCustomValidity(customValidity);
+ $(input).siblings('.invalid-feedback').text(customValidity);
}
export function initTakeNewSnapshot() {
diff --git a/cypress/integration/origin-save.spec.js b/cypress/integration/origin-save.spec.js
--- a/cypress/integration/origin-save.spec.js
+++ b/cypress/integration/origin-save.spec.js
@@ -777,4 +777,73 @@
.should('have.class', 'active');
});
+ it('should not accept origin URL with password', function() {
+
+ makeOriginSaveRequest('git', 'https://user:password@git.example.org/user/repo');
+
+ cy.get('.invalid-feedback')
+ .should('contain', 'The origin url contains a password and cannot be accepted for security reasons');
+
+ });
+
+ it('should accept origin URL with username but without password', function() {
+
+ cy.adminLogin();
+ cy.visit(url);
+
+ const originUrl = 'https://user@git.example.org/user/repo';
+
+ stubSaveRequest({requestUrl: this.Urls.api_1_save_origin('git', originUrl),
+ saveRequestStatus: 'accepted',
+ originUrl: originUrl,
+ saveTaskStatus: 'not yet scheduled'});
+
+ makeOriginSaveRequest('git', originUrl);
+
+ cy.wait('@saveRequest').then(() => {
+ checkAlertVisible('success', saveCodeMsg['success']);
+ });
+
+ });
+
+ it('should accept origin URL with anonymous credentials', function() {
+
+ cy.adminLogin();
+ cy.visit(url);
+
+ const originUrl = 'https://anonymous:anonymous@git.example.org/user/repo';
+
+ stubSaveRequest({requestUrl: this.Urls.api_1_save_origin('git', originUrl),
+ saveRequestStatus: 'accepted',
+ originUrl: originUrl,
+ saveTaskStatus: 'not yet scheduled'});
+
+ makeOriginSaveRequest('git', originUrl);
+
+ cy.wait('@saveRequest').then(() => {
+ checkAlertVisible('success', saveCodeMsg['success']);
+ });
+
+ });
+
+ it('should accept origin URL with empty password', function() {
+
+ cy.adminLogin();
+ cy.visit(url);
+
+ const originUrl = 'https://anonymous:@git.example.org/user/repo';
+
+ stubSaveRequest({requestUrl: this.Urls.api_1_save_origin('git', originUrl),
+ saveRequestStatus: 'accepted',
+ originUrl: originUrl,
+ saveTaskStatus: 'not yet scheduled'});
+
+ makeOriginSaveRequest('git', originUrl);
+
+ cy.wait('@saveRequest').then(() => {
+ checkAlertVisible('success', saveCodeMsg['success']);
+ });
+
+ });
+
});
diff --git a/swh/web/common/origin_save.py b/swh/web/common/origin_save.py
--- a/swh/web/common/origin_save.py
+++ b/swh/web/common/origin_save.py
@@ -9,6 +9,7 @@
import json
import logging
from typing import Any, Dict, List, Optional, Tuple
+from urllib.parse import urlparse
from prometheus_client import Gauge
import requests
@@ -218,7 +219,14 @@
_validate_url(origin_url)
except ValidationError:
raise BadInputExc(
- "The provided origin url (%s) is not valid!" % escape(origin_url)
+ f"The provided origin url ({escape(origin_url)}) is not valid!"
+ )
+
+ parsed_url = urlparse(origin_url)
+ if parsed_url.password not in (None, "", "anonymous"):
+ raise BadInputExc(
+ "The provided origin url contains a password and cannot be "
+ "accepted for security reasons."
)
diff --git a/swh/web/tests/api/views/test_origin_save.py b/swh/web/tests/api/views/test_origin_save.py
--- a/swh/web/tests/api/views/test_origin_save.py
+++ b/swh/web/tests/api/views/test_origin_save.py
@@ -603,3 +603,55 @@
assert SaveOriginRequest.objects.get(user_ids__contains=f'"{regular_user.id}"')
assert SaveOriginRequest.objects.get(user_ids__contains=f'"{regular_user2.id}"')
+
+
+def test_reject_origin_url_with_password(api_client, swh_scheduler):
+ url = reverse(
+ "api-1-save-origin",
+ url_args={
+ "visit_type": "git",
+ "origin_url": "https://user:password@git.example.org/user/repo",
+ },
+ )
+ resp = check_api_post_responses(api_client, url, status_code=400)
+
+ assert resp.data == {
+ "exception": "BadInputExc",
+ "reason": (
+ "The provided origin url contains a password and cannot "
+ "be accepted for security reasons."
+ ),
+ }
+
+
+def test_accept_origin_url_with_username_but_without_password(
+ api_client, swh_scheduler
+):
+ url = reverse(
+ "api-1-save-origin",
+ url_args={
+ "visit_type": "git",
+ "origin_url": "https://user@git.example.org/user/repo",
+ },
+ )
+ check_api_post_responses(api_client, url, status_code=200)
+
+
+@pytest.mark.parametrize(
+ "origin_url",
+ [
+ "https://anonymous:anonymous@git.example.org/user/repo",
+ "https://anonymous:@git.example.org/user/repo",
+ ],
+)
+def test_accept_origin_url_with_anonymous_credentials(
+ api_client, swh_scheduler, origin_url
+):
+ url = reverse(
+ "api-1-save-origin",
+ url_args={
+ "visit_type": "git",
+ "origin_url": origin_url,
+ },
+ )
+ check_api_post_responses(api_client, url, status_code=200)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Aug 24, 6:04 PM (3 d, 9 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3223307
Attached To
D7843: origin_save: Reject save request when origin URL contains a password
Event Timeline
Log In to Comment