Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removal of OAuth2 stuff from CLI #15613

Open
wants to merge 10 commits into
base: devel
Choose a base branch
from
Open
3 changes: 2 additions & 1 deletion awx_collection/plugins/module_utils/awxkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
def authenticate(self):
try:
if self.oauth_token:
self.connection.login(None, None, token=self.oauth_token)
# MERGE: fix conflicts with removal of OAuth2 token from collection branch
self.connection.login(None, None)

Check warning on line 38 in awx_collection/plugins/module_utils/awxkit.py

View check run for this annotation

Codecov / codecov/patch

awx_collection/plugins/module_utils/awxkit.py#L38

Added line #L38 was not covered by tests
self.authenticated = True
elif self.username:
self.connection.login(username=self.username, password=self.password)
Expand Down
5 changes: 0 additions & 5 deletions awx_collection/plugins/modules/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,6 @@
- workflow names, IDs, or named URLs to export
type: list
elements: str
applications:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not remove the applications module from the Collection PR. I thought it was used for more purposes apart from Oauth. Is it not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think applications serve any purpose other than for creating tokens. IMO, the tests seemed to reflect this. It's not impossible that I'm wrong, but it seemed relatively clear even from reading the issue for this PR.

description:
- OAuth2 application names, IDs, or named URLs to export
type: list
elements: str
schedules:
description:
- schedule names, IDs, or named URLs to export
Expand Down
1 change: 0 additions & 1 deletion awx_collection/test/awx/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"job_templates",
"workflow_job_templates",
"execution_environments",
"applications",
"schedules",
])

Expand Down
13 changes: 1 addition & 12 deletions awxkit/awxkit/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@ class ConnectionException(exc.Common):
pass


class Token_Auth(requests.auth.AuthBase):
def __init__(self, token):
self.token = token

def __call__(self, request):
request.headers['Authorization'] = 'Bearer {0.token}'.format(self)
return request


def log_elapsed(r, *args, **kwargs): # requests hook to display API elapsed time
log.debug('"{0.request.method} {0.url}" elapsed: {0.elapsed}'.format(r))

Expand All @@ -47,7 +38,7 @@ def get_session_requirements(self, next=config.api_base_path):
self.get(config.api_base_path) # this causes a cookie w/ the CSRF token to be set
return dict(next=next)

def login(self, username=None, password=None, token=None, **kwargs):
def login(self, username=None, password=None, **kwargs):
if username and password:
_next = kwargs.get('next')
if _next:
Expand All @@ -62,8 +53,6 @@ def login(self, username=None, password=None, token=None, **kwargs):
self.uses_session_cookie = True
else:
self.session.auth = (username, password)
elif token:
self.session.auth = Token_Auth(token)
else:
self.session.auth = None

Expand Down
2 changes: 0 additions & 2 deletions awxkit/awxkit/api/pages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
from .bulk import * # NOQA
from .access_list import * # NOQA
from .api import * # NOQA
from .authtoken import * # NOQA
from .roles import * # NOQA
from .organizations import * # NOQA
from .notifications import * # NOQA
from .notification_templates import * # NOQA
from .users import * # NOQA
from .applications import * # NOQA
from .teams import * # NOQA
from .credentials import * # NOQA
from .unified_jobs import * # NOQA
Expand Down
1 change: 0 additions & 1 deletion awxkit/awxkit/api/pages/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
'job_templates',
'workflow_job_templates',
'execution_environments',
'applications',
'schedules',
]

Expand Down
82 changes: 0 additions & 82 deletions awxkit/awxkit/api/pages/applications.py

This file was deleted.

10 changes: 0 additions & 10 deletions awxkit/awxkit/api/pages/authtoken.py

This file was deleted.

72 changes: 1 addition & 71 deletions awxkit/awxkit/api/pages/base.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
import collections
import logging
import typing

from requests.auth import HTTPBasicAuth

from awxkit.api.pages import Page, get_registered_page, exception_from_status_code
from awxkit.api.pages import Page
from awxkit.config import config
from awxkit.api.resources import resources
import awxkit.exceptions as exc


