Ejemplo n.º 1
0
def check_logged_in():
    # first, try to get the refresh tokens from config
    # we can skip the access tokens and their expiration times as those are not
    # strictly necessary
    transfer_rt = lookup_option(TRANSFER_RT_OPTNAME)
    auth_rt = lookup_option(AUTH_RT_OPTNAME)

    # if either of the refresh tokens are null return False
    if transfer_rt is None or auth_rt is None:
        return False

    # get or create the instance client
    auth_client = internal_auth_client(requires_instance=True)

    # check that tokens and client are valid
    try:
        for tok in (transfer_rt, auth_rt):
            res = auth_client.oauth2_validate_token(tok)
            if not res["active"]:
                return False

    # if the instance client is invalid, an AuthAPIError will be raised
    # we then force a new client to be created before continuing
    except AuthAPIError:
        return False

    return True
Ejemplo n.º 2
0
def check_logged_in():
    # first, try to get the refresh tokens from config
    # we can skip the access tokens and their expiration times as those are not
    # strictly necessary
    transfer_rt = lookup_option(TRANSFER_RT_OPTNAME)
    auth_rt = lookup_option(AUTH_RT_OPTNAME)

    # if either of the refresh tokens are null return False
    if (transfer_rt is None or auth_rt is None):
        return False

    # get or create the instance client
    auth_client = internal_auth_client(requires_instance=True)

    # check that tokens and client are valid
    try:
        for tok in (transfer_rt, auth_rt):
            res = auth_client.oauth2_validate_token(tok)
            if not res['active']:
                return False

    # if the instance client is invalid, an AuthAPIError will be raised
    # we then force a new client to be created before continuing
    except AuthAPIError:
        return False

    return True
Ejemplo n.º 3
0
def check_logged_in():
    # first, try to get the refresh tokens from config
    # we can skip the access tokens and their expiration times as those are not
    # strictly necessary
    transfer_rt = lookup_option(TRANSFER_RT_OPTNAME)
    auth_rt = lookup_option(AUTH_RT_OPTNAME)

    # if either of the refresh tokens are null return False
    if (transfer_rt is None or auth_rt is None):
        return False

    # check that tokens are valid
    native_client = internal_auth_client()
    for tok in (transfer_rt, auth_rt):
        res = native_client.oauth2_validate_token(tok)
        if not res['active']:
            return False

    return True
Ejemplo n.º 4
0
def logout_command():
    # try to get the user's preferred username from userinfo
    # if an API error is raised, they probably are not logged in
    try:
        username = get_auth_client().oauth2_userinfo()["preferred_username"]
    except AuthAPIError:
        safeprint(("Unable to lookup username. You may not be logged in. "
                   "Attempting logout anyway...\n"))
        username = None
    safeprint(
        u'Logging out of Globus{}\n'.format(u' as ' +
                                            username if username else ''))

    # build the NativeApp client object
    native_client = internal_auth_client()

    # remove tokens from config and revoke them
    # also, track whether or not we should print the rescind help
    print_rescind_help = False
    for token_opt in (TRANSFER_RT_OPTNAME, TRANSFER_AT_OPTNAME,
                      AUTH_RT_OPTNAME, AUTH_AT_OPTNAME):
        # first lookup the token -- if not found we'll continue
        token = lookup_option(token_opt)
        if not token:
            safeprint(('Warning: Found no token named "{}"! '
                       'Recommend rescinding consent').format(token_opt))
            print_rescind_help = True
            continue
        # token was found, so try to revoke it
        try:
            native_client.oauth2_revoke_token(token)
        # if we network error, revocation failed -- print message and abort so
        # that we can revoke later when the network is working
        except globus_sdk.NetworkError:
            safeprint(('Failed to reach Globus to revoke tokens. '
                       'Because we cannot revoke these tokens, cancelling '
                       'logout'))
            click.get_current_context().exit(1)
        # finally, we revoked, so it's safe to remove the token
        remove_option(token_opt)

    # remove expiration times, just for cleanliness
    for expires_opt in (TRANSFER_AT_EXPIRES_OPTNAME, AUTH_AT_EXPIRES_OPTNAME):
        remove_option(expires_opt)

    # if print_rescind_help is true, we printed warnings above
    # so, jam out an extra newline as a separator
    safeprint(("\n" if print_rescind_help else "") + _LOGOUT_EPILOG)

    # if some token wasn't found in the config, it means its possible that the
    # config file was removed without logout
    # in that case, the user should rescind the CLI consent to invalidate any
    # potentially leaked refresh tokens, so print the help on that
    if print_rescind_help:
        safeprint(_RESCIND_HELP)
