Skip to content

Commit 4a187ca

Browse files
gl-johnsonGitHub Enterprise
authored andcommitted
Merge pull request #32 from Conjur-Enterprise/docs-updates
CNJR-0000: Readme authentication updates
2 parents 3b4b182 + 0ca1de6 commit 4a187ca

File tree

5 files changed

+81
-52
lines changed

5 files changed

+81
-52
lines changed

.gitleaksignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignores for test files/examples
2+
f01985c225aa5d9ac815cc4c0ec8cc5327e44c4f:README.md:generic-api-key:72
3+
925cc7ebe3df6b63b16163c4c56a404bb7bcd874:ci/test/conjur-deployment/configuration/ldap/certs/ldap-server.key.pem:private-key:1
4+
925cc7ebe3df6b63b16163c4c56a404bb7bcd874:ci/test/conjur-deployment/configuration/oidc/certs/oidc-server.key.pem:private-key:1
5+
925cc7ebe3df6b63b16163c4c56a404bb7bcd874:ci/test/conjur-deployment/ubuntu_compose.yml:generic-api-key:35

.pylintrc

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ persistent=yes
3232
# Specify a configuration file.
3333
#rcfile=
3434

35-
# When enabled, pylint would attempt to guess common misconfiguration and emit
36-
# user-friendly hints instead of false-positive error messages.
37-
suggestion-mode=yes
38-
3935
# Allow loading of arbitrary C extensions. Extensions are imported into the
4036
# active Python interpreter and may run arbitrary code.
4137
unsafe-load-any-extension=no
@@ -508,4 +504,4 @@ preferred-modules=
508504

509505
# Exceptions that will emit a warning when being caught. Defaults to
510506
# "BaseException, Exception".
511-
overgeneral-exceptions=BaseException
507+
overgeneral-exceptions=builtins.BaseException

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88

9+
## [0.1.8] - 2025-11-07
10+
11+
### Changed
12+
- Remove `async_timeout` dependency
13+
- Clarify authentication methods in README.md
14+
915
## [0.1.7] - 2025-10-16
1016

1117
### Added

README.md

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,26 @@ pip3 install .
5959

6060
#### Define connection parameters
6161

62-
In order to login to Secrets Manager you need to have 5 parameters known from advance.
62+
In order to authenticate to Secrets Manager you need to have 5 parameters known in advance.
63+
**NOTE:** We include example values in the sample code for simplicity, but credentials and secrets should **never** be hardcoded.
6364

65+
As a host/workload:
6466
```python
6567
from conjur_api.models import SslVerificationMode
6668

6769
conjur_url = "https://my_conjur.com"
68-
account = "my_account"
70+
account = "conjur"
71+
role_id = "host/data/my-host"
72+
api_key = "m3y70m29xt8ya2aa9p4z1nj0dskra4wpn2913vjb6s0ffw1j6gkp7"
73+
ssl_verification_mode = SslVerificationMode.TRUST_STORE
74+
```
75+
76+
As a user (Only compatible with Secrets Manager Self-Hosted):
77+
```python
78+
from conjur_api.models import SslVerificationMode
79+
80+
conjur_url = "https://my_conjur.com"
81+
account = "conjur"
6982
username = "user1"
7083
password = "SomeStr@ngPassword!1"
7184
ssl_verification_mode = SslVerificationMode.TRUST_STORE
@@ -83,38 +96,49 @@ connection_info = ConjurConnectionInfo(conjur_url=conjur_url,account=account,cer
8396

8497
* conjur_url - url of Secrets Manager server
8598
* account - the account which we want to connect to
86-
* cert_file - a path to Secrets Manager rootCA file. we need it if we initialize the client in `SslVerificationMode.SELF_SIGN`
99+
* cert_file - a path to Secrets Manager rootCA file. Required if initializing the client in `SslVerificationMode.SELF_SIGN`
87100
or `SslVerificationMode.CA_BUNDLE` mode
88-
* service_id - a service id for the Secrets Manager authenticator. Required when using the ldap authenticator (see below) but not when using the default `authn` authenticator.
101+
* service_id - a service id for the Secrets Manager authenticator. Required when using an authenticator besides the default
102+
authn (see `Create Authentication Strategy`)
89103
* proxy_params - parameters for proxy connection. see `ProxyParams` class for more details - Optional
90104

91-
#### Create credentials provider
105+
#### Create Credentials Provider
92106

93-
The client uses credentials provider in order to get the connection credentials before making api command. This approach
94-
allow to keep the credentials in a safe location and provide it to the client on demand.
107+
The client uses a credentials provider in order to fetch connection credentials before making API calls. This allows credential
108+
storage in a safe location on the system.
95109

96-
We provide the user with `CredentialsProviderInterface` which can be implemented the way the user see as best
97-
fit (`keyring` usage for example)
110+
We provide the user with `CredentialsProviderInterface` which can be implemented to create a custom credentials provider that
111+
best fits the use case (`keyring` for example)
98112

99-
We also provide the user with a simple implementation of such provider called `SimpleCredentialsProvider`. Example of
100-
creating such provider + storing credentials:
113+
We also provide a simple implementation called `SimpleCredentialsProvider`. Example of
114+
creating a provider and storing credentials:
101115

102116
```python
103117
from conjur_api.models import CredentialsData
104118
from conjur_api.providers import SimpleCredentialsProvider
105119

120+
# If using API key (most common)
121+
credentials = CredentialsData(username=role_id, api_key=api_key, machine=conjur_url)
122+
123+
# If using username/password
106124
credentials = CredentialsData(username=username, password=password, machine=conjur_url)
125+
107126
credentials_provider = SimpleCredentialsProvider()
108127
credentials_provider.save(credentials)
109128
del credentials
110129
```
111130

112-
#### Create authentication strategy
113-
114-
The client also uses an authentication strategy in order to authenticate to Secrets Manager. This approach allows us to implement different authentication strategies
115-
(e.g. `authn`, `authn-ldap`, `authn-k8s`) and to keep the authentication logic separate from the client implementation.
131+
#### Create Authentication Strategy
116132

117-
We provide the `AuthnAuthenticationStrategy` for the default Secrets Manager authenticator. Example use:
133+
The client uses an authentication strategy in order to authenticate to Secrets Manager. This approach allows us to implement
134+
different authentication strategies while keeping logic separate from the client implementation. Supported strategies are based
135+
on different Secrets Manager authenticators:
136+
- authn (default)
137+
- authn-ldap
138+
- authn-oidc
139+
- authn-jwt
140+
141+
We provide the `AuthnAuthenticationStrategy` for the default Secrets Manager authenticator. Example usage:
118142

119143
```python
120144
from conjur_api.providers import AuthnAuthenticationStrategy
@@ -124,7 +148,7 @@ authn_provider = AuthnAuthenticationStrategy(credentials_provider)
124148

125149
We also provide the `LdapAuthenticationStrategy`, `OidcAuthenticationStrategy`, and `JWTAuthenticationStrategy` for the
126150
ldap, oidc, and jwt authenticators respectively.
127-
Example use:
151+
Example usage:
128152

129153
```python
130154
from conjur_api.providers import LdapAuthenticationStrategy, OidcAuthenticationStrategy, JWTAuthenticationStrategy
@@ -136,7 +160,7 @@ jwt_provider = JWTAuthenticationStrategy(token)
136160

137161
When using these strategies, make sure `connection_info` has a `service_id` specified.
138162

139-
#### Creating the client and use it
163+
#### Creating and using the client
140164

141165
Now that we have created `connection_info` and `authn_provider`, we can create our client:
142166

@@ -148,14 +172,14 @@ client = Client(connection_info,
148172
ssl_verification_mode=ssl_verification_mode)
149173
```
150174

151-
* ssl_verification_mode = `SslVerificationMode` enum that states what is the certificate verification technique we will
152-
use when making the api request
175+
* ssl_verification_mode = `SslVerificationMode` enum that states what is the certificate verification technique to be
176+
used when making requests
153177

154178
After creating the client we can login to Secrets Manager and start using it. Example of usage:
155179

156180
```python
157-
client.login() # login to conjur and return the api_key
158-
client.list() # get list of all conjur resources that the user authorize to read
181+
client.login() # NOTE: Only applicable for username/password authentication on Self-Hosted
182+
client.list() # List Secrets Manager resources the role is authorized to read
159183
```
160184

161185
## Supported Client methods
@@ -287,7 +311,7 @@ endpoint is still subject to breaking changes in the future._
287311

288312
#### `authenticate()`
289313

290-
Performs an authentication with Secrets Manager, based on the authentication strategy and credentials provider there were given to the client.
314+
Performs an authentication with Secrets Manager, based on the authentication strategy and credentials provider that were given to the client.
291315
This method is not required, it will also be done implicitly and automatically when session with Secrets Manager needs to be refreshed.
292316

293317
## Contributing
@@ -297,7 +321,7 @@ development workflows, please see our [contributing guide](CONTRIBUTING.md).
297321

298322
## License
299323

300-
Copyright (c) 2020 CyberArk Software Ltd. All rights reserved.
324+
Copyright (c) 2025 CyberArk Software Ltd. All rights reserved.
301325

302326
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
303327
License. You may obtain a copy of the License at

conjur_api/wrappers/http_wrapper.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
from typing import Union
1616
from urllib.parse import quote
1717

18-
import async_timeout
1918
import urllib3
20-
from aiohttp import BasicAuth, ClientError, ClientResponseError, ClientSSLError, ClientSession
19+
from aiohttp import BasicAuth, ClientError, ClientResponseError, ClientSSLError, ClientSession, ClientTimeout
2120

2221
from conjur_api.errors.errors import CertificateHostnameMismatchException, HttpSslError, HttpError, HttpStatusError
2322
from conjur_api.http.endpoints import ConjurEndpoint
@@ -171,27 +170,26 @@ async def invoke_request(http_verb: HttpVerb,
171170
This method preforms the actual request and catches possible SSLErrors to
172171
perform more user-friendly messages
173172
"""
174-
async with ClientSession() as session:
175-
async with async_timeout.timeout(REQUEST_TIMEOUT_SECONDS):
176-
ssl_context = __create_ssl_context(ssl_verification_metadata)
177-
try:
178-
async with session.request(http_verb.name,
179-
url,
180-
data=data,
181-
params=query,
182-
ssl=ssl_context,
183-
auth=BasicAuth(*auth) if auth else None,
184-
headers=headers,
185-
proxy=proxy_params.proxy_url if proxy_params else None) as response:
186-
return await HttpResponse.from_client_response(response)
187-
188-
except ClientSSLError as ssl_error:
189-
host_mismatch_message = re.search("hostname '.+' doesn't match", str(ssl_error))
190-
if host_mismatch_message:
191-
raise CertificateHostnameMismatchException from ssl_error
192-
raise HttpSslError(message=str(ssl_error)) from ssl_error
193-
except ClientError as request_error:
194-
raise HttpError() from request_error
173+
async with ClientSession(timeout=ClientTimeout(total=REQUEST_TIMEOUT_SECONDS)) as session:
174+
ssl_context = __create_ssl_context(ssl_verification_metadata)
175+
try:
176+
async with session.request(http_verb.name,
177+
url,
178+
data=data,
179+
params=query,
180+
ssl=ssl_context,
181+
auth=BasicAuth(*auth) if auth else None,
182+
headers=headers,
183+
proxy=proxy_params.proxy_url if proxy_params else None) as response:
184+
return await HttpResponse.from_client_response(response)
185+
186+
except ClientSSLError as ssl_error:
187+
host_mismatch_message = re.search("hostname '.+' doesn't match", str(ssl_error))
188+
if host_mismatch_message:
189+
raise CertificateHostnameMismatchException from ssl_error
190+
raise HttpSslError(message=str(ssl_error)) from ssl_error
191+
except ClientError as request_error:
192+
raise HttpError() from request_error
195193

196194

197195
def __create_ssl_context(ssl_verification_metadata: SslVerificationMetadata) -> Union[bool, ssl.SSLContext]:

0 commit comments

Comments
 (0)