'Takes a dictionary sent by the client in the login / registration
protocol and handles the login flow.
As a side effect, this function fills in the \'creds\' key on the user\'s
session with a map, which maps each auth-type (str) to the relevant
identity authenticated by that auth-type (mostly str, but for captcha, bool).
Args:
flows (list): A list of login flows. Each flow is an ordered list of
strings representing auth-types. At least one full
flow must be completed in order for auth to be successful.
clientdict: The dictionary from the client root level, not the
\'auth\' key: this method prompts for auth if none is sent.
clientip (str): The IP address of the client.
Returns:
A tuple of (authed, dict, dict, session_id) where authed is true if
the client has successfully completed an auth flow. If it is true
the first dict contains the authenticated credentials of each stage.
If authed is false, the first dictionary is the server response to
the login request and should be passed back to the client.
In either case, the second dict contains the parameters for this
request (which may have been given only in a previous call).
session_id is the ID of this session, either passed in by the client
or assigned by the call to check_auth'

@defer.inlineCallbacks
def check_auth(self, flows, clientdict, clientip):

    authdict = None
    sid = None
    if (clientdict and ('auth' in clientdict)):
        authdict = clientdict['auth']
        del clientdict['auth']
        if ('session' in authdict):
            sid = authdict['session']
    session = self._get_session_info(sid)
    if (len(clientdict) > 0):
        session['clientdict'] = clientdict
        self._save_session(session)
    elif ('clientdict' in session):
        clientdict = session['clientdict']
    if (not authdict):
        defer.returnValue((False, self._auth_dict_for_flows(flows, session), clientdict, session['id']))
    if ('creds' not in session):
        session['creds'] = {}
    creds = session['creds']
    errordict = {}
    if ('type' in authdict):
        login_type = authdict['type']
        if (login_type not in self.checkers):
            raise LoginError(400, '', Codes.UNRECOGNIZED)
        try:
            result = (yield self.checkers[login_type](authdict, clientip))
            if result:
                creds[login_type] = result
                self._save_session(session)
        except LoginError as e:
            if (login_type == LoginType.EMAIL_IDENTITY):
                raise e
            errordict = e.error_dict()
    for f in flows:
        if (len((set(f) - set(creds.keys()))) == 0):
            logger.info('Auth    completed    with    creds:    %r.    Client    dict    has    keys:    %r', creds, clientdict.keys())
            defer.returnValue((True, creds, clientdict, session['id']))
    ret = self._auth_dict_for_flows(flows, session)
    ret['completed'] = creds.keys()
    ret.update(errordict)
    defer.returnValue((False, ret, clientdict, session['id']))