Ejemplo n.º 5
0
def show_command(parameter):
    """Show a value from the Globus config file"""
    section = "cli"
    if "." in parameter:
        section, parameter = parameter.split(".", 1)

    value = lookup_option(parameter, section=section)

    if value is None:
        click.echo("{} not set".format(parameter))
    else:
        click.echo("{} = {}".format(parameter, value))
Ejemplo n.º 6
0
def session_show():
    """List all identities in your current CLI auth session.

    Lists identities that are in the session tied to the CLI's access tokens along with
    the time the user authenticated with that identity.
    """
    # get a token to introspect, refreshing if neccecary
    auth_client = internal_auth_client()
    try:
        auth_client.authorizer._check_expiration_time()
    except AttributeError:  # if we have no RefreshTokenAuthorizor
        pass
    access_token = lookup_option(AUTH_AT_OPTNAME)

    # only instance clients can introspect tokens
    if isinstance(auth_client, globus_sdk.ConfidentialAppAuthClient):
        res = auth_client.oauth2_token_introspect(access_token,
                                                  include="session_info")

        session_info = res.get("session_info", {})
        authentications = session_info.get("authentications") or {}

    # empty session if still using Native App Client
    else:
        session_info = {}
        authentications = {}

    # resolve ids to human readable usernames
    resolved_ids = globus_sdk.IdentityMap(get_auth_client(),
                                          list(authentications))

    # put the nested dicts in a format table output can work with
    # while also converting vals into human readable formats
    list_data = [{
        "id":
        key,
        "username":
        resolved_ids.get(key, {}).get("username"),
        "auth_time":
        time.strftime("%Y-%m-%d %H:%M %Z", time.localtime(vals["auth_time"])),
    } for key, vals in authentications.items()]

    print_command_hint(
        "For information on your primary identity or full identity set see\n"
        "  globus whoami\n")

    formatted_print(
        list_data,
        json_converter=lambda x: session_info,
        fields=[("Username", "username"), ("ID", "id"),
                ("Auth Time", "auth_time")],
    )
Ejemplo n.º 7
0
def show_command(parameter):
    """
    Executor for `globus config show`
    """
    section = "cli"
    if "." in parameter:
        section, parameter = parameter.split(".", 1)

    value = lookup_option(parameter, section=section)

    if value is None:
        click.echo("{} not set".format(parameter))
    else:
        click.echo("{} = {}".format(parameter, value))
Ejemplo n.º 8
0
def show_command(parameter):
    """
    Executor for `globus config show`
    """
    section = "cli"
    if "." in parameter:
        section, parameter = parameter.split(".", 1)

    value = lookup_option(parameter, section=section)

    if value is None:
        safeprint("{} not set".format(parameter))
    else:
        safeprint("{} = {}".format(parameter, value))
Ejemplo n.º 9
0
def show_command(parameter):
    """
    Executor for `globus config show`
    """
    section = "cli"
    if '.' in parameter:
        section, parameter = parameter.split('.', 1)

    value = lookup_option(parameter, section=section)

    if value is None:
        safeprint('{} not set'.format(parameter))
    else:
        safeprint('{} = {}'.format(parameter, value))
Ejemplo n.º 10
0
def session_show():
    # get a token to introspect, refreshing if neccecary
    auth_client = internal_auth_client()
    try:
        auth_client.authorizer._check_expiration_time()
    except AttributeError:  # if we have no RefreshTokenAuthorizor
        pass
    access_token = lookup_option(AUTH_AT_OPTNAME)

    # only instance clients can introspect tokens
    if isinstance(auth_client, globus_sdk.ConfidentialAppAuthClient):
        res = auth_client.oauth2_token_introspect(access_token, include="session_info")

        session_info = res.get("session_info", {})
        authentications = session_info.get("authentications") or {}

    # empty session if still using Native App Client
    else:
        session_info = {}
        authentications = {}

    # resolve ids to human readable usernames
    resolved_ids = LazyIdentityMap(list(authentications))

    # put the nested dicts in a format table output can work with
    # while also converting vals into human readable formats
    list_data = [
        {
            "id": key,
            "username": resolved_ids.get(key),
            "auth_time": time.strftime(
                "%Y-%m-%d %H:%M %Z", time.localtime(vals["auth_time"])
            ),
        }
        for key, vals in authentications.items()
    ]

    print_command_hint(
        "For information on your primary identity or full identity set see\n"
        "  globus whoami\n"
    )

    formatted_print(
        list_data,
        json_converter=lambda x: session_info,
        fields=[("Username", "username"), ("ID", "id"), ("Auth Time", "auth_time")],
    )
