Repository: pdm-project/pdm (Python)

Issue:
Fail to authenticate for Azure Artifacts
## Steps to reproduce
To add a private pypi from Azure Artifacts, I added a section in the `pyproject.toml` as follows:

```
[[tool.pdm.source]]
name = "datahub"
url = "https://pkgs.dev.azure.com/xxx/Datahub/_packaging/Datahub/pypi/simple/"
verify_ssl = true
```

I try to add a package to the pyproject.toml that is available in the private repo by:
`pdm add datahub-cli==0.2.0a6 -v`

## Actual behavior
When I run the above command, I get the message below:
```
Adding packages to default dependencies: datahub-cli==0.2.0a6
STATUS: Resolving dependencies
pdm.termui: ======== Start resolving requirements ========
pdm.termui:   datahub-cli==0.2.0a6
pdm.termui:   python==3.12.*
pdm.termui:   Adding requirement datahub-cli==0.2.0a6
unearth.collector: Failed to collect links from https://pypi.org/simple/datahub-cli/: Client Error(404): Not Found

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
   at NuGetCredentialProvider.Program.<Main>d__3.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at NuGetCredentialProvider.Program.Main(String[] args)
   at NuGetCredentialProvider.Program.<Main>(String[] args)
unearth.auth: Keyring is skipped due to an exception: Failed to get credentials: process with PID 24148 exited with code 3762504530; additional error message: 
User for pkgs.dev.azure.com:
```
However, when I pass personal login information via the `pyproject.toml` in the `tool.pdm.source` section (which I don't want), it does work. 

The same error also appears, when I want to install a package from a public pypi, which is very inconvenient.

## Expected behavior
Package from private pypi is added to `pyproject.toml` and installed.

## Environment Information
`pdm info; pdm info --env `:

```bash
PDM version:
  2.13.2
Python Interpreter:
  C:\Users\avanwestreenen\OneDrive - Waterschap Vallei Veluwe\Projects\PlayGround2\.venv\Scripts\python.exe (3.12)
Project Root:
  C:/Users/avanwestreenen/OneDrive - Waterschap Vallei Veluwe/Projects/PlayGround2
Local Packages:

{
  "implementation_name": "cpython",
  "implementation_version": "3.12.2",
  "os_name": "nt",
  "platform_machine": "AMD64",
  "platform_release": "11",
  "platform_system": "Windows",
  "platform_version": "10.0.22631",
  "python_full_version": "3.12.2",
  "platform_python_implementation": "CPython",
  "python_version": "3.12",
  "sys_platform": "win32"
}

```



Discussion: There seems to be some issue with the keyring that can't be fixed on PDM side, you can check it by running keyring directly:

```python
import keyring
keyring.get_credential(url, username)
keyring.get_password(url, username)
```

> However, when I pass personal login information via the `pyproject.toml` in the `tool.pdm.source` section (which I don't want), it does work.

You can also set it in config:

```
pdm config pypi.datahub.username "xxxx"
pdm config pypi.datahub.password "xxxxx"
```
> There seems to be some issue with the keyring that can't be fixed on PDM side, you can check it by running keyring directly:
> 
> ```python
> import keyring
> keyring.get_credential(url, username)
> keyring.get_password(url, username)
> ```

Hmm, using this `keyring`-only example, I do not get any errors. Would you expect this example raises a similar error as with pdm? 

> You can also set it in config:
> 
> ```
> pdm config pypi.datahub.username "xxxx"
> pdm config pypi.datahub.password "xxxxx"
> ```
Sure, good point. Can indeed use this as a workaround.

I have manage to get all authentication to work with azure artifacts by running the following:

`pdm self add keyring artifacts-keyring`

And then simply add `[[tool.pdm.source]]` as you did above with the `url=` for your artifacts feed





Fix (patch):
diff --git a/docs/usage/config.md b/docs/usage/config.md
index 31bf5f504d..e7fecdbd13 100644
--- a/docs/usage/config.md
+++ b/docs/usage/config.md
@@ -300,6 +300,18 @@ Alternatively, if you have installed a copy of keyring globally, make sure the C
 export PATH=$PATH:path/to/keyring/bin
 ```
 
+### Password management with keyring for Azure Artifacts
+
+When trying to authenticate towards azure artifacts, this can be achieved by either using AD groups to authenticate: `pdm self add keyring artifacts-keyring` ensuring that artifacts-keyring will be used for authentication.
+
+And then adding the artifacts url to `pyproject.toml`
+
+```
+[[tool.pdm.source]]
+name = "NameOfFeed"
+url = "https://pkgs.dev.azure.com/[org name]/_packaging/[feed name]/pypi/simple/"
+```
+
 ## Override the resolved package versions
 
 +++ 1.12.0
diff --git a/news/2851.bugfix.md b/news/2851.bugfix.md
new file mode 100644
index 0000000000..bf5721a778
--- /dev/null
+++ b/news/2851.bugfix.md
@@ -0,0 +1,1 @@
+Fixed pdm venv activate, to also work for windows. And added documentation on how to authenticate to Azure Artifacts
\ No newline at end of file
diff --git a/src/pdm/cli/commands/venv/activate.py b/src/pdm/cli/commands/venv/activate.py
index d827cababc..a8fe5a0161 100644
--- a/src/pdm/cli/commands/venv/activate.py
+++ b/src/pdm/cli/commands/venv/activate.py
@@ -1,4 +1,5 @@
 import argparse
+import platform
 import shlex
 from pathlib import Path
 
@@ -55,9 +56,11 @@ def get_activate_command(self, venv: VirtualEnv) -> str:  # pragma: no cover
             command, filename = "source", "activate"
         activate_script = venv.interpreter.with_name(filename)
         if activate_script.exists():
+            if platform.system() == "Windows":
+                return f"{self.quote(str(activate_script), shell)}"
             return f"{command} {self.quote(str(activate_script), shell)}"
         # Conda backed virtualenvs don't have activate scripts
-        return f"conda activate {shlex.quote(str(venv.root))}"
+        return f"conda activate {self.quote(str(venv.root), shell)}"
 
     @staticmethod
     def quote(command: str, shell: str) -> str: