Skip to content

Commit 98f9363

Browse files
committed
Updated pr.
1 parent be93da1 commit 98f9363

File tree

3 files changed

+276
-239
lines changed

3 files changed

+276
-239
lines changed

ads/common/auth.py

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import copy
88
import os
99
from dataclasses import dataclass
10-
from typing import Any, Callable, Dict, Optional
10+
from typing import Any, Callable, Dict, Optional, Union
1111

1212
import ads.telemetry
1313
import oci
@@ -45,7 +45,7 @@ class AuthState(metaclass=SingletonMeta):
4545
oci_cli_auth: str = None
4646
oci_config_path: str = None
4747
oci_key_profile: str = None
48-
oci_config: str = None
48+
oci_config: Dict = None
4949
oci_signer: Any = None
5050
oci_signer_callable: Callable = None
5151
oci_signer_kwargs: Dict = None
@@ -66,7 +66,6 @@ def __post_init__(self):
6666
)
6767
self.oci_config = self.oci_config or {}
6868
self.oci_signer = self.oci_signer
69-
self.oci_signer_callable = self.oci_signer_callable
7069
self.oci_signer_kwargs = self.oci_signer_kwargs or {}
7170
self.oci_client_kwargs = self.oci_client_kwargs or {}
7271

@@ -82,15 +81,14 @@ def set_auth(
8281
client_kwargs: Optional[Dict] = {},
8382
) -> None:
8483
"""
85-
Save type of authentication, profile, config location, config (keypair identity) or signer, which will be used
86-
when actual creation of config or signer happens.
84+
Sets the default authentication type.
8785
8886
Parameters
8987
----------
9088
auth: Optional[str], default 'api_key'
9189
'api_key', 'resource_principal' or 'instance_principal'. Enable/disable resource principal identity,
9290
instance principal or keypair identity in a notebook session
93-
oci_config_location: Optional[str], default oci.config.DEFAULT_LOCATION, which is '~/.oci/config'
91+
oci_config_location: Optional[str], default '~/.oci/config'
9492
config file location
9593
profile: Optional[str], default is DEFAULT_PROFILE, which is 'DEFAULT'
9694
profile name for api keys config file
@@ -117,14 +115,50 @@ def set_auth(
117115
>>> ads.set_auth("api_key", oci_config_location = "other_config_location") # use non-default oci_config_location
118116
119117
>>> ads.set_auth("api_key", client_kwargs={"timeout": 60}) # default signer with connection and read timeouts set to 60 seconds for the client.
120-
>>> ads.set_auth("api_key", signer_kwargs={"key_content": "private_key_content"}) # Create config using key content
118+
121119
>>> other_config = oci.config.from_file("other_config_location", "OTHER_PROFILE") # Create non-default config
122120
>>> ads.set_auth(config=other_config) # Set api keys type of authentication based on provided config
123121
122+
>>> config={
123+
... user=ocid1.user.oc1..<unique_ID>,
124+
... fingerprint=<fingerprint>,
125+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
126+
... region=us-ashburn-1,
127+
... key_content=<private key content>,
128+
... }
129+
>>> ads.set_auth(config=config) # Set api key authentication using private key content based on provided config
130+
131+
>>> config={
132+
... user=ocid1.user.oc1..<unique_ID>,
133+
... fingerprint=<fingerprint>,
134+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
135+
... region=us-ashburn-1,
136+
... key_file=~/.oci/oci_api_key.pem,
137+
... }
138+
>>> ads.set_auth(config=config) # Set api key authentication using private key file location based on provided config
139+
124140
>>> ads.set_auth("resource_principal") # Set resource principal authentication
125141
126142
>>> ads.set_auth("instance_principal") # Set instance principal authentication
127143
144+
>>> singer = oci.signer.Signer(
145+
... user=ocid1.user.oc1..<unique_ID>,
146+
... fingerprint=<fingerprint>,
147+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
148+
... region=us-ashburn-1,
149+
... private_key_content=<private key content>,
150+
... )
151+
>>> ads.set_auth(singer=singer) # Set api keys authentication with private key content based on provided signer
152+
153+
>>> singer = oci.signer.Signer(
154+
... user=ocid1.user.oc1..<unique_ID>,
155+
... fingerprint=<fingerprint>,
156+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
157+
... region=us-ashburn-1,
158+
... private_key_file_location=<private key content>,
159+
... )
160+
>>> ads.set_auth(singer=singer) # Set api keys authentication with private key file location based on provided signer
161+
128162
>>> singer = oci.auth.signers.get_resource_principals_signer()
129163
>>> ads.auth.create_signer(config={}, singer=signer) # resource principals authentication dictionary created
130164
@@ -157,47 +191,30 @@ def set_auth(
157191

158192
auth_state.oci_config = config
159193
auth_state.oci_key_profile = profile
160-
if auth == AuthType.API_KEY and not signer and not signer_callable and not signer_kwargs:
161-
if os.path.exists(os.path.expanduser(oci_config_location)):
162-
auth_state.oci_config_path = oci_config_location
163-
else:
164-
raise ValueError(
165-
f"{oci_config_location} path does not exist, please provide existing path to config file."
166-
)
167-
194+
auth_state.oci_config_path = oci_config_location
168195
auth_state.oci_signer = signer
169196
auth_state.oci_signer_callable = signer_callable
170197
auth_state.oci_signer_kwargs = signer_kwargs
171198
auth_state.oci_client_kwargs = client_kwargs
172199

173200

174201
def api_keys(
175-
oci_config: str = os.path.join(os.path.expanduser("~"), ".oci", "config"),
202+
oci_config: Union[str, Dict] = os.path.expanduser(DEFAULT_LOCATION),
176203
profile: str = DEFAULT_PROFILE,
177204
client_kwargs: Dict = None,
178-
kwargs: Dict = None
179205
) -> Dict:
180206
"""
181207
Prepares authentication and extra arguments necessary for creating clients for different OCI services using API
182208
Keys.
183209
184210
Parameters
185211
----------
186-
oci_config: Optional[str], default is $HOME/.oci/config
187-
OCI authentication config file location.
212+
oci_config: Optional[Union[str, Dict]], default is ~/.oci/config
213+
OCI authentication config file location or a dictionary with config attributes.
188214
profile: Optional[str], is DEFAULT_PROFILE, which is 'DEFAULT'
189215
Profile name to select from the config file.
190216
client_kwargs: Optional[Dict], default None
191217
kwargs that are required to instantiate the Client if we need to override the defaults.
192-
kwargs:
193-
kwargs for API authentication signer.
194-
- user: OCID of the user calling the API.
195-
- tenancy: OCID of user's tenancy.
196-
- fingerprint: Fingerprint for the public key that was added to this user.
197-
- region: An Oracle Cloud Infrastructure region.
198-
- pass_phrase: Passphrase used for the key, if it is encrypted.
199-
- key_file: Full path and filename of the private key.
200-
- key_content: The private key as PEM string.
201218
202219
Returns
203220
-------
@@ -215,10 +232,12 @@ def api_keys(
215232
>>> oc.OCIClientFactory(**auth).object_storage # Creates Object storage client with timeout set to 6000 using API Key authentication
216233
"""
217234
signer_args = dict(
218-
oci_config_location=oci_config,
235+
oci_config=oci_config if isinstance(oci_config, Dict) else {},
236+
oci_config_location=oci_config
237+
if isinstance(oci_config, str)
238+
else os.path.expanduser(DEFAULT_LOCATION),
219239
oci_key_profile=profile,
220240
client_kwargs=client_kwargs,
221-
signer_kwargs=kwargs,
222241
)
223242
signer_generator = AuthFactory().signerGenerator(AuthType.API_KEY)
224243
return signer_generator(signer_args).create_signer()
@@ -302,6 +321,24 @@ def create_signer(
302321
>>> config = oci.config.from_file("other_config_location", "OTHER_PROFILE")
303322
>>> auth = ads.auth.create_signer(config=config) # api_key type of authentication dictionary created based on provided config
304323
324+
>>> config={
325+
... user=ocid1.user.oc1..<unique_ID>,
326+
... fingerprint=<fingerprint>,
327+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
328+
... region=us-ashburn-1,
329+
... key_content=<private key content>,
330+
... }
331+
>>> auth = ads.auth.create_signer(config=config) # api_key type of authentication dictionary with private key content created based on provided config
332+
333+
>>> config={
334+
... user=ocid1.user.oc1..<unique_ID>,
335+
... fingerprint=<fingerprint>,
336+
... tenancy=ocid1.tenancy.oc1..<unique_ID>,
337+
... region=us-ashburn-1,
338+
... key_file=~/.oci/oci_api_key.pem,
339+
... }
340+
>>> auth = ads.auth.create_signer(config=config) # api_key type of authentication dictionary with private key file location created based on provided config
341+
305342
>>> singer = oci.auth.signers.get_resource_principals_signer()
306343
>>> auth = ads.auth.create_signer(config={}, signer=signer) # resource principals authentication dictionary created
307344
@@ -327,7 +364,6 @@ def create_signer(
327364
oci_config_location=oci_config_location,
328365
oci_key_profile=profile,
329366
oci_config=config,
330-
signer_kwargs=signer_kwargs,
331367
client_kwargs=client_kwargs,
332368
)
333369
if config:
@@ -398,7 +434,6 @@ def default_signer(client_kwargs: Optional[Dict] = None) -> Dict:
398434
oci_config_location=auth_state.oci_config_path,
399435
oci_key_profile=auth_state.oci_key_profile,
400436
oci_config=auth_state.oci_config,
401-
signer_kwargs=auth_state.oci_signer_kwargs or {},
402437
client_kwargs={
403438
**(auth_state.oci_client_kwargs or {}),
404439
**(client_kwargs or {}),
@@ -483,22 +518,20 @@ def __init__(self, args: Optional[Dict] = None):
483518
- oci_config_location - path to config file
484519
- oci_key_profile - the profile to load from config file
485520
- client_kwargs - optional parameters for OCI client creation in next steps
486-
- signer_kwargs - optional parameters for signer
487521
"""
488522
self.oci_config = args.get("oci_config")
489523
self.oci_config_location = args.get("oci_config_location")
490524
self.oci_key_profile = args.get("oci_key_profile")
491525
self.client_kwargs = args.get("client_kwargs")
492-
self.signer_kwargs = args.get("signer_kwargs")
493526

494527
def create_signer(self) -> Dict:
495528
"""
496529
Creates api keys configuration and signer with extra arguments necessary for creating clients.
497530
Signer constructed from the `oci_config` provided. If not 'oci_config', configuration will be
498531
constructed from 'oci_config_location' and 'oci_key_profile' in place.
499532
500-
Resturns
501-
--------
533+
Returns
534+
-------
502535
dict
503536
Contains keys - config, signer and client_kwargs.
504537
@@ -517,23 +550,22 @@ def create_signer(self) -> Dict:
517550
"""
518551
if self.oci_config:
519552
configuration = ads.telemetry.update_oci_client_config(self.oci_config)
520-
elif self.signer_kwargs:
521-
configuration = ads.telemetry.update_oci_client_config(self.signer_kwargs)
522553
else:
523554
configuration = ads.telemetry.update_oci_client_config(
524555
oci.config.from_file(self.oci_config_location, self.oci_key_profile)
525556
)
526-
557+
558+
oci.config.validate_config(configuration)
527559
logger.info(f"Using 'api_key' authentication.")
528560
return {
529561
"config": configuration,
530562
"signer": oci.signer.Signer(
531-
configuration.get("tenancy"),
532-
configuration.get("user"),
533-
configuration.get("fingerprint"),
534-
configuration.get("key_file"),
535-
configuration.get("pass_phrase"),
536-
configuration.get("key_content")
563+
tenancy=configuration["tenancy"],
564+
user=configuration["user"],
565+
fingerprint=configuration["fingerprint"],
566+
private_key_file_location=configuration.get("key_file"),
567+
pass_phrase= configuration.get("pass_phrase"),
568+
private_key_content=configuration.get("key_content")
537569
),
538570
"client_kwargs": self.client_kwargs,
539571
}
@@ -563,8 +595,8 @@ def create_signer(self) -> Dict:
563595
"""
564596
Creates Resource Principal signer with extra arguments necessary for creating clients.
565597
566-
Resturns
567-
--------
598+
Returns
599+
-------
568600
dict
569601
Contains keys - config, signer and client_kwargs.
570602
@@ -619,8 +651,8 @@ def create_signer(self) -> Dict:
619651
Signer instantiated from the `signer_callable` or if the `signer` provided is will be return by this method.
620652
If `signer_callable` or `signer` not provided new signer will be created in place.
621653
622-
Resturns
623-
--------
654+
Returns
655+
-------
624656
dict
625657
Contains keys - config, signer and client_kwargs.
626658

docs/source/user_guide/cli/authentication.rst

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ The ``~/.oci/config`` configuration allow for multiple configurations to be stor
8282
ads.set_auth("api_key") # default signer is set to API Keys
8383
ads.set_auth("api_key", profile = "TEST") # default signer is set to API Keys and to use TEST profile
8484
ads.set_auth("api_key", oci_config_location = "~/.test_oci/config") # default signer is set to API Keys and to use non-default oci_config_location
85+
private_key_content = """
86+
-----BEGIN RSA PRIVATE KEY-----
87+
MIIBIjANBgkqhkiG9w0BAQE...
88+
...
89+
-----END RSA PRIVATE KEY-----
90+
"""
91+
config = dict(
92+
user="ocid1.user.oc1..xxx",
93+
fingerprint="35:67:25:90:89:87:45:78:bf:4h:g5:13:16:32:4d:f4",
94+
tenancy="ocid1.tenancy.oc1..xxx",
95+
region="us-ashburn-1",
96+
key_content=private_key_content,
97+
)
98+
ads.set_auth(config = config) # default signer is set to API Keys with private key content
99+
85100
ads.set_auth("resource_principal") # default signer is set to resource principal authentication
86101
ads.set_auth("instance_principal") # default signer is set to instance principal authentication
87102
@@ -139,21 +154,5 @@ More signers can be created using the ``create_signer()`` method. With the ``aut
139154
signer_callable = oci.auth.signers.InstancePrincipalsSecurityTokenSigner
140155
signer_kwargs = dict(log_requests=True) # will log the request url and response data when retrieving
141156
auth = ads.auth.create_signer(signer_callable=signer_callable, signer_kwargs=signer_kwargs)
142-
143-
# Example 4. Create signer that carries oci config in signer_kwargs. You can either pass key_file or key_content to signer_kwargs.
144-
private_key_content = """
145-
-----BEGIN RSA PRIVATE KEY-----
146-
MIIBIjANBgkqhkiG9w0BAQE...
147-
...
148-
-----END RSA PRIVATE KEY-----
149-
"""
150-
signer_kwargs = dict(
151-
user="ocid1.user.oc1..xxx",
152-
fingerprint="35:67:25:90:89:87:45:78:bf:4h:g5:13:16:32:4d:f4",
153-
tenancy="ocid1.tenancy.oc1..xxx",
154-
region="us-ashburn-1",
155-
key_content=private_key_content,
156-
)
157-
auth = ads.auth.create_signer(signer_kwargs=signer_kwargs)
158157
159158
``AuthContext`` context class can also be used to specify the desired type of authentication. It supports API key configuration, resource principal, and instance principal authentication, as well as predefined signers, callable signers, or API keys configurations from specified locations. See `API Documentation <../../ads.common.html#ads.common.auth.AuthContext>`__ for more details.

0 commit comments

Comments
 (0)