Ejemplo n.º 11
0
def exchange_code_and_store_config(auth_client, auth_code):
    """
    Finishes auth flow after code is gotten from command line or local server.
    Exchanges code for tokens and gets user info from auth.
    Stores tokens and user info in config.
    """
    # do a token exchange with the given code
    tkn = auth_client.oauth2_exchange_code_for_tokens(auth_code)
    tkn = tkn.by_resource_server

    store_queue = []

    def _enqueue(optname, newval, revoke=True):
        store_queue.append((optname, newval, revoke))

    # extract access tokens from final response
    if "transfer.api.globus.org" in tkn:
        _enqueue(TRANSFER_RT_OPTNAME, tkn["transfer.api.globus.org"]["refresh_token"])
        _enqueue(TRANSFER_AT_OPTNAME, tkn["transfer.api.globus.org"]["access_token"])
        _enqueue(
            TRANSFER_AT_EXPIRES_OPTNAME,
            tkn["transfer.api.globus.org"]["expires_at_seconds"],
            revoke=False,
        )
    if "auth.globus.org" in tkn:
        _enqueue(AUTH_RT_OPTNAME, tkn["auth.globus.org"]["refresh_token"])
        _enqueue(AUTH_AT_OPTNAME, tkn["auth.globus.org"]["access_token"])
        _enqueue(
            AUTH_AT_EXPIRES_OPTNAME,
            tkn["auth.globus.org"]["expires_at_seconds"],
            revoke=False,
        )

    # revoke any existing tokens
    for optname in [optname for (optname, _val, revoke) in store_queue if revoke]:
        token = lookup_option(optname)
        if token:
            auth_client.oauth2_revoke_token(token)

    # write new data to config
    for optname, newval, _revoke in store_queue:
        write_option(optname, newval)
Ejemplo n.º 12
0
def exchange_code_and_store_config(native_client, auth_code):
    """
    Finishes login flow after code is gotten from command line or local server.
    Exchanges code for tokens and gets user info from auth.
    Stores tokens and user info in config.
    """
    # do a token exchange with the given code
    tkn = native_client.oauth2_exchange_code_for_tokens(auth_code)
    tkn = tkn.by_resource_server

    # extract access tokens from final response
    transfer_at = (tkn['transfer.api.globus.org']['access_token'])
    transfer_at_expires = (
        tkn['transfer.api.globus.org']['expires_at_seconds'])
    transfer_rt = (tkn['transfer.api.globus.org']['refresh_token'])
    auth_at = (tkn['auth.globus.org']['access_token'])
    auth_at_expires = (tkn['auth.globus.org']['expires_at_seconds'])
    auth_rt = (tkn['auth.globus.org']['refresh_token'])

    # get the identity that the tokens were issued to
    auth_client = AuthClient(authorizer=AccessTokenAuthorizer(auth_at))
    res = auth_client.oauth2_userinfo()

    # revoke any existing tokens
    for token_opt in (TRANSFER_RT_OPTNAME, TRANSFER_AT_OPTNAME,
                      AUTH_RT_OPTNAME, AUTH_AT_OPTNAME):
        token = lookup_option(token_opt)
        if token:
            native_client.oauth2_revoke_token(token)

    # write new tokens to config
    write_option(TRANSFER_RT_OPTNAME, transfer_rt)
    write_option(TRANSFER_AT_OPTNAME, transfer_at)
    write_option(TRANSFER_AT_EXPIRES_OPTNAME, transfer_at_expires)
    write_option(AUTH_RT_OPTNAME, auth_rt)
    write_option(AUTH_AT_OPTNAME, auth_at)
    write_option(AUTH_AT_EXPIRES_OPTNAME, auth_at_expires)

    safeprint(_LOGIN_EPILOG.format(res["preferred_username"]))
Ejemplo n.º 13
0
def exchange_code_and_store_config(auth_client, auth_code):
    """
    Finishes auth flow after code is gotten from command line or local server.
    Exchanges code for tokens and gets user info from auth.
    Stores tokens and user info in config.
    """
    # do a token exchange with the given code
    tkn = auth_client.oauth2_exchange_code_for_tokens(auth_code)
    tkn = tkn.by_resource_server

    # extract access tokens from final response
    transfer_at = (
        tkn['transfer.api.globus.org']['access_token'])
    transfer_at_expires = (
        tkn['transfer.api.globus.org']['expires_at_seconds'])
    transfer_rt = (
        tkn['transfer.api.globus.org']['refresh_token'])
    auth_at = (
        tkn['auth.globus.org']['access_token'])
    auth_at_expires = (
        tkn['auth.globus.org']['expires_at_seconds'])
    auth_rt = (
        tkn['auth.globus.org']['refresh_token'])

    # revoke any existing tokens
    for token_opt in (TRANSFER_RT_OPTNAME, TRANSFER_AT_OPTNAME,
                      AUTH_RT_OPTNAME, AUTH_AT_OPTNAME):
        token = lookup_option(token_opt)
        if token:
            auth_client.oauth2_revoke_token(token)

    # write new tokens to config
    write_option(TRANSFER_RT_OPTNAME, transfer_rt)
    write_option(TRANSFER_AT_OPTNAME, transfer_at)
    write_option(TRANSFER_AT_EXPIRES_OPTNAME, transfer_at_expires)
    write_option(AUTH_RT_OPTNAME, auth_rt)
    write_option(AUTH_AT_OPTNAME, auth_at)
    write_option(AUTH_AT_EXPIRES_OPTNAME, auth_at_expires)
Ejemplo n.º 14
0
def exchange_code_and_store_config(auth_client, auth_code):
    """
    Finishes auth flow after code is gotten from command line or local server.
    Exchanges code for tokens and gets user info from auth.
    Stores tokens and user info in config.
    """
    # do a token exchange with the given code
    tkn = auth_client.oauth2_exchange_code_for_tokens(auth_code)
    tkn = tkn.by_resource_server

    # extract access tokens from final response
    transfer_at = tkn["transfer.api.globus.org"]["access_token"]
    transfer_at_expires = tkn["transfer.api.globus.org"]["expires_at_seconds"]
    transfer_rt = tkn["transfer.api.globus.org"]["refresh_token"]
    auth_at = tkn["auth.globus.org"]["access_token"]
    auth_at_expires = tkn["auth.globus.org"]["expires_at_seconds"]
    auth_rt = tkn["auth.globus.org"]["refresh_token"]

    # revoke any existing tokens
    for token_opt in (
        TRANSFER_RT_OPTNAME,
        TRANSFER_AT_OPTNAME,
        AUTH_RT_OPTNAME,
        AUTH_AT_OPTNAME,
    ):
        token = lookup_option(token_opt)
        if token:
            auth_client.oauth2_revoke_token(token)

    # write new tokens to config
    write_option(TRANSFER_RT_OPTNAME, transfer_rt)
    write_option(TRANSFER_AT_OPTNAME, transfer_at)
    write_option(TRANSFER_AT_EXPIRES_OPTNAME, transfer_at_expires)
    write_option(AUTH_RT_OPTNAME, auth_rt)
    write_option(AUTH_AT_OPTNAME, auth_at)
    write_option(AUTH_AT_EXPIRES_OPTNAME, auth_at_expires)
Ejemplo n.º 15
0
def endpoint_activate(endpoint_id, myproxy, myproxy_username, myproxy_password,
                      myproxy_lifetime, web, no_browser, delegate_proxy,
                      proxy_lifetime, no_autoactivate, force):
    """
    Executor for `globus endpoint activate`
    """
    default_myproxy_username = lookup_option(MYPROXY_USERNAME_OPTNAME)
    client = get_client()

    # validate options
    if web + myproxy + bool(delegate_proxy) > 1:
        raise click.UsageError(
            "--web, --myproxy, and --delegate-proxy are mutually exclusive.")
    if no_autoactivate and not (myproxy or web or delegate_proxy):
        raise click.UsageError(
            "--no-autoactivate requires another activation method be given.")
    if myproxy_username and not myproxy:
        raise click.UsageError("--myproxy-username requires --myproxy.")
    if myproxy_password and not myproxy:
        raise click.UsageError("--myproxy-password requires --myproxy.")
    # NOTE: "0" is a legitimate, though weird, value
    # In the case where someone is setting this value programatically,
    # respecting it behaves more consistently/predictably
    if myproxy_lifetime is not None and not myproxy:
        raise click.UsageError("--myproxy-lifetime requires --myproxy.")
    if no_browser and not web:
        raise click.UsageError("--no-browser requires --web.")
    if proxy_lifetime and not delegate_proxy:
        raise click.UsageError("--proxy-lifetime requires --delegate-proxy.")

    # check if endpoint is already activated unless --force
    if not force:
        res = client.endpoint_autoactivate(endpoint_id, if_expires_in=60)

        if "AlreadyActivated" == res["code"]:
            formatted_print(
                res,
                simple_text=("Endpoint is already activated. Activation "
                             "expires at {}".format(res["expire_time"])))
            return

    # attempt autoactivation unless --no-autoactivate
    if not no_autoactivate:

        res = client.endpoint_autoactivate(endpoint_id)

        if "AutoActivated" in res["code"]:
            formatted_print(
                res,
                simple_text=(
                    "Autoactivation succeeded with message: {}".format(
                        res["message"])))
            return

        # override potentially confusing autoactivation failure response
        else:
            message = ("The endpoint could not be auto-activated.\n\n" +
                       activation_requirements_help_text(res, endpoint_id))
            res = {"message": message}

    # myproxy activation
    if myproxy:

        # get username and password
        if not (myproxy_username or default_myproxy_username):
            myproxy_username = click.prompt("Myproxy username")
        if not myproxy_password:
            myproxy_password = click.prompt("Myproxy password",
                                            hide_input=True)

        no_server_msg = ("This endpoint has no myproxy server "
                         "and so cannot be activated through myproxy")

        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id).data

        if not len(requirements_data["DATA"]):
            raise click.ClickException(no_server_msg)

        for data in requirements_data["DATA"]:
            # skip non-myproxy values
            # although the API does not practice this today, in theory other
            # activation types may have fields with the same names...
            if data["type"] != "myproxy":
                continue

            if data["name"] == "passphrase":
                data["value"] = myproxy_password
            if data["name"] == "username":
                data["value"] = myproxy_username or default_myproxy_username
            if data["name"] == "hostname" and data["value"] is None:
                raise click.ClickException(no_server_msg)
            # NOTE: remember that "0" is a possible value
            if (data["name"] == "lifetime_in_hours"
                    and myproxy_lifetime is not None):
                data["value"] = str(myproxy_lifetime)

        res = client.endpoint_activate(endpoint_id, requirements_data)

    # web activation
    elif web:
        url = ("https://www.globus.org/app/"
               "endpoints/{}/activate".format(endpoint_id))
        if no_browser or is_remote_session():
            res = {"message": "Web activation url: {}".format(url), "url": url}
        else:
            webbrowser.open(url, new=1)
            res = {
                "message": "Browser opened to web activation page",
                "url": url
            }

    # delegate proxy activation
    elif delegate_proxy:
        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id).data
        filled_requirements_data = fill_delegate_proxy_activation_requirements(
            requirements_data,
            delegate_proxy,
            lifetime_hours=proxy_lifetime or 12)
        res = client.endpoint_activate(endpoint_id, filled_requirements_data)

    # output
    formatted_print(res, text_format=FORMAT_TEXT_RAW, response_key='message')
