Repository: pulp/pulpcore

Issue:
Passwords stored within remotes are being truncated
Author: @lubosmj (lmjachky)


Redmine Issue: 9617, https://pulp.plan.io/issues/9617

---

Passwords with trailing whitespace characters are truncated automatically. This feature is not advertised at https://docs.pulpproject.org/pulpcore/restapi.html#operation/remotes_file_file_create or anywhere else.

```
(pulp) [vagrant@pulp3-source-fedora34 ~]$ http :24817/pulp/api/v3/remotes/file/file/ url="https://docker.io" username="lmjachky" password="pasword " name=foo
HTTP/1.1 201 Created
Access-Control-Expose-Headers: Correlation-ID
Allow: GET, POST, HEAD, OPTIONS
Connection: close
Content-Length: 506
Content-Type: application/json
Correlation-ID: 10166cb9b1eb4a9eb341525d413472bf
Date: Wed, 08 Dec 2021 13:57:44 GMT
Location: /pulp/api/v3/remotes/file/file/e0299ca2-80d5-4491-8174-8e468cc696af/
Referrer-Policy: same-origin
Server: gunicorn
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "ca_cert": null,
    "client_cert": null,
    "connect_timeout": null,
    "download_concurrency": null,
    "headers": null,
    "max_retries": null,
    "name": "foo",
    "policy": "immediate",
    "proxy_url": null,
    "pulp_created": "2021-12-08T13:57:44.659583Z",
    "pulp_href": "/pulp/api/v3/remotes/file/file/e0299ca2-80d5-4491-8174-8e468cc696af/",
    "pulp_labels": {},
    "pulp_last_updated": "2021-12-08T13:57:44.659601Z",
    "rate_limit": null,
    "sock_connect_timeout": null,
    "sock_read_timeout": null,
    "tls_validation": true,
    "total_timeout": null,
    "url": "https://docker.io"
}


(pulp) [vagrant@pulp3-source-fedora34 ~]$ django-admin shell_plus
/usr/local/lib/pulp/lib64/python3.9/site-packages/redis/connection.py:72: UserWarning: redis-py works best with hiredis. Please consider installing
  warnings.warn(msg)
1. Shell Plus Model Imports
from django.contrib.admin.models import LogEntry
from pulpcore.app.models.access_policy import AccessPolicy, Group
from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from guardian.models.models import GroupObjectPermission, UserObjectPermission
from pulp_container.app.models import Blob, BlobManifest, ContainerDistribution, ContainerNamespace, ContainerPushRepository, ContainerRemote, ContainerRepository, ContentRedirectContentGuard, Manifest, ManifestListManifest, Tag
from pulpcore.app.models.upload import Upload, UploadChunk
from pulp_file.app.models import FileAlternateContentSource, FileContent, FileDistribution, FilePublication, FileRemote, FileRepository
from pulp_ostree.app.models import OstreeCommit, OstreeCommitObject, OstreeConfig, OstreeDistribution, OstreeObject, OstreeRef, OstreeRemote, OstreeRepository, OstreeSummary
from pulp_rpm.app.models.acs import RpmAlternateContentSource
from pulp_rpm.app.models.advisory import UpdateCollection, UpdateCollectionPackage, UpdateRecord, UpdateReference
from pulp_rpm.app.models.comps import PackageCategory, PackageEnvironment, PackageGroup, PackageLangpacks
from pulp_rpm.app.models.custom_metadata import RepoMetadataFile
from pulp_rpm.app.models.distribution import Addon, Checksum, DistributionTree, Image, Variant
from pulp_rpm.app.models.modulemd import Modulemd, ModulemdDefaults
from pulp_rpm.app.models.package import Package
from pulp_rpm.app.models.repository import RpmDistribution, RpmPublication, RpmRemote, RpmRepository, UlnRemote
from pulpcore.app.models.acs import AlternateContentSource, AlternateContentSourcePath
from pulpcore.app.models.base import Label
from pulpcore.app.models.content import Artifact, AsciiArmoredDetachedSigningService, Content, ContentArtifact, PulpTemporaryFile, RemoteArtifact, SigningService
from pulpcore.app.models.exporter import Export, ExportedResource, Exporter, FilesystemExport, FilesystemExporter, PulpExport, PulpExporter
from pulpcore.app.models.importer import Import, Importer, PulpImport, PulpImporter, PulpImporterRepository
from pulpcore.app.models.progress import GroupProgressReport, ProgressReport
from pulpcore.app.models.publication import BaseDistribution, ContentGuard, Distribution, Publication, PublishedArtifact, PublishedMetadata, RBACContentGuard
from pulpcore.app.models.repository import Remote, Repository, RepositoryContent, RepositoryVersion, RepositoryVersionContentDetails
from pulpcore.app.models.role import GroupRole, Role, UserRole
from pulpcore.app.models.status import ContentAppStatus
from pulpcore.app.models.task import CreatedResource, Task, TaskGroup, Worker
1. Shell Plus Django Imports
from django.core.cache import cache
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Avg, Case, Count, F, Max, Min, Prefetch, Q, Sum, When
from django.utils import timezone
from django.urls import reverse
from django.db.models import Exists, OuterRef, Subquery
Python 3.9.7 (default, Aug 30 2021, 00:00:00) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.29.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: FileRemote.objects.first().password
Out[1]: 'pasword'


```





Discussion:
This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!

Resolving patch:
diff --git a/pulpcore/app/serializers/repository.py b/pulpcore/app/serializers/repository.py
--- a/pulpcore/app/serializers/repository.py
+++ b/pulpcore/app/serializers/repository.py
@@ -115,10 +115,14 @@ class RemoteSerializer(ModelSerializer):
         write_only=True,
     )
     proxy_password = serializers.CharField(
-        help_text="The password to authenticte to the proxy.",
+        help_text=_(
+            "The password to authenticate to the proxy. Extra leading and trailing whitespace "
+            "characters are not trimmed."
+        ),
         required=False,
         allow_null=True,
         write_only=True,
+        trim_whitespace=False,
         style={"input_type": "password"},
     )
     username = serializers.CharField(
@@ -128,10 +132,14 @@ class RemoteSerializer(ModelSerializer):
         write_only=True,
     )
     password = serializers.CharField(
-        help_text="The password to be used for authentication when syncing.",
+        help_text=_(
+            "The password to be used for authentication when syncing. Extra leading and trailing "
+            "whitespace characters are not trimmed."
+        ),
         required=False,
         allow_null=True,
         write_only=True,
+        trim_whitespace=False,
         style={"input_type": "password"},
     )
     pulp_last_updated = serializers.DateTimeField(


Test patch: