예제 #1
0
def register_user(email,
                  first_name,
                  last_name,
                  registration_method,
                  selected_plan=None,
                  promo_code=None,
                  token=None,
                  status='pending',
                  create_organization=True,
                  request=None):
    # User does not exist so we have to add him/her to the database
    # First make sure that email is not banned
    # Then create the User objects and the Organization
    if email.split('@')[1] in config.BANNED_EMAIL_PROVIDERS:
        raise MethodNotAllowedError("Email provider is banned.")

    user = User()
    user.email = email
    user.first_name = first_name
    user.last_name = last_name
    user.registration_method = registration_method
    user.registration_date = time()
    user.status = status
    user.activation_key = get_secure_rand_token()
    user.can_create_org = True
    user.save()

    # For some users registering through sso it might not be necessary to
    # create an organization, hence the flag
    org = create_org_for_user(user, '', promo_code, token, selected_plan) \
        if create_organization else None

    log_event_args = {
        'owner_id': org and org.id or '',
        'user_id': user.id,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'company': user.feedback.company_name,
        'event_type': 'request',
        'action': 'register',
        'authentication_provider': registration_method
    }

    if request:
        log_event_args.update({
            'request_method': request.method,
            'request_path': request.path,
            'request_ip': ip_from_request(request),
            'user_agent': request.user_agent,
        })

    if org:
        log_event_args.update({'org_id': org.id, 'org_name': org.name})

    # Create log for the registration of a user and if an org has been created
    # add the id and name of the org
    from mist.api.logs.methods import log_event
    log_event(**log_event_args)

    return user, org
예제 #2
0
 def __call__(self, environ, start_response):
     request = Request(environ)
     session = environ['session']
     # when someone is POSTing to /auth (check_auth) then he is trying
     # to authenticate and does not have a csrf token in the SessionToken
     # which has been produced by default
     if request.path not in self.exempt and \
        isinstance(session, SessionToken) and \
        not getattr(session, 'internal', False) and \
        request.method in ('POST', 'PUT', 'PATCH', 'DELETE'):
         csrf_token = request.headers.get('Csrf-Token', '').lower()
         if not csrf_token:
             csrf_token = request.params.get('Csrf-Token', '').lower()
         if csrf_token != session.csrf_token:
             log.error("Bad CSRF token '%s'", csrf_token)
             user = session.get_user()
             if user is not None:
                 owner_id = session.org.id
                 user_id = user.id
                 email = user.email
             else:
                 owner_id = user_id = None
                 params = params_from_request(request)
                 email = params.get('email', '')
             log_event(
                 owner_id=owner_id,
                 user_id=user_id,
                 email=email,
                 request_method=request.method,
                 request_path=request.path,
                 request_ip=ip_from_request(request),
                 user_agent=request.user_agent,
                 csrf_token=csrf_token,
                 session_csrf=session.csrf_token,
                 event_type='request',
                 action='csrf_validation',
                 error=True,
             )
             start_response('403 Forbidden',
                            [('Content-Type', 'text/plain')])
             return ["Invalid csrf token\n"]
     return self.app(environ, start_response)
예제 #3
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
예제 #4
0
    def __call__(self, environ, start_response):
        request = Request(environ)
        session = session_from_request(request)

        def session_start_response(status, headers, exc_info=None):
            session = environ['session']  # reload in case it was reissued
            if isinstance(session, SessionToken) and \
                    not getattr(session, 'internal', False) and \
                    not session.last_accessed_at:
                cookie = 'session.id=%s; Path=/;' % session.token
                headers.append(('Set-Cookie', cookie))

            # ApiTokens with 'dummy' in name are handed out by session from
            # request function when the api token is not correct, to prevent
            # csrf checks by the CsrfMiddleware but allow calls to function
            # that don't require authentication. When the response is sent out
            # they are to be thrown away, not saved.
            if not (isinstance(session, ApiToken) and 'dummy' in session.name
                    or getattr(session, 'internal', False)):
                session.touch()
                session.save()
            # CORS
            if (environ.get('HTTP_ORIGIN')
                    and environ.get('PATH_INFO') in CORS_ENABLED_PATHS):
                if ('OPTIONS' in environ['REQUEST_METHOD']
                        or isinstance(session, ApiToken)):
                    for header in [
                        ('Access-Control-Allow-Origin',
                         environ['HTTP_ORIGIN']),
                        ('Access-Control-Allow-Methods', 'GET,OPTIONS'),
                        ('Access-Control-Allow-Headers',
                         'Origin, Content-Type, Accept, Authorization'),
                        ('Access-Control-Allow-Credentials', 'true'),
                        ('Access-Control-Max-Age', '1728000'),
                    ]:
                        headers.append(header)
                    if 'OPTIONS' in environ['REQUEST_METHOD']:
                        return start_response('204 No Content', headers,
                                              exc_info)

            return start_response(status, headers, exc_info)

        user = session.get_user()
        # Check whether the request IP is in the user whitelisted ones.
        if session and user is not None and request.path != '/logout' and \
                not getattr(session, 'internal', False):
            current_user_ip = netaddr.IPAddress(ip_from_request(request))
            saved_wips = [netaddr.IPNetwork(ip.cidr) for ip in user.ips]
            config_wips = [
                netaddr.IPNetwork(cidr) for cidr in config.WHITELIST_CIDR
            ]
            wips = saved_wips + config_wips
            if len(saved_wips) > 0:
                for ipnet in wips:
                    if current_user_ip in ipnet:
                        break
                else:
                    log_event(
                        owner_id=session.org.id,
                        user_id=user.id,
                        email=user.email,
                        request_method=request.method,
                        request_path=request.path,
                        request_ip=ip_from_request(request),
                        user_agent=request.user_agent,
                        event_type='ip_whitelist_mismatch',
                        action=request.path,
                        error=True,
                    )
                    # Only logout user if token is SessionToken
                    # Do not logout if it's ApiToken
                    if isinstance(session, SessionToken):
                        reissue_cookie_session(request)
                    start_response('403 Forbidden',
                                   [('Content-type', 'text/plain')])
                    return [
                        "Request sent from non-whitelisted IP.\n"
                        "You have been logged out from this account.\n"
                        "Please sign in to request whitelisting your "
                        "current IP via email."
                    ]

        # Enforce read-only access.
        if config.HAS_RBAC:
            if isinstance(session, ReadOnlyApiToken):
                if request.method not in (
                        'GET',
                        'HEAD',
                        'OPTIONS',
                ):
                    start_response('405 Method Not Allowed',
                                   [('Content-type', 'text/plain')])
                    return ['State-changing HTTP method not allowed\n']

        response = self.app(environ, session_start_response)
        return response