Ejemplo n.º 16
0
def endpoint_activate(
    endpoint_id,
    myproxy,
    myproxy_username,
    myproxy_password,
    myproxy_lifetime,
    web,
    no_browser,
    delegate_proxy,
    proxy_lifetime,
    no_autoactivate,
    force,
):
    """
    Executor for `globus endpoint activate`
    """
    default_myproxy_username = lookup_option(MYPROXY_USERNAME_OPTNAME)
    client = get_client()

    # validate options
    if web + myproxy + bool(delegate_proxy) > 1:
        raise click.UsageError(
            "--web, --myproxy, and --delegate-proxy are mutually exclusive."
        )
    if no_autoactivate and not (myproxy or web or delegate_proxy):
        raise click.UsageError(
            "--no-autoactivate requires another activation method be given."
        )
    if myproxy_username and not myproxy:
        raise click.UsageError("--myproxy-username requires --myproxy.")
    if myproxy_password and not myproxy:
        raise click.UsageError("--myproxy-password requires --myproxy.")
    # NOTE: "0" is a legitimate, though weird, value
    # In the case where someone is setting this value programatically,
    # respecting it behaves more consistently/predictably
    if myproxy_lifetime is not None and not myproxy:
        raise click.UsageError("--myproxy-lifetime requires --myproxy.")
    if no_browser and not web:
        raise click.UsageError("--no-browser requires --web.")
    if proxy_lifetime and not delegate_proxy:
        raise click.UsageError("--proxy-lifetime requires --delegate-proxy.")

    # check if endpoint is already activated unless --force
    if not force:
        res = client.endpoint_autoactivate(endpoint_id, if_expires_in=60)

        if "AlreadyActivated" == res["code"]:
            formatted_print(
                res,
                simple_text=(
                    "Endpoint is already activated. Activation "
                    "expires at {}".format(res["expire_time"])
                ),
            )
            return

    # attempt autoactivation unless --no-autoactivate
    if not no_autoactivate:

        res = client.endpoint_autoactivate(endpoint_id)

        if "AutoActivated" in res["code"]:
            formatted_print(
                res,
                simple_text=(
                    "Autoactivation succeeded with message: {}".format(res["message"])
                ),
            )
            return

        # override potentially confusing autoactivation failure response
        else:
            message = (
                "The endpoint could not be auto-activated.\n\n"
                + activation_requirements_help_text(res, endpoint_id)
            )
            res = {"message": message}

    # myproxy activation
    if myproxy:

        # get username and password
        if not (myproxy_username or default_myproxy_username):
            myproxy_username = click.prompt("Myproxy username")
        if not myproxy_password:
            myproxy_password = click.prompt("Myproxy password", hide_input=True)

        no_server_msg = (
            "This endpoint has no myproxy server "
            "and so cannot be activated through myproxy"
        )

        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id
        ).data

        if not len(requirements_data["DATA"]):
            raise click.ClickException(no_server_msg)

        for data in requirements_data["DATA"]:
            # skip non-myproxy values
            # although the API does not practice this today, in theory other
            # activation types may have fields with the same names...
            if data["type"] != "myproxy":
                continue

            if data["name"] == "passphrase":
                data["value"] = myproxy_password
            if data["name"] == "username":
                data["value"] = myproxy_username or default_myproxy_username
            if data["name"] == "hostname" and data["value"] is None:
                raise click.ClickException(no_server_msg)
            # NOTE: remember that "0" is a possible value
            if data["name"] == "lifetime_in_hours" and myproxy_lifetime is not None:
                data["value"] = str(myproxy_lifetime)

        res = client.endpoint_activate(endpoint_id, requirements_data)

    # web activation
    elif web:
        url = "https://app.globus.org/file-manager" "?origin_id={}".format(endpoint_id)
        if no_browser or is_remote_session():
            res = {"message": "Web activation url: {}".format(url), "url": url}
        else:
            webbrowser.open(url, new=1)
            res = {"message": "Browser opened to web activation page", "url": url}

    # delegate proxy activation
    elif delegate_proxy:
        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id
        ).data
        filled_requirements_data = fill_delegate_proxy_activation_requirements(
            requirements_data, delegate_proxy, lifetime_hours=proxy_lifetime or 12
        )
        res = client.endpoint_activate(endpoint_id, filled_requirements_data)

    # output
    formatted_print(res, text_format=FORMAT_TEXT_RAW, response_key="message")