log = logging.getLogger(__name__)


class AuthUrls(typing.TypedDict):
access_token: str
personal_token: str


class Base(Page):
def silent_delete(self):
"""Delete the object. If it's already deleted, ignore the error"""
Expand Down Expand Up @@ -135,66 +125,6 @@ def object_roles(self):
for obj_role in Roles(self.connection, endpoint=url).get().json.results:
yield Role(self.connection, endpoint=obj_role.url).get()

def get_authtoken(self, username='', password=''):
default_cred = config.credentials.default
payload = dict(username=username or default_cred.username, password=password or default_cred.password)
auth_url = resources.authtoken
return get_registered_page(auth_url)(self.connection, endpoint=auth_url).post(payload).token

def load_authtoken(self, username='', password=''):
self.connection.login(token=self.get_authtoken(username, password))
return self

load_default_authtoken = load_authtoken

def _request_token(self, auth_urls, username, password, client_id, description, client_secret, scope):
req = collections.namedtuple('req', 'headers')({})
if client_id and client_secret:
HTTPBasicAuth(client_id, client_secret)(req)
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
resp = self.connection.post(
auth_urls["access_token"],
data={"grant_type": "password", "username": username, "password": password, "scope": scope},
headers=req.headers,
)
elif client_id:
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
resp = self.connection.post(
auth_urls["access_token"],
data={"grant_type": "password", "username": username, "password": password, "client_id": client_id, "scope": scope},
headers=req.headers,
)
else:
HTTPBasicAuth(username, password)(req)
resp = self.connection.post(
auth_urls['personal_token'],
json={"description": description, "application": None, "scope": scope},
headers=req.headers,
)
if resp.ok:
result = resp.json()
if client_id:
return result.pop('access_token', None)
else:
return result.pop('token', None)
else:
raise exception_from_status_code(resp.status_code)

def get_oauth2_token(self, username='', password='', client_id=None, description='AWX CLI', client_secret=None, scope='write'):
default_cred = config.credentials.default
username = username or default_cred.username
password = password or default_cred.password
# Try gateway first, fallback to controller
urls: AuthUrls = {"access_token": "/o/token/", "personal_token": f"{config.gateway_base_path}v1/tokens/"}
try:
return self._request_token(urls, username, password, client_id, description, client_secret, scope)
except exc.NotFound:
urls = {
"access_token": f"{config.api_base_path}o/token/",
"personal_token": f"{config.api_base_path}v2/users/{username}/personal_tokens/",
}
return self._request_token(urls, username, password, client_id, description, client_secret, scope)

