|
27 | 27 |
|
28 | 28 | __all__ = [ |
29 | 29 | 'create_client_from_env', |
| 30 | + 'employee_client', |
30 | 31 | 'Client', |
31 | 32 | 'BaseClient', |
32 | 33 | 'API_PUBLIC_ENDPOINT', |
@@ -142,6 +143,88 @@ def create_client_from_env(username=None, |
142 | 143 | return BaseClient(auth=auth, transport=transport, config_file=config_file) |
143 | 144 |
|
144 | 145 |
|
| 146 | +def employee_client(username=None, |
| 147 | + api_key=None, |
| 148 | + endpoint_url=None, |
| 149 | + timeout=None, |
| 150 | + auth=None, |
| 151 | + config_file=None, |
| 152 | + proxy=None, |
| 153 | + user_agent=None, |
| 154 | + transport=None, |
| 155 | + verify=True): |
| 156 | + """Creates an INTERNAL SoftLayer API client using your environment. |
| 157 | +
|
| 158 | + Settings are loaded via keyword arguments, environemtal variables and |
| 159 | + config file. |
| 160 | +
|
| 161 | + :param username: your user ID |
| 162 | + :param api_key: hash from SoftLayer_User_Employee::performExternalAuthentication(username, password, 2fa_string) |
| 163 | + :param endpoint_url: the API endpoint base URL you wish to connect to. |
| 164 | + Set this to API_PRIVATE_ENDPOINT to connect via SoftLayer's private |
| 165 | + network. |
| 166 | + :param proxy: proxy to be used to make API calls |
| 167 | + :param integer timeout: timeout for API requests |
| 168 | + :param auth: an object which responds to get_headers() to be inserted into |
| 169 | + the xml-rpc headers. Example: `BasicAuthentication` |
| 170 | + :param config_file: A path to a configuration file used to load settings |
| 171 | + :param user_agent: an optional User Agent to report when making API |
| 172 | + calls if you wish to bypass the packages built in User Agent string |
| 173 | + :param transport: An object that's callable with this signature: |
| 174 | + transport(SoftLayer.transports.Request) |
| 175 | + :param bool verify: decide to verify the server's SSL/TLS cert. DO NOT SET |
| 176 | + TO FALSE WITHOUT UNDERSTANDING THE IMPLICATIONS. |
| 177 | +
|
| 178 | + Usage: |
| 179 | +
|
| 180 | + >>> import SoftLayer |
| 181 | + >>> client = SoftLayer.create_client_from_env() |
| 182 | + >>> resp = client.call('Account', 'getObject') |
| 183 | + >>> resp['companyName'] |
| 184 | + 'Your Company' |
| 185 | +
|
| 186 | + """ |
| 187 | + settings = config.get_client_settings(username=username, |
| 188 | + api_key=api_key, |
| 189 | + endpoint_url=endpoint_url, |
| 190 | + timeout=timeout, |
| 191 | + proxy=proxy, |
| 192 | + verify=verify, |
| 193 | + config_file=config_file) |
| 194 | + |
| 195 | + if transport is None: |
| 196 | + url = settings.get('endpoint_url') |
| 197 | + if url is not None and '/rest' in url: |
| 198 | + # If this looks like a rest endpoint, use the rest transport |
| 199 | + transport = transports.RestTransport( |
| 200 | + endpoint_url=settings.get('endpoint_url'), |
| 201 | + proxy=settings.get('proxy'), |
| 202 | + timeout=settings.get('timeout'), |
| 203 | + user_agent=user_agent, |
| 204 | + verify=verify, |
| 205 | + ) |
| 206 | + else: |
| 207 | + # Default the transport to use XMLRPC |
| 208 | + transport = transports.XmlRpcTransport( |
| 209 | + endpoint_url=settings.get('endpoint_url'), |
| 210 | + proxy=settings.get('proxy'), |
| 211 | + timeout=settings.get('timeout'), |
| 212 | + user_agent=user_agent, |
| 213 | + verify=verify, |
| 214 | + ) |
| 215 | + |
| 216 | + |
| 217 | + if auth is None and settings.get('username') and settings.get('api_key'): |
| 218 | + real_transport = getattr(transport, 'transport', transport) |
| 219 | + if isinstance(real_transport, transports.XmlRpcTransport): |
| 220 | + auth = slauth.EmployeeAuthentication( |
| 221 | + settings.get('username'), |
| 222 | + settings.get('api_key'), |
| 223 | + ) |
| 224 | + |
| 225 | + return BaseClient(auth=auth, transport=transport) |
| 226 | + |
| 227 | + |
145 | 228 | def Client(**kwargs): |
146 | 229 | """Get a SoftLayer API Client using environmental settings. |
147 | 230 |
|
@@ -545,6 +628,77 @@ def __repr__(self): |
545 | 628 | return "IAMClient(transport=%r, auth=%r)" % (self.transport, self.auth) |
546 | 629 |
|
547 | 630 |
|
| 631 | +class EmployeeClient(BaseClient): |
| 632 | + """Internal SoftLayer Client |
| 633 | +
|
| 634 | + :param auth: auth driver that looks like SoftLayer.auth.AuthenticationBase |
| 635 | + :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request) |
| 636 | + """ |
| 637 | + |
| 638 | + def authenticate_with_password(self, username, password, security_token=None): |
| 639 | + """Performs IBM IAM Username/Password Authentication |
| 640 | +
|
| 641 | + :param string username: your softlayer username |
| 642 | + :param string password: your softlayer password |
| 643 | + :param int security_token: your 2FA token, prompt if None |
| 644 | + """ |
| 645 | + |
| 646 | + self.auth = None |
| 647 | + if security_token is None: |
| 648 | + security_token = input("Enter your 2FA Token now: ") |
| 649 | + if len(security_token) != 6: |
| 650 | + raise Exception("Invalid security token: {}".format(security_token)) |
| 651 | + |
| 652 | + auth_result = self.call('SoftLayer_User_Employee', 'performExternalAuthentication', |
| 653 | + username, password, security_token) |
| 654 | + |
| 655 | + |
| 656 | + self.settings['softlayer']['access_token'] = auth_result['hash'] |
| 657 | + self.settings['softlayer']['userId'] = auth_result['userId'] |
| 658 | + # self.settings['softlayer']['refresh_token'] = tokens['refresh_token'] |
| 659 | + |
| 660 | + config.write_config(self.settings, self.config_file) |
| 661 | + self.auth = slauth.EmployeeAuthentication(auth_result['userId'], auth_result['hash']) |
| 662 | + |
| 663 | + return auth_result |
| 664 | + |
| 665 | + |
| 666 | + |
| 667 | + def authenticate_with_hash(self, userId, access_token): |
| 668 | + """Authenticates to the Internal SL API with an employee userid + token |
| 669 | +
|
| 670 | + :param string userId: Employee UserId |
| 671 | + :param string access_token: Employee Hash Token |
| 672 | + """ |
| 673 | + self.auth = slauth.EmployeeAuthentication(userId, access_token) |
| 674 | + |
| 675 | + def refresh_token(self, userId, auth_token): |
| 676 | + """Refreshes the login token""" |
| 677 | + |
| 678 | + self.auth = None |
| 679 | + auth_result = self.call('SoftLayer_User_Employee', 'refreshEncryptedToken', auth_token, id=userId) |
| 680 | + print(auth_result) |
| 681 | + self.settings['softlayer']['access_token'] = auth_result[0] |
| 682 | + |
| 683 | + config.write_config(self.settings, self.config_file) |
| 684 | + self.auth = slauth.EmployeeAuthentication(userId, auth_result[0]) |
| 685 | + return auth_result |
| 686 | + |
| 687 | + def call(self, service, method, *args, **kwargs): |
| 688 | + """Handles refreshing IAM tokens in case of a HTTP 401 error""" |
| 689 | + try: |
| 690 | + return super().call(service, method, *args, **kwargs) |
| 691 | + except exceptions.SoftLayerAPIError as ex: |
| 692 | + |
| 693 | + if ex.faultCode == 401: |
| 694 | + LOGGER.warning("Token has expired, trying to refresh. %s", ex.faultString) |
| 695 | + return ex |
| 696 | + else: |
| 697 | + raise ex |
| 698 | + |
| 699 | + def __repr__(self): |
| 700 | + return "IAMClient(transport=%r, auth=%r)" % (self.transport, self.auth) |
| 701 | + |
548 | 702 | class Service(object): |
549 | 703 | """A SoftLayer Service. |
550 | 704 |
|
|
0 commit comments