Ejemplo n.º 17
0
def logout_command():
    # try to get the user's preferred username from userinfo
    # if an API error is raised, they probably are not logged in
    try:
        username = get_auth_client().oauth2_userinfo()["preferred_username"]
    except AuthAPIError:
        click.echo(("Unable to lookup username. You may not be logged in. "
                    "Attempting logout anyway...\n"))
        username = None
    click.echo(
        u"Logging out of Globus{}\n".format(u" as " +
                                            username if username else ""))

    # we use a Native Client to prevent an invalid instance client
    # from preventing token revocation
    native_client = internal_native_client()

    # remove tokens from config and revoke them
    # also, track whether or not we should print the rescind help
    print_rescind_help = False
    for token_opt in (
            TRANSFER_RT_OPTNAME,
            TRANSFER_AT_OPTNAME,
            AUTH_RT_OPTNAME,
            AUTH_AT_OPTNAME,
    ):
        # first lookup the token -- if not found we'll continue
        token = lookup_option(token_opt)
        if not token:
            click.echo(('Warning: Found no token named "{}"! '
                        "Recommend rescinding consent").format(token_opt))
            print_rescind_help = True
            continue
        # token was found, so try to revoke it
        try:
            native_client.oauth2_revoke_token(token)
        # if we network error, revocation failed -- print message and abort so
        # that we can revoke later when the network is working
        except globus_sdk.NetworkError:
            click.echo(("Failed to reach Globus to revoke tokens. "
                        "Because we cannot revoke these tokens, cancelling "
                        "logout"))
            click.get_current_context().exit(1)
        # finally, we revoked, so it's safe to remove the token
        remove_option(token_opt)

    # delete the instance client if one exists
    client_id = lookup_option(CLIENT_ID_OPTNAME)

    if client_id:
        instance_client = internal_auth_client()
        try:
            instance_client.delete("/v2/api/clients/{}".format(client_id))

        # if the client secret has been invalidated or the client has
        # already been removed, we continue on
        except AuthAPIError:
            pass

    # remove deleted client values and expiration times
    for opt in (
            CLIENT_ID_OPTNAME,
            CLIENT_SECRET_OPTNAME,
            TRANSFER_AT_EXPIRES_OPTNAME,
            AUTH_AT_EXPIRES_OPTNAME,
    ):
        remove_option(opt)

    # if print_rescind_help is true, we printed warnings above
    # so, jam out an extra newline as a separator
    click.echo(("\n" if print_rescind_help else "") + _LOGOUT_EPILOG)

    # if some token wasn't found in the config, it means its possible that the
    # config file was removed without logout
    # in that case, the user should rescind the CLI consent to invalidate any
    # potentially leaked refresh tokens, so print the help on that
    if print_rescind_help:
        click.echo(_RESCIND_HELP)
