FTN8.3: FutoIn Security Concept - Client Authentication
Version: 0.2DV
Date: 2017-12-27
Copyright: 2014-2018 FutoIn Project (http://futoin.org)
Authors: Andrey Galkin

CHANGES

1. Intro

This sub-specification of FTN8 covers Client authentication and Service authorization.

Client is assumed to be a software under control of User. User is a living being like human.

The ultimate goal is to concentrate primary User and Client authentication logic in AuthService as defined in the main spec while Service itself has minimal responsibility.

2. Concept

2.1. User registration

There is an open list of possible use cases:

  1. By adminstrator of AuthService.
  2. Via self-registration form.
  3. By Service which creates users on demand.

2.2. Client authentication and sessions

2.2.1. Authentication of Client requests

At least for HTTP-based Clients, there is doubtful security of using stateless or MAC-based request signing authentication as modern browsers support protection of cookies from exposure to applications on page.

Therefore, this sub-spec is focused on cookie-based authentication. The cookie must be bound to particular Service. It must not be possible to re-use it in other Service.

  1. Each non-anonymous request must be undoubtedly associated with User account.
  2. Service passes active session token to AuthService.
  3. AuthService does authentication implementation-defined way:
  4. AuthService returns user local and global IDs for further processing

2.2.2. PleaseReauth handling in Client code

  1. Client must immediately request signed redirect URL for login page.
  2. Client must follow the URL as is.
  3. Upon successful authentication and return to Service, implementation may restore session state and continue execution as if no interruption occured.

Note: this logic does not apply to Service-to-Service calls

2.2.3. User authentication in Client

  1. If Client comes from Service redirect (Auth Query):
  2. Client passes implementation-defined authentication procedure on AuthService page.
  3. HTTP session cookie or its equivalent may be set on Client in scope of AuthService.
  4. If the Service has not been Authorized to access user's resource yet then user is prompted for that.
  5. If Client comes from Service redirect (Auth Query):

2.2.3.1. "session token" vs. "session start token"

2.2.4. User session persistence

2.2.5. Multiple User sessions in the same Client

It's assumed that single Client can have multiple User sessions at the same time.

Therefore:

  1. Both Service and AuthService must be aware of possible multiple session cases.
  2. Login as different user must always be available to add additional sessions, unless there are opposite business requirements - prevention of multiple accounts.
  3. If multiple user sessions are authenticated in Client then current User selection must be available.

2.2.5. Sessions of foreign users

  1. Foreign user's home AuthService must be aware of all related sessions and be able to invalidate them.
  2. Service-local AuthService must listen to foreign user updates from user's home AuthService.

More details are provided in FTN8.6 sub-spec.

2.3. Service Authorization

More details of Service authorization to access User's resources on different Services is described in the main FTN8 spec and FTN8.4 sub-spec.

2.3.1. Auth Queries from Client by Service through AuthService

"Auth Query" stays both for "Authentication" and for "Authorization" query. The second always depends on the first one, but plain authentication query without asking for any resource authorization can be done. In scope of the spec, User authentication can be seen as authorization of Service to get basic User's local and global ID.

User private information available in AuthService is accessible through dedicated interface. So, there is no special handling compared to any other resources.

To request User authorization for some resources, Service may request AuthService to ask User to grant access of owned and/or controlled resources in another location.

The important aspects:

  1. Service must have pre-existing Master Secret exchange with AuthService
  2. Service/AuthService may want to protect from potential DoS attacks caused by other peer redirects either intentional or due to software bug or due to attacks from Client itself.
  3. AuthService must ask user for actions initiated by Service:

2.3.2. Auth Query signing details

  1. It's assumed ServiceA and ServiceB are paired to AuthService based on Master Secret auth.
  2. It's assumed declareAccessControl() is called by Services once per new software version.
  3. It's assumed Services and AuthService are in time sync.
  4. ServiceA generates a random nonce (e.g. UUID).
  5. ServiceA creates AuthQueryRequest payload with access control descriptors of ServiceB.
  6. ServiceA derives EXPOSED signing key from Master Secret and signed the payload with the key.
  7. ServiceA uses auth_url concatenated with the payload encoded in Base64.
  8. ServiceA redirects Clients based on result URL.
  9. AuthService decodes the request payload and verifies its content:
  10. AuthService authenticates User, if needed.
  11. AuthService asks User to approve ServiceA access, if needed.
  12. AuthService creates AuthQueryResponse using new timestamp, but the same nonce and signing key.
  13. AuthService redirects user to result_url concatenated with Base64 encoded payload.
  14. ServiceA decodes the result payload and varifies its content:
  15. ServiceA start User session:
  16. Optional, ServiceA can make requests to ServiceB on behalf of the user.

2.3.3. User session handling

  1. After successful Auth Query, Service must call startSession().
  2. Service should call resumeSession() once in 10 minutes, if session is used.
  3. If User is logged out from the Service then closeSession() must be called.
  4. Service must call `resumeSession() on every client fingerprints change and/or service may force logout.

2.3.4. Session invalidation

Service should listen to AuthService events through FTN18 Event Stream interface.

3. Interface

3.1. Service interface

{
    "iface" : "futoin.auth.service",
    "version" : "{ver}",
    "ftn3rev" : "1.8",
    "imports" : [
        "futoin.ping:1.0",
        "futoin.auth.types:{ver}"
    ],
    "types" : {
        "TemplateName" : {
            "type" : "GenericIdentifier",
            "maxlen" : 32
        },
        "SessionStartToken" : {
            "type" : "Base64",
            "minlen" : 22,
            "maxlen" : 171
        },
        "SessionToken" : {
            "type" : "Base64",
            "minlen" : 22,
            "maxlen" : 171
        },
        "AuthQueryID" : "UUIDB64",
        "AuthQueryNonce" : {
            "type" : "Base64",
            "maxlen" : 22
        },
        "AuthQueryRequest" : {
            "type" : "map",
            "fields" : {
                "id" : "AuthQueryID",
                "ts" : "Timestamp",
                "nonce" : "AuthQueryNonce",
                "msid" : "MasterSecretID"
            }
        },
        "AuthQueryResponse" : {
            "type" : "map",
            "fields" : {
                "token" : "SessionStartToken",
                "ts" : "Timestamp",
                "nonce" : "AuthQueryNonce",
                "msid" : "MasterSecretID"
            }
        }
    },
    "funcs" : {
        "declareAccessControl" : {
            "params" : {
                "access_groups" : "AccessGroupList"
            },
            "result" : "boolean"
        },
        "authQueryTemplate" : {
            "params" : {
                "name" : "TemplateName",
                "acds" : "ServiceAccessGroupList",
                "result_url" : "RedirectURL"
            },
            "result" : {
                "id" : "AuthQueryID",
                "auth_url" : "RedirectURL"
            },
            "throws" : [
                "SecurityError"
            ]
        },
        "startSession" : {
            "params" : {
                "start_token" : "SessionStartToken",
                "client" : "ClientFingerprints"
            },
            "result" : {
                "token" : "SessionToken",
                "info" : "AuthInfo"
            },
            "throws" : [
                "InvalidStartToken",
                "PleaseReauth"
            ]
        },
        "resumeSession" : {
            "params" : {
                "start_token" : "SessionToken",
                "client" : "ClientFingerprints"
            },
            "result" : "boolean",
            "throws" : [
                "UnknownSession",
                "PleaseReauth"
            ]
        },
        "closeSession" : {
            "params" : {
                "start_token" : "SessionToken"
            },
            "result" : "boolean"
        }
    },
    "requires" : [
        "SecureChannel",
        "MessageSignature"
    ]
}

3.2. User interface for access grants

{
    "iface" : "futoin.info.me",
    "version" : "{ver}",
    "ftn3rev" : "1.8",
    "imports" : [
        "futoin.ping:1.0",
        "futoin.auth.types:{ver}"
    ],
    "funcs" : {
        "getEmail" : {
            "result" : "Email",
            "throws" : [
                "NoValidatedEmail"
            ]
        },
        "getPhone" : {
            "result" : "Phone",
            "throws" : [
                "NoValidatedPhone"
            ]
        },
        "getNames" : {
            "result" : {
                "first" : "LatinName",
                "middle" : "LatinFullName",
                "last" : "LatinName",
                "full" : "LatinFullName",
                "n_first" : "NativeName",
                "n_middle" : "NativeFullName",
                "n_last" : "NativeName",
                "n_full" : "NativeFullName"
            },
            "throws" : [
                "NoValidatedNames"
            ]
        },
        "getAvatar" : {
            "rawresult" : true
        },
        "getDateOfBirth" : {
            "result" : "Datestamp"
        },
        "getPlaceOfBirth" : {
            "result" : {
                "place" : "LatinLocation",
                "n_place" : "NativeLocation"
            }
        },
        "getHomeAddress" : {
            "result" : {
                "country" : "ISO3166A3",
                "address" : "LatinLocation",
                "n_address" : "NativeLocation"
            }
        }
    },
    "requires" : [
        "SecureChannel"
    ]
}

=END OF SPEC=