def load_session(self, username='', password=''):
default_cred = config.credentials.default
self.connection.login(
Expand Down
12 changes: 1 addition & 11 deletions awxkit/awxkit/api/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ class Resources(object):
_ad_hoc_related_cancel = r'ad_hoc_commands/\d+/cancel/'
_ad_hoc_relaunch = r'ad_hoc_commands/\d+/relaunch/'
_ansible_facts = r'hosts/\d+/ansible_facts/'
_application = r'applications/\d+/'
_applications = 'applications/'
_auth = 'auth/'
_authtoken = 'authtoken/'
_bulk = 'bulk/'
_bulk_job_launch = 'bulk/job_launch/'
_config = 'config/'
Expand Down Expand Up @@ -233,8 +230,6 @@ class Resources(object):
_team_permissions = r'teams/\d+/permissions/'
_team_users = r'teams/\d+/users/'
_teams = 'teams/'
_token = r'tokens/\d+/'
_tokens = 'tokens/'
_unified_job_template = r'unified_job_templates/\d+/'
_unified_job_templates = 'unified_job_templates/'
_unified_jobs = 'unified_jobs/'
Expand Down Expand Up @@ -282,12 +277,7 @@ class Resources(object):
def __getattr__(self, resource):
if resource[:3] == '___':
raise AttributeError('No existing resource: {}'.format(resource))
# Currently we don't handle anything under:
# /api/o/
# /api/login/
# /api/logout/
# If/when we do we will probably need to modify this __getattr__ method
# Also, if we add another API version, this would be handled here
# If/when we add another API version, this would be handled here
prefix = 'v2'
resource = '_' + resource
return '{0}{1}'.format(getattr(self, prefix), getattr(self, resource))
Expand Down
13 changes: 1 addition & 12 deletions awxkit/awxkit/awx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
@contextmanager
def as_user(v, username, password=None):
"""Context manager to allow running tests as an alternative login user."""
access_token = False
if not isinstance(v, api.client.Connection):
connection = v.connection
else:
Expand All @@ -83,11 +82,6 @@
password = username.password
username = username.username

if isinstance(username, api.OAuth2AccessToken):
access_token = username.token
username = None
password = None

try:
if config.use_sessions:
session_id = None
Expand All @@ -101,19 +95,14 @@
break
if session_id:
del connection.session.cookies[connection.session_cookie_name]
if access_token:
kwargs = dict(token=access_token)
else:
kwargs = connection.get_session_requirements()
kwargs = connection.get_session_requirements()

Check warning on line 98 in awxkit/awxkit/awx/utils.py

View check run for this annotation

Codecov / codecov/patch

awxkit/awxkit/awx/utils.py#L98

Added line #L98 was not covered by tests
else:
previous_auth = connection.session.auth
kwargs = dict()
connection.login(username, password, **kwargs)
yield
finally:
if config.use_sessions:
if access_token:
connection.session.auth = None
del connection.session.cookies[connection.session_cookie_name]
if session_id:
connection.session.cookies.set(connection.session_cookie_name, session_id, domain=domain)
Expand Down
16 changes: 4 additions & 12 deletions awxkit/awxkit/cli/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,9 @@
return '--help' in self.argv or '-h' in self.argv

def authenticate(self):
"""Configure the current session (or OAuth2.0 token)"""
token = self.get_config('token')
if token:
self.root.connection.login(
None,
None,
token=token,
)
else:
config.use_sessions = True
self.root.load_session().get()
"""Configure the current session for basic auth"""
config.use_sessions = True
self.root.load_session().get()

Check warning on line 87 in awxkit/awxkit/cli/client.py

View check run for this annotation

Codecov / codecov/patch

awxkit/awxkit/cli/client.py#L86-L87

Added lines #L86 - L87 were not covered by tests

def connect(self):
"""Fetch top-level resources from /api/v2"""
Expand Down Expand Up @@ -141,7 +133,7 @@
"""Attempt to parse the <resource> (e.g., jobs) specified on the CLI

If a valid resource is discovered, the user will be authenticated
(either via an OAuth2.0 token or session-based auth) and the remaining
(via session-based auth) and the remaining
CLI arguments will be processed (to determine the requested action
e.g., list, create, delete)

Expand Down
3 changes: 0 additions & 3 deletions awxkit/awxkit/cli/docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,3 @@ A few of the most important ones are:

``--conf.password, CONTROLLER_PASSWORD``
the AWX password to use for authentication

``--conf.token, CONTROLLER_OAUTH_TOKEN``
an OAuth2.0 token to use for authentication
6 changes: 0 additions & 6 deletions awxkit/awxkit/cli/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ def add_authentication_arguments(parser, env):
default=env.get('CONTROLLER_HOST', env.get('TOWER_HOST', 'https://127.0.0.1:443')),
metavar='https://example.awx.org',
)
auth.add_argument(
'--conf.token',
default=env.get('CONTROLLER_OAUTH_TOKEN', env.get('CONTROLLER_TOKEN', env.get('TOWER_OAUTH_TOKEN', env.get('TOWER_TOKEN', '')))),
help='an OAuth2.0 token (get one by using `awx login`)',
metavar='TEXT',
)

config_username, config_password = get_config_credentials()
# options configured via cli args take higher precedence than those from the config
Expand Down
Loading
Loading