Beispiel #1
0
def list_tokens(request):
    """
    Tags: api_tokens
    ---
    Lists user's api tokens
    ---
    """
    # FIXME: should call an optimized methods.list_tokens
    auth_context = auth_context_from_request(request)
    api_tokens = ApiToken.objects(user_id=auth_context.user.id, revoked=False)
    tokens_list = []
    for token in api_tokens:
        if token.is_valid():
            token_view = token.get_public_view()
            if token_view['last_accessed_at'] == 'None':
                token_view['last_accessed_at'] = 'Never'
            tokens_list.append(token_view)

    # If user is owner also include all active tokens in the current org
    # context
    if auth_context.is_owner():
        org_tokens = ApiToken.objects(org=auth_context.org, revoked=False)
        for token in org_tokens:
            if token.is_valid():
                token_view = token.get_public_view()
                if token_view['last_accessed_at'] == 'None':
                    token_view['last_accessed_at'] = 'Never'
                try:
                    tokens_list.index(token_view)
                except ValueError:
                    tokens_list.append(token_view)
    return tokens_list
Beispiel #2
0
def migrate_old_api_token(request):
    """Migrate old API tokens (aka mist_1: email:token) to new ApiTokens"""

    # check if auth header with old api token format and migrate if needed
    auth_header = request.headers.get('Authorization', '').lower()
    if not auth_header:
        return
    parts = auth_header.split(" ", 1)
    mist_label = parts[0]
    if not mist_label.startswith('mist_'):
        return
    if len(parts) == 1:
        return
    api_version = mist_label[5:]
    header_content = parts[1]
    if api_version != "1":
        return
    parts = header_content.split(":")
    if len(parts) != 2:
        return
    email, mist_api_token = parts

    if not mist_api_token:
        return

    if len(mist_api_token) > 64:
        raise ValueError('Token is larger than 64 characters')

    # migrate old api token to new ApiToken if needed
    try:
        # if token is less than 64 characters then add 0's at the beginning
        # and search for that token
        padding = 64 - len(mist_api_token)
        padded_mist_api_token = '0' * padding + mist_api_token
        token = ApiToken.objects.get(token=padded_mist_api_token)
    except DoesNotExist:
        try:
            user = User.objects.get(email=email)
        except UserNotFoundError:
            return
        if not user.mist_api_token or user.mist_api_token != mist_api_token:
            return

        # if token is shorter than 64 chars then add padding with 0's
        # and save it that way
        padding = 64 - len(mist_api_token)
        padded_mist_api_token = '0' * padding + mist_api_token

        token = ApiToken(token=padded_mist_api_token,
                         user_id=user.get_id(),
                         name=get_random_name_for_token(user),
                         ip_address=mist.api.helpers.ip_from_request(request),
                         user_agent=request.user_agent)
        token.save()
    return token
Beispiel #3
0
def session_from_request(request):
    """Get SessionToken or ApiToken instance from request"""
    if 'session' in request.environ:
        return request.environ['session']
    session = migrate_old_api_token(request)
    if session is None:
        auth_value = request.headers.get('Authorization', '').lower()
        if auth_value.startswith('internal'):
            parts = auth_value.split(' ')
            if len(parts) == 3:
                internal_api_key, session_id = parts[1:]
                if internal_api_key == Portal.get_singleton().internal_api_key:
                    try:
                        session_token = SessionToken.objects.get(
                            token=session_id)
                    except SessionToken.DoesNotExist:
                        pass
                    else:
                        if session_token.is_valid():
                            session_token.internal = True
                            session = session_token
        elif auth_value:
            token_from_request = auth_value
            try:
                api_token = ApiToken.objects.get(token=token_from_request)
            except DoesNotExist:
                api_token = None
            try:
                if not api_token and config.HAS_RBAC:
                    api_token = SuperToken.objects.get(
                        token=token_from_request)
            except DoesNotExist:
                pass
            if api_token and api_token.is_valid():
                session = api_token
            else:
                session = ApiToken()
                session.name = 'dummy_token'
    if session is None:
        try:
            session_token = SessionToken.objects.get(
                token=request.cookies.get('session.id'))
            if session_token.is_valid():
                session = session_token
        except DoesNotExist:
            pass
    if session is None:
        session = SessionToken(
            user_agent=request.user_agent,
            ip_address=mist.api.helpers.ip_from_request(request))
        session.save()
    request.environ['session'] = session
    return session
Beispiel #4
0
def session_from_request(request):
    """Get SessionToken or ApiToken instance from request"""
    if 'session' in request.environ:
        return request.environ['session']
    session = migrate_old_api_token(request)
    if session is None:
        token_from_request = request.headers.get('Authorization', '').lower()
        if token_from_request:
            try:
                api_token = ApiToken.objects.get(
                    token=token_from_request
                )
            except DoesNotExist:
                api_token = None
            try:
                if not api_token and SUPER_EXISTS:
                    api_token = SuperToken.objects.get(
                                token=token_from_request)
            except DoesNotExist:
                pass
            if api_token and api_token.is_valid():
                session = api_token
            else:
                session = ApiToken()
                session.name = 'dummy_token'
    if session is None:
        try:
            session_token = SessionToken.objects.get(
                token=request.cookies.get('session.id')
            )
            if session_token.is_valid():
                session = session_token
        except DoesNotExist:
            pass
    if session is None:
        session = SessionToken(
            user_agent=request.user_agent,
            ip_address=mist.api.helpers.ip_from_request(request)
        )
        session.save()
    request.environ['session'] = session
    return session
Beispiel #5
0
def create_token(request):
    """
    Tags: api_tokens
    ---
    Creates a new api token.
    Used so that a user can send his credentials and produce a new api token.
    The api token itself will be returned in a json document along with it's
    id and it's name.
    If user has used su then he should provide his own credentials.However, the
    api token will authenticate the user he is impersonating.
    If name is not sent then a random one with the format api_token_xyz where
    xyz is a number will be produced.
    If the user provides a name then there must be no other token for that user
    with the same name.
    If the user has a cookie or sends an api token in the request headers then
    the username and password must belong to him.
    Used by io to authenticate to core (when running separately. Io sends
    user's email and password. We return an access token that will be used to
    authenticate any further communications.
    An anti-CSRF token is not needed to access this api call.
    If user is coming from oauth then he will be able to create a new token
    without a password provided he is authenticated somehow.
    If you are using the /auth route please switch to /api_v1_tokens route. The
    /auth route is deprecated.
    ---
    email:
      description: User's email
      type: string
      required: true
    password:
      description: User's password
      type: string
      required: true
    name:
      description: Api token name
      type: string
    ttl:
      description: Time to live for the token
      type: integer
    org_id:
      description: Org id if the token will be used in organizational context
      type: string
    """

    params = params_from_request(request)
    email = params.get('email', '').lower()
    password = params.get('password', '')
    api_token_name = params.get('name', '')
    org_id = params.get('org_id', '')
    ttl = params.get('ttl', 60 * 60)
    if isinstance(ttl, basestring) and not ttl.isdigit():
        raise BadRequestError('Ttl must be a number greater than 0')
    ttl = int(ttl)
    if ttl < 0:
        raise BadRequestError('Ttl must be greater or equal to zero')
    if not password:
        raise RequiredParameterMissingError('password')

    try:
        auth_context = auth_context_from_request(request)
        user, org = auth_context.user, auth_context.org
    except UserUnauthorizedError:
        # The following should apply, but currently it can't due to tests.
        # if not org_id:
            # raise RequiredParameterMissingError("No org_id provided")
        if not email:
            raise RequiredParameterMissingError("No email provided")
        org = None
        if org_id:
            try:
                org = Organization.objects.get(id=org_id)
            except Organization.DoesNotExist:
                try:
                    org = Organization.objects.get(name=org_id)
                except Organization.DoesNotExist:
                    # The following should apply, but currently it can't due to
                    # tests.
                    # raise UserUnauthorizedError()
                    pass
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            raise UserUnauthorizedError()
        # Remove org is not None when we enforce org context on tokens.
        if org is not None and user not in org.members:
            raise ForbiddenError()

    if user.status != 'confirmed':
        raise UserUnauthorizedError()
    if not user.password:
        raise BadRequestError('Please use the GUI to set a password and retry')
    if not user.check_password(password):
        raise UserUnauthorizedError('Wrong password')

    if not org:
        org = reissue_cookie_session(request, user.id).org
    # first check if the api token name is unique if it has been provided
    # otherwise produce a new one.
    if api_token_name:
        # will raise exception if there exists valid token with given name
        token_with_name_not_exists(user, api_token_name)
    else:
        api_token_name = get_random_name_for_token(user)
    tokens_num = len([token for token in ApiToken.objects(user_id=user.id,
                                                          revoked=False)
                      if token.is_valid()])
    if tokens_num < config.ACTIVE_APITOKEN_NUM:
        new_api_token = ApiToken()
        new_api_token.name = api_token_name
        new_api_token.org = org
        new_api_token.ttl = ttl
        new_api_token.set_user(user)
        new_api_token.ip_address = ip_from_request(request)
        new_api_token.user_agent = request.user_agent
        new_api_token.save()
    else:
        raise BadRequestError("MAX number of %s active tokens reached"
                              % config.ACTIVE_APITOKEN_NUM)

    token_view = new_api_token.get_public_view()
    token_view['last_accessed_at'] = 'Never'
    token_view['token'] = new_api_token.token

    return token_view
Beispiel #6
0
def token_with_name_not_exists(user, name):
    api_tokens = ApiToken.objects(user_id=user.get_id(), name=name)
    for token in api_tokens:
        if token.is_valid():
            raise ConflictError('Token with name %s already exists' % name)
Beispiel #7
0
def info_from_ApiKeyAuth(api_key, required_scopes):
    """
    Check and retrieve authentication information from api_key.
    Returned value will be passed in 'token_info' parameter of your operation
    function, if there is one. 'sub' or 'uid' will be set in 'user' parameter
    of your operation function, if there is one.

    :param api_key API key provided by Authorization header
    :type api_key: str
    :param required_scopes Always None. Used for other authentication method
    :type required_scopes: None
    :return: Information attached to provided api_key or None if api_key is
        invalid or does not allow access to called API
    :rtype: dict | None
    """
    from mist.api.auth.models import ApiToken, SessionToken
    from mist.api.portal.models import Portal
    from mist.api import config
    if config.HAS_RBAC:
        from mist.rbac.tokens import SuperToken
        from mist.rbac.methods import AuthContext
    else:
        from mist.api.dummy.rbac import AuthContext

    auth_value = api_key.lower()
    auth_context = session = None
    if auth_value.startswith('internal'):
        parts = auth_value.split(' ')
        if len(parts) == 3:
            internal_api_key, session_id = parts[1:]
            if internal_api_key == Portal.get_singleton().internal_api_key:
                try:
                    session_token = SessionToken.objects.get(token=session_id)
                except SessionToken.DoesNotExist:
                    pass
                else:
                    if session_token.is_valid():
                        session_token.internal = True
                        session = session_token
    elif auth_value:
        token_from_request = auth_value
        try:
            api_token = ApiToken.objects.get(token=token_from_request)
        except DoesNotExist:
            api_token = None
        try:
            if not api_token and config.HAS_RBAC:
                api_token = SuperToken.objects.get(token=token_from_request)
        except DoesNotExist:
            pass
        if api_token and api_token.is_valid():
            session = api_token
        else:
            session = ApiToken()
            session.name = 'dummy_token'
    if session:
        user = session.get_user()
        if user:
            auth_context = AuthContext(user, session)
            return {'uid': user.id, 'user': user, 'auth_context': auth_context}
    return None