Ejemplo n.º 18
0
def endpoint_activate(
    endpoint_id,
    myproxy,
    myproxy_username,
    myproxy_password,
    myproxy_lifetime,
    web,
    no_browser,
    delegate_proxy,
    proxy_lifetime,
    no_autoactivate,
    force,
):
    """
    Activate an endpoint using Autoactivation, Myproxy, Delegate Proxy,
    or Web activation.
    Note that --web, --delegate-proxy, and --myproxy activation are mutually
    exclusive options.

    \b
    Autoactivation will always be attempted unless the --no-autoactivate
    option is given. If autoactivation succeeds any other activation options
    will be ignored as the endpoint has already been successfully activated.

    \b
    To use Web activation use the --web option.
    The CLI will try to open your default browser to the endpoint's activation
    page, but if a remote CLI session is detected, or the --no-browser option
    is given, a url will be printed for you to manually follow and activate
    the endpoint.

    \b
    To use Myproxy activation give the --myproxy option.
    Myproxy activation requires your username and password for the myproxy
    server the endpoint is using for authentication. e.g. for default
    Globus Connect Server endpoints this will be your login credentials for the
    server the endpoint is hosted on.
    You can enter your username when prompted, give your username with the
    --myproxy-username option, or set a default myproxy username in config with
    "globus config init" or "globus config set cli.default_myproxy_username".
    For security it is recommended that you only enter your password when
    prompted to hide your inputs and keep your password out of your
    command history, but you may pass your password with the hidden
    --myproxy-password or -P options.

    \b
    To use Delegate Proxy activation use the --delegate-proxy option with a
    file containing an X.509 certificate as an argument (e.g. an X.509
    gotten from the myproxy-logon command). This certificate must
    be a valid credential or proxy credential for the user from an identity
    provider accepted by the endpoint being activated, and the endpoint must be
    configured with a gridmap that will match the globus user using this
    command with the local user the certificate was made to. Note if the X.509
    is valid, but the endpoint does not recognize the identity provider or the
    user the error will not be detected until the user attempts to perform an
    operation on the endpoint.
    """
    default_myproxy_username = lookup_option(MYPROXY_USERNAME_OPTNAME)
    client = get_client()

    # validate options
    if web + myproxy + bool(delegate_proxy) > 1:
        raise click.UsageError(
            "--web, --myproxy, and --delegate-proxy are mutually exclusive.")
    if no_autoactivate and not (myproxy or web or delegate_proxy):
        raise click.UsageError(
            "--no-autoactivate requires another activation method be given.")
    if myproxy_username and not myproxy:
        raise click.UsageError("--myproxy-username requires --myproxy.")
    if myproxy_password and not myproxy:
        raise click.UsageError("--myproxy-password requires --myproxy.")
    # NOTE: "0" is a legitimate, though weird, value
    # In the case where someone is setting this value programatically,
    # respecting it behaves more consistently/predictably
    if myproxy_lifetime is not None and not myproxy:
        raise click.UsageError("--myproxy-lifetime requires --myproxy.")
    if no_browser and not web:
        raise click.UsageError("--no-browser requires --web.")
    if proxy_lifetime and not delegate_proxy:
        raise click.UsageError("--proxy-lifetime requires --delegate-proxy.")

    # check if endpoint is already activated unless --force
    if not force:
        res = client.endpoint_autoactivate(endpoint_id, if_expires_in=60)

        if "AlreadyActivated" == res["code"]:
            formatted_print(
                res,
                simple_text=("Endpoint is already activated. Activation "
                             "expires at {}".format(res["expire_time"])),
            )
            return

    # attempt autoactivation unless --no-autoactivate
    if not no_autoactivate:

        res = client.endpoint_autoactivate(endpoint_id)

        if "AutoActivated" in res["code"]:
            formatted_print(
                res,
                simple_text=(
                    "Autoactivation succeeded with message: {}".format(
                        res["message"])),
            )
            return

        # override potentially confusing autoactivation failure response
        else:
            message = ("The endpoint could not be auto-activated.\n\n" +
                       activation_requirements_help_text(res, endpoint_id))
            res = {"message": message}

    # myproxy activation
    if myproxy:
        # fetch activation requirements
        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id).data
        # filter to the myproxy requirements; ensure that there are values
        myproxy_requirements_data = [
            x for x in requirements_data["DATA"] if x["type"] == "myproxy"
        ]
        if not len(myproxy_requirements_data):
            raise click.ClickException(
                "This endpoint does not support myproxy activation")

        # get username and password
        if not (myproxy_username or default_myproxy_username):
            myproxy_username = click.prompt("Myproxy username")
        if not myproxy_password:
            myproxy_password = click.prompt("Myproxy password",
                                            hide_input=True)

        # fill out the requirements data -- note that because everything has been done
        # by reference, `requirements_data` still refers to the document containing
        # these values
        for data in myproxy_requirements_data:
            if data["name"] == "passphrase":
                data["value"] = myproxy_password
            if data["name"] == "username":
                data["value"] = myproxy_username or default_myproxy_username
            if data["name"] == "hostname" and data["value"] is None:
                raise click.ClickException(
                    "This endpoint has no myproxy server "
                    "and so cannot be activated through myproxy")
            # NOTE: remember that "0" is a possible value
            if data["name"] == "lifetime_in_hours" and myproxy_lifetime is not None:
                data["value"] = str(myproxy_lifetime)

        res = client.endpoint_activate(endpoint_id, requirements_data)

    # web activation
    elif web:
        url = "https://app.globus.org/file-manager?origin_id={}".format(
            endpoint_id)
        if no_browser or is_remote_session():
            res = {"message": "Web activation url: {}".format(url), "url": url}
        else:
            webbrowser.open(url, new=1)
            res = {
                "message": "Browser opened to web activation page",
                "url": url
            }

    # delegate proxy activation
    elif delegate_proxy:
        requirements_data = client.endpoint_get_activation_requirements(
            endpoint_id).data
        filled_requirements_data = fill_delegate_proxy_activation_requirements(
            requirements_data,
            delegate_proxy,
            lifetime_hours=proxy_lifetime or 12)
        res = client.endpoint_activate(endpoint_id, filled_requirements_data)

    # output
    formatted_print(res, text_format=FORMAT_TEXT_RAW, response_key="message")