Skip to content

Commit 934a941

Browse files
committed
feat: add auth network options
1 parent 55de34c commit 934a941

4 files changed

Lines changed: 76 additions & 10 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath"
3-
version = "2.0.73"
3+
version = "2.0.74"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.10"

src/uipath/_cli/_auth/_client_credentials.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@
1313
class ClientCredentialsService:
1414
"""Service for client credentials authentication flow."""
1515

16-
def __init__(self, domain: str):
16+
def __init__(
17+
self, domain: str, verify_ssl: bool = True, cert: str = None, proxy: str = None
18+
):
1719
self.domain = domain
20+
self.verify_ssl = verify_ssl
21+
self.cert = cert
22+
self.proxy = proxy
1823

1924
def get_token_url(self) -> str:
2025
"""Get the token URL for the specified domain."""
@@ -91,7 +96,17 @@ def authenticate(
9196
}
9297

9398
try:
94-
with httpx.Client(timeout=30.0) as client:
99+
client_kwargs = {"timeout": 30.0}
100+
101+
if not self.verify_ssl:
102+
client_kwargs["verify"] = False
103+
elif self.cert:
104+
client_kwargs["verify"] = self.cert
105+
106+
if self.proxy:
107+
client_kwargs["proxies"] = self.proxy
108+
109+
with httpx.Client(**client_kwargs) as client:
95110
response = client.post(token_url, data=data)
96111

97112
match response.status_code:

src/uipath/_cli/_auth/_portal_service.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
)
1717

1818
console = ConsoleLogger()
19-
client = httpx.Client(follow_redirects=True, timeout=30.0)
2019

2120

2221
class PortalService:
@@ -27,25 +26,47 @@ class PortalService:
2726
domain: Optional[str] = None
2827
selected_tenant: Optional[str] = None
2928

29+
_client: httpx.Client = None
30+
3031
_tenants_and_organizations: Optional[TenantsAndOrganizationInfoResponse] = None
3132

3233
def __init__(
3334
self,
3435
domain: str,
3536
access_token: Optional[str] = None,
3637
prt_id: Optional[str] = None,
38+
verify_ssl: bool = True,
39+
cert: str = None,
40+
proxy: str = None,
3741
):
3842
self.domain = domain
3943
self.access_token = access_token
4044
self.prt_id = prt_id
4145

46+
client_kwargs = {"follow_redirects": True, "timeout": 30.0}
47+
48+
if not verify_ssl:
49+
client_kwargs["verify"] = False
50+
elif cert:
51+
client_kwargs["verify"] = cert
52+
53+
if proxy:
54+
client_kwargs["proxies"] = proxy
55+
56+
self._client = httpx.Client(**client_kwargs)
57+
58+
def __del__(self):
59+
"""Cleanup method to close the HTTP client."""
60+
if hasattr(self, "_client") and self._client:
61+
self._client.close()
62+
4263
def update_token_data(self, token_data: TokenData):
4364
self.access_token = token_data["access_token"]
4465
self.prt_id = get_parsed_token_data(token_data).get("prt_id")
4566

4667
def get_tenants_and_organizations(self) -> TenantsAndOrganizationInfoResponse:
4768
url = f"https://{self.domain}.uipath.com/{self.prt_id}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo"
48-
response = client.get(
69+
response = self._client.get(
4970
url, headers={"Authorization": f"Bearer {self.access_token}"}
5071
)
5172
if response.status_code < 400:
@@ -83,7 +104,7 @@ def post_refresh_token_request(self, refresh_token: str) -> TokenData:
83104

84105
headers = {"Content-Type": "application/x-www-form-urlencoded"}
85106

86-
response = client.post(url, data=data, headers=headers)
107+
response = self._client.post(url, data=data, headers=headers)
87108
if response.status_code < 400:
88109
return response.json()
89110
elif response.status_code == 401:
@@ -148,7 +169,7 @@ def post_auth(self, base_url: str) -> None:
148169

149170
try:
150171
[try_enable_first_run_response, acquire_license_response] = [
151-
client.post(
172+
self._client.post(
152173
url,
153174
headers={"Authorization": f"Bearer {self.access_token}"},
154175
)

src/uipath/_cli/cli_auth.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,45 @@ def set_port():
8080
required=False,
8181
help="Base URL for the UiPath tenant instance (required for client credentials)",
8282
)
83+
@click.option(
84+
"--no-verify-ssl",
85+
"--insecure",
86+
is_flag=True,
87+
required=False,
88+
help="Disable SSL certificate verification (not recommended for production)",
89+
)
90+
@click.option(
91+
"--cert",
92+
required=False,
93+
type=click.Path(exists=True),
94+
help="Path to custom CA certificate bundle file (for corporate certificates)",
95+
)
96+
@click.option(
97+
"--proxy",
98+
required=False,
99+
help="Proxy URL in format: http://proxy:port or https://proxy:port",
100+
)
83101
@track
84102
def auth(
85103
domain,
86104
force: None | bool = False,
87105
client_id: str = None,
88106
client_secret: str = None,
89107
base_url: str = None,
108+
no_verify_ssl: bool = False,
109+
cert: str = None,
110+
proxy: str = None,
90111
):
91112
"""Authenticate with UiPath Cloud Platform.
92113
93114
Interactive mode (default): Opens browser for OAuth authentication.
94115
Unattended mode: Use --client-id, --client-secret and --base-url for client credentials flow.
116+
117+
Network options:
118+
- Use --cert to specify custom CA certificates for corporate environments
119+
- Use --no-verify-ssl to disable SSL verification (not recommended)
120+
- Use --proxy to configure proxy settings (e.g., --proxy http://proxy:8080)
121+
- Set HTTP_PROXY/HTTPS_PROXY environment variables for proxy configuration
95122
"""
96123
# Check if client credentials are provided for unattended authentication
97124
if client_id and client_secret:
@@ -102,8 +129,9 @@ def auth(
102129
return
103130

104131
with console.spinner("Authenticating with client credentials ..."):
105-
# Create service instance
106-
credentials_service = ClientCredentialsService(domain)
132+
credentials_service = ClientCredentialsService(
133+
domain, verify_ssl=not no_verify_ssl, cert=cert, proxy=proxy
134+
)
107135

108136
# If base_url is provided, extract domain from it to override the CLI domain parameter
109137
if base_url:
@@ -127,7 +155,9 @@ def auth(
127155

128156
# Interactive authentication flow (existing logic)
129157
with console.spinner("Authenticating with UiPath ..."):
130-
portal_service = PortalService(domain)
158+
portal_service = PortalService(
159+
domain, verify_ssl=not no_verify_ssl, cert=cert, proxy=proxy
160+
)
131161

132162
if not force:
133163
if (

0 commit comments

Comments
 (0)