Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Authentication Service 2.0"

(Background)
 
(46 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
{{#eclipseproject:technology.higgins|eclipse_custom_style.css}} [[Image:Higgins logo 76Wx100H.jpg|right]]  
 
{{#eclipseproject:technology.higgins|eclipse_custom_style.css}} [[Image:Higgins logo 76Wx100H.jpg|right]]  
 
This page describes a new network [[Authentication Service 1.1]].
 
  
 
== Objective  ==
 
== Objective  ==
  
A new service that performs authentication of selector clients and issues an access token that can be consumed by both the Higgins Selector (e.g. [[GTK Selector 1.1-Win]]) and all of its various supporting services including the [[I-Card Service 1.1]], [[CardSync Service 1.1]].  
+
A new service that performs authentication of active clients and issues an access token that can be passed by the client to supporting web services.
  
 
== Background  ==
 
== Background  ==
  
At present authentication is performed within the [[RPPS Package]] within the [[I-Card Service]]. Here are some implications:  
+
In Higgins 1.0 & 1.1 authentication is performed within the [[RPPS Package]] within the [[I-Card Service]]. Here are some implications:  
  
 
*In deployments where the [[I-Card Service]] and [[CardSync Service]] are co-resident, the [[CardSync Service]] can rely on this same authentication capability within [[RPPS Package]]. However if these services are deployed separately, the [[CardSync Service will have no way to authenticate the selector client.  
 
*In deployments where the [[I-Card Service]] and [[CardSync Service]] are co-resident, the [[CardSync Service]] can rely on this same authentication capability within [[RPPS Package]]. However if these services are deployed separately, the [[CardSync Service will have no way to authenticate the selector client.  
*As we move towards Higgins 1.1 other new services may be added that also need to authenticate the selector client. With the current design this is difficult.  
+
*As we move towards Higgins 2.0 other new services may be added that also need to authenticate the client. With the current design this is difficult.  
 
*We can envision deployment architectures where organization A would host the authentication service, and organization B would host the others. By having a separate authentication service, this deployment option becomes available.
 
*We can envision deployment architectures where organization A would host the authentication service, and organization B would host the others. By having a separate authentication service, this deployment option becomes available.
  
Line 47: Line 45:
 
*Selector checks user name (''GET /user/<username>/<captchaId>/<captcha_answer>'')  
 
*Selector checks user name (''GET /user/<username>/<captchaId>/<captcha_answer>'')  
 
*Auth service returns '''404''' http status code if user doesn't exists, otherwise '''302''' - found. (Selector may re-use that captchaId not more than 5 times.)  
 
*Auth service returns '''404''' http status code if user doesn't exists, otherwise '''302''' - found. (Selector may re-use that captchaId not more than 5 times.)  
*Selector sends add user account request containing username, hash-of-password, email address, email marketing permission, CAPTCHA ID and CAPTCHA answer, and (optionally) selector serial number (''POST /user/passhash/email/marketing/serial/<captchaId>/<captcha_answer>'').  
+
*Selector sends add user account request containing username, hash-of-password, email address, email marketing permission, CAPTCHA ID and CAPTCHA answer, and (optionally) selector serial number (''POST /user'').  
 
**Auth service sends OTP via out-of-band channel (email, sms, etc)  
 
**Auth service sends OTP via out-of-band channel (email, sms, etc)  
 
**Selector sends "add selector" message containing OTP, selector name, selector serial number and selector public key (POST /selector/<otp>) over either SSL or with message encrypted using auth service's certificate and http Authorization header (Authorization: HWS <session_token>)  
 
**Selector sends "add selector" message containing OTP, selector name, selector serial number and selector public key (POST /selector/<otp>) over either SSL or with message encrypted using auth service's certificate and http Authorization header (Authorization: HWS <session_token>)  
Line 53: Line 51:
 
*If selector serial number is not sent, then account is created in non-serialized (low security) mode.
 
*If selector serial number is not sent, then account is created in non-serialized (low security) mode.
  
<br>  
+
<br>
  
 
=== Adding a new selector to user's account  ===
 
=== Adding a new selector to user's account  ===
Line 79: Line 77:
 
*Selector requests CAPTCHA&nbsp;''(GET /captcha)''  
 
*Selector requests CAPTCHA&nbsp;''(GET /captcha)''  
 
*Auth service sends CAPTCHA ID (selector may load captcha image by using ''GET &nbsp;/captcha/&lt;captchaId&gt;'')  
 
*Auth service sends CAPTCHA ID (selector may load captcha image by using ''GET &nbsp;/captcha/&lt;captchaId&gt;'')  
*Selector sends request "get reset password OTP" message containing username, selector serial number , CAPTCHA ID and CAPTCHA answer ''(POST /otppwr/&lt;captchaId&gt;/&lt;captcha_answer&gt;)''  
+
*Selector sends request "get reset password OTP" message containing username, selector serial number , CAPTCHA ID and CAPTCHA answer ''(POST /otppwr)''  
 
*Auth service sends OTP via out-of-band channel which was used for adding last user selector  
 
*Auth service sends OTP via out-of-band channel which was used for adding last user selector  
 
*Selector sends request "reset password" message containing (username, OTP, selector serial number, new hash-of-password) over either SSL or with message encrypted using auth service's certificate ''(PUT /user/&lt;otppwr&gt;)''  
 
*Selector sends request "reset password" message containing (username, OTP, selector serial number, new hash-of-password) over either SSL or with message encrypted using auth service's certificate ''(PUT /user/&lt;otppwr&gt;)''  
Line 85: Line 83:
 
*Auth service returns an access token which includes (selector public key, username)
 
*Auth service returns an access token which includes (selector public key, username)
  
=== Removing a selector from user's account  ===
+
=== Permanently Removing a selector from user's account  ===
  
*to-be-written
+
* User logs-in to a selector authorized to their account, other than the one they want to remove.
 +
* User navigates to the "devices" tab. See [[Authentication_Service_1.1_UI#Case_5:_Manage_Selectors | UI Mockups]].
 +
* User selects "permanently remove" for the selector to be removed. This removes the chosen selector from the account, including from the devices list.
 +
* If someone subsequently tries to use the removed selector, it will behave the same as for a new selector that had never been authorized to the account.
 +
 
 +
=== Temporarily locking a selector from user's account  ===
 +
 
 +
* User logs-in to a selector authorized to their account, other than the one they want to lock.
 +
* User navigates to the "devices" tab. See [[Authentication_Service_1.1_UI#Case_5:_Manage_Selectors | UI Mockups]].
 +
* User selects "lock" for the selector to be removed. This locks the chosen selector from the account. The locked selector stays in the devices list, shown as locked.
 +
* The locked selector can be un-locked from the devices list in a similar fashion.
 +
* If a user tries to use a locked selector, they will get a message telling them that the selector is locked, and they will not be able to proceed.
  
 
=== Cloud-selector authentication  ===
 
=== Cloud-selector authentication  ===
Line 146: Line 155:
 
== Rest API  ==
 
== Rest API  ==
  
{| width="100%" cellspacing="1" cellpadding="1" border="1"
+
=== Access Token format ===
 +
Access Token is a short lived bearer token issued by the Authentication Server to the Client.
 +
 
 +
The Access Token contains list of encoded (application/x-www-form-urlencoded) name/value parameters  for enabling the Protected Service to determine the client authorization without querying any other resource.
 +
"Issuer" - represents issuer that issued token;
 +
"ExpiresOn" - represents  the moment when the token is not to be accepted for further processing;
 +
"UserId" - represents user identifier.
 +
 
 +
The issuer is the Authentication Server URL.
 +
 
 +
The expiration date/time is recorded as the number of seconds that will pass from 1970-01-01T0:0:0Z until the moment of expiration as measured in UTC.
 +
 
 +
The last Access Token name/value parameter is SHA-256 with RSA signature:
 +
SHA256withRSA=<base 64 encoded signature>
 +
 
 +
The Access Token will  be encrypted by using Protected Service certificate (public key) if Authentication Server has(or can load) Protected Service certificate.
 +
 
 +
==== Access Token signature  ====
 +
 
 +
The Authentication Server signs access token by using the Authentication Server private key. The java code for signing token:
 +
<source lang="java">
 +
Signature rsaSignature = Signature.getInstance("SHA256withRSA");
 +
rsaSignature.initSign(privateKey);
 +
rsaSignature.update(token);
 +
return rsaSignature.sign();
 +
</source>
 +
 
 +
The Protected Service must validate signature. The java code example:
 +
<source lang="java">
 +
String[] t = plainToken.split("&amp;SHA256withRSA=");
 +
Signature rsaSignature = Signature.getInstance("SHA256withRSA");
 +
rsaSignature.initVerify(publicKey);
 +
rsaSignature.update(t[0].getBytes("UTF-8"));
 +
Boolean verSign = rsaSignature.verify(new BASE64Decoder().decodeBuffer(t[1]));
 +
</source>
 +
 
 +
==== Encrypting/Decrypting of Access Token ====
 +
The Authentication Server encrypts access token by using Protected Service certificate (public key) if Authentication Server has(or can load) Protected Service certificate.
 +
 
 +
<source lang="java">
 +
ByteArrayOutputStream encToken = new ByteArrayOutputStream();
 +
ByteArrayInputStream plainToken = new ByteArrayInputStream(
 +
(accessTokenEntity.getSignedData() + "&SHA256withRSA="
 +
                    + accessTokenEntity.getSignature()).getBytes("UTF-8"));
 +
try {
 +
if (null != serviceKey) {
 +
// encrypt token
 +
byte buf[] = new byte[100];
 +
int bytesRead = 0;
 +
while ((bytesRead = plainToken.read(buf)) > 0) {
 +
encToken.write(SecureUtils.encrypt(buf, 0,
 +
                            bytesRead, serviceKey.getPublicKey(),
 +
                            "RSA/ECB/PKCS1Padding"));
 +
}
 +
}
 +
accessTokenEntity.setToken(base64Encoder.encode(encToken.toByteArray()));
 +
} finally {
 +
encToken.close();
 +
plainToken.close();
 +
}
 +
 
 +
</source>
 +
 
 +
<source lang="java">
 +
ByteArrayOutputStream plainTkn = new ByteArrayOutputStream();
 +
ByteArrayInputStream encToken = new ByteArrayInputStream(
 +
            new BASE64Decoder().decodeBuffer(token.getToken()));
 +
try {
 +
byte buf[] = new byte[128];
 +
int bytesRead = 0;
 +
while ((bytesRead = encToken.read(buf)) > 0) {
 +
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
 +
cipher.init(Cipher.DECRYPT_MODE, issuerPrivateKey);
 +
plainTkn.write(cipher.doFinal(buf, 0, bytesRead));
 +
}
 +
} finally {
 +
encToken.close();
 +
plainTkn.close();
 +
}
 +
 
 +
String plainToken = new String(plainTkn.toByteArray(), "UTF-8");
 +
</source>
 +
 
 +
== API ==
 +
 
 +
{| cellspacing="1" cellpadding="1" border="1" width="100%"
 
|-
 
|-
 
| align="center" | '''HTTP operation'''  
 
| align="center" | '''HTTP operation'''  
Line 155: Line 249:
 
| GET  
 
| GET  
 
| /captcha  
 
| /captcha  
| none
+
| ___________________________
| Generates new captcha and returns &lt;captchaId&gt;
+
| Generates new captcha and returns&nbsp;CaptchaTO
 
|-
 
|-
 
| GET  
 
| GET  
 
| /captcha/&lt;captchaId&gt;  
 
| /captcha/&lt;captchaId&gt;  
 
|  
 
|  
Path parameters:  
+
Path parameters:<br>String&nbsp;: captcheId&nbsp;  
 
+
String&nbsp;: captcheId&nbsp;  
+
  
 
| Returns captcha image
 
| Returns captcha image
 
|-
 
|-
| GET  
+
| &nbsp;! GET  
 
| /channel  
 
| /channel  
| none
+
| ____________________________
 
| Returns all supported transport channels  
 
| Returns all supported transport channels  
 
<br>  
 
<br>  
  
 
|-
 
|-
| POST<br>  
+
| &nbsp;! POST<br>  
 
| /accesstoken  
 
| /accesstoken  
 
|  
 
|  
Request parameters:  
+
Request parameters:<br>UserCredential&nbsp;: userCredential&nbsp;  
 
+
UserCredential&nbsp;: userCredential&nbsp;  
+
  
 
|  
 
|  
Line 190: Line 280:
 
| /sessiontoken  
 
| /sessiontoken  
 
|  
 
|  
Request parameters:  
+
Request parameters:<br>CredentialTO&nbsp;: userCredential  
 
+
UserCredential&nbsp;: userCredential  
+
  
 
|  
 
|  
 
Validates user credential,  
 
Validates user credential,  
  
return session token  
+
return&nbsp;SessionTokenTO&nbsp;with status code 200<br>if user has 'serialized' selectors, but CredentialTO doesn't contain serial number&nbsp;status code will be&nbsp;'''230''', this session token may be used just for asking new access code GET /otp (see case 2)
  
 
|-
 
|-
| GET
+
| POST
| /user/&lt;username&gt;
+
 
|  
 
|  
Path parameters:<br>String&nbsp;: user name
+
/user/check/&lt;captchaId&gt;/&lt;answer&gt;  
  
Request parameters:<br>Captcha&nbsp;: captcha<br>
+
/user/check (just for testing)
  
 
|  
 
|  
Validates captcha,<br>returns http status code  
+
Path parameters:<br>String&nbsp;: captchaId <br>String&nbsp;: captcha answer
 +
 
 +
Request parameters:<br>BaseTO: id is user name
 +
 
 +
<br>
 +
 
 +
|
 +
Validates captcha,<br>returns BaseTO with status code  
  
 
404 if user doesn't exists,  
 
404 if user doesn't exists,  
Line 216: Line 310:
 
|-
 
|-
 
| POST  
 
| POST  
| /user
 
 
|  
 
|  
Request parameters:
+
/user/&lt;captchaId&gt;/&lt;answer&gt;
  
Captcha&nbsp;: captcha
+
/user&nbsp;(just for testing)
  
UserCredential&nbsp;: userCredential
+
|
 +
Path parameters:<br>String&nbsp;: captchaId <br>String&nbsp;: captcha answer<br>
 +
 
 +
Request parameters:<br>UserTO: userTO
  
 
|  
 
|  
 
Creates new user accounts,  
 
Creates new user accounts,  
  
returns http status code 201  
+
sends Access Code by using &nbsp;userTO.address value,
 +
 
 +
returns SessionTokenTO&nbsp;with status code 201  
  
 
|-
 
|-
 
| PUT  
 
| PUT  
| /user  
+
| /user/&lt;otp&gt;
 
|  
 
|  
Request parameters:  
+
Path parameters:<br>String&nbsp;: otp
  
String&nbsp;: OTP <br>UserCredential&nbsp;: userCredential  
+
Request parameters:<br>UserCredential&nbsp;: userCredential  
  
 
|  
 
|  
 
Validates OTP,  
 
Validates OTP,  
  
updates user password hash,  
+
updates user UserCredential,  
  
returns http status code 200  
+
returns BaseTO with status code 200
 +
 
 +
|-
 +
| GET
 +
| /user
 +
| Headers:Authorization: HWS &lt;session_token&gt;
 +
| Validates session token,<br>returns UserTO with empty credential set.
 +
|-
 +
| DELETE
 +
| /user
 +
| Headers:Authorization: HWS &lt;session_token&gt;
 +
|
 +
Validates session token,<br>deletes user account,<br>returns&nbsp;BaseTO with status code 200  
  
 
|-
 
|-
 
| POST  
 
| POST  
| /otp
 
 
|  
 
|  
Headers:<br>Authorization: HWS &lt;session_token&gt;  
+
/otp/&lt;captchaId&gt;/&lt;answer&gt;  
  
Request parameters:
+
/otp&nbsp;(just for testing)
  
Captcha&nbsp;: captcha  
+
| Headers:Authorization: HWS &lt;session_token&gt;
 +
| Validates captcha,<br>sends Access Code to all confirmed email addresses,<br>returns BaseTO&nbsp;with status code 200&nbsp;&nbsp;(see case 2)
 +
|-
 +
| POST
 +
|
 +
/otp/pw/&lt;captchaId&gt;/&lt;answer&gt;
  
Channel&nbsp;: channel
+
/otp/pw (just for testing)
  
 
|  
 
|  
Validates session token,
+
Path parameters:<br>String&nbsp;: captchaId <br>String&nbsp;: captcha answer
  
sends OTP via out-of-band channel
+
Request parameters:<br>BaseTO: id is user name
  
 +
| Validates captcha,<br>check userId,<br>sends password reset code to all confirmed email addresses,<br>returns BaseTO with status code 200
 
|-
 
|-
 
| POST  
 
| POST  
| /otppwr
+
| /address
 
|  
 
|  
Request parameters:  
+
Headers:Authorization: HWS &lt;session_token&gt;
  
Captcha&nbsp;: captcha<br>UserCredential&nbsp;: userCredential
+
Request parameters:<br>AddressTO&nbsp;: &nbsp;address
 +
 
 +
|
 +
Validates session token,<br>returns created AddressTO with status 201.
 +
 
 +
|-
 +
| PUT
 +
| /address
 +
|
 +
Headers:Authorization: HWS &lt;session_token&gt;
 +
 
 +
Request parameters:<br>AddressTO&nbsp;: &nbsp;address
 +
 
 +
|
 +
Validates session token,<br>returns updated &nbsp;AddressTO
 +
 
 +
if old addres value does not equal new address value, confirmed field will be false.
  
| Validates captcha,<br>sends OTP via out-of-band channel which was used for adding last user selector
 
 
|-
 
|-
 
| POST  
 
| POST  
| /selector
+
| /address/otp
 
|  
 
|  
Headers:<br>Authorization: HWS &lt;session_token&gt;  
+
Headers:Authorization: HWS &lt;session_token&gt;  
  
 
Request parameters:  
 
Request parameters:  
  
String&nbsp;: otp
+
AddressTO&nbsp;: &nbsp;address<br>
  
Selector&nbsp;: selector
+
|
 +
Validates session token,<br>sends access code for confirming email address,
 +
 
 +
returns&nbsp;BaseTO with status code 200
  
| Validates session token,<br> persists selector,&nbsp;<br>returns http status code 201<br>
 
 
|-
 
|-
| GET
+
| POST
| /selector
+
| /address/otp/&lt;otp&gt;
| Headers:<br>Authorization: HWS &lt;session_token&gt;  
+
|  
| Validates session token,<br>returns list of user selectors<br>
+
Headers:Authorization: HWS &lt;session_token&gt;
 +
 
 +
Path parameter<br>String&nbsp;: otp
 +
 
 +
|
 +
Validates session token and access code (otp),<br>update corresponding address,<br>returns updated AddressTO.
 +
 
 +
|-
 +
| DELETE
 +
| /address/&lt;addressId&gt;
 +
| Headers:Authorization: HWS &lt;session_token&gt;  
 +
| Validates session token,<br>deletes address,<br>returns BaseTO with status code 200
 +
|-
 +
| POST
 +
| /selector/&lt;otp&gt;
 +
|
 +
Headers:<br>Authorization: HWS &lt;session_token&gt;
 +
 
 +
Path parameter<br>String&nbsp;: otp
 +
 
 +
Request parameters:<br>SelectorTO&nbsp;: selector
 +
 
 +
|
 +
Validates session token and access code (otp),<br>generate new serial number,<br> persists selector,&nbsp;<br>returns SelectorTO &nbsp;with status code 201
 +
 
 
|-
 
|-
 
| PUT  
 
| PUT  
 
| /selector  
 
| /selector  
| Headers:<br>Authorization: HWS &lt;session_token&gt;<br>Request parameters:<br>Selector&nbsp;: selector<br>
+
|  
| Validates session token,<br>update selector name, key and status,<br>returns http status code 200<br>
+
Headers:<br>Authorization: HWS &lt;session_token&gt;  
 +
 
 +
Request parameters:<br>SelectorTO: selector  
 +
 
 +
| Validates session token,<br>update selector name, key and status,<br>returns&nbsp;SelectorTO<br>
 
|-
 
|-
 
| DELETE  
 
| DELETE  
Line 298: Line 458:
 
| Headers:<br>Authorization: HWS &lt;session_token&gt;<br>Path parameters:<br>String&nbsp;: selectorSerialNumber  
 
| Headers:<br>Authorization: HWS &lt;session_token&gt;<br>Path parameters:<br>String&nbsp;: selectorSerialNumber  
 
| Validates session token,<br>delete selector.<br>
 
| Validates session token,<br>delete selector.<br>
|-
 
| <br>
 
| <br>
 
| <br>
 
|
 
<br>
 
 
<br>
 
 
 
|}
 
|}
  
Line 313: Line 464:
 
=== Authentication Service TOs  ===
 
=== Authentication Service TOs  ===
  
<br> [[Image:Org.eclipse.higgins.auth.to.png|left|800px|Authentication Service TOs]]<br>  
+
Authentication Service supports serialization transfer objects to XML. We're going to normalize API according to WRAP, so all parameters will be formatted as application/x-www-form-urlencoded (AZ-310). Serialization to google protobuf format is deprecated.
 +
 
 +
XML schema of Authentication Service transfer objects [[Image:Schemas.zip|0x0px|XML schema of Authentication Service transfer objects]].
 +
 
 +
<br> [[Image:Org.eclipse.higgins.auth.to.png|left|780px|Authentication Service TOs]]<br>
 +
 
 +
=== Authentication Service Exceptions  ===
 +
 
 +
<br> [[Image:Org.eclipse.higgins.auth.ex.png|left|780px|Authentication Service TOs]]<br>
  
 
== Implementation characteristics  ==
 
== Implementation characteristics  ==
Line 320: Line 479:
 
#Security is of course important  
 
#Security is of course important  
 
#Uses open standards where possible
 
#Uses open standards where possible
 +
 +
== Field Validation ==
 +
Text input fields should be validated as follows. Users should be notified of any fields that do not validate, and have a chance to correct them.
 +
 +
* USERNAME_REGEXP "[A-Za-z][A-Za-z0-9._-]{3,30}[A-Za-z0-9]"
 +
** The user name is 5-32 characters long; it must start with a (Latin) letter, end with a letter or digit, and can contain letters, digits, dashes, underlines, and periods.
 +
* PASSWORD_REGEXP "[\\S]{5,32}"
 +
** The password is 5-32 characters long; it must not start with white space. All other characters are allowed, since internally we’re using the password’s hash.
 +
* EMAIL_REGEXP "^[A-Za-z0-9._+-]+@(?:[A-Za-z0-9-]+[.])+[A-Za-z]{2,}$"
 +
** The e-mail address must start with at least one letter, digit, or ._+-, followed by @, then at least one letter or digit followed by a period, then two or more letters.
 +
* CAPTCHA_REGEXP - not defined
 +
* PASSPHRASE_REGEXP "[\\S]{5,60}"
 +
** The passphrase is 5-60 characters long; it must not start with white space.
 +
* DEVICE_NAME_REGEXP "[\\S]{5,60}"
 +
** The passphrase is 5-60 characters long; it must not start with white space.
 +
* AUTH_CODE_REGEXP  "[0-9a-fA-F]{4}"
 +
** The auth code is just 4 hexadecimal digits.
  
 
== Open Issues  ==
 
== Open Issues  ==
  
 
#Are there any performance issues with all this public key stuff?  
 
#Are there any performance issues with all this public key stuff?  
#Should we worry about "idle time"?
+
#Should we worry about "idle time"?  
 +
#We can't support non-secure http connection for&nbsp;non-serialized selectors due to we don't have selector public key. So Authentication Service has to redirect to https, or&nbsp;non-serialized&nbsp;selector has to generate new key pair every time and send public key with UserCredential.
  
 
== See Also  ==
 
== See Also  ==

Latest revision as of 11:02, 23 May 2010

{{#eclipseproject:technology.higgins|eclipse_custom_style.css}}
Higgins logo 76Wx100H.jpg

Objective

A new service that performs authentication of active clients and issues an access token that can be passed by the client to supporting web services.

Background

In Higgins 1.0 & 1.1 authentication is performed within the RPPS Package within the I-Card Service. Here are some implications:

  • In deployments where the I-Card Service and CardSync Service are co-resident, the CardSync Service can rely on this same authentication capability within RPPS Package. However if these services are deployed separately, the [[CardSync Service will have no way to authenticate the selector client.
  • As we move towards Higgins 2.0 other new services may be added that also need to authenticate the client. With the current design this is difficult.
  • We can envision deployment architectures where organization A would host the authentication service, and organization B would host the others. By having a separate authentication service, this deployment option becomes available.

High Level Requirements

  • Separate authentication, provisioning and some account management to a separate "auth" service
  • Allow all the existing Higgins services to rely on this auth service to authenticate users/selectors instead of doing it themselves
  • Allow the auth service to evolve independently
  • Supports uses where one organizational entity is running the auth service and other organizations run the other Higgins services
  • Higgins reference implementation of auth service for Higgins 1.1
  • Any organization/service that can implement the auth service API can act as a Higgins selector authenticator (no need to use the Higgins reference implementation)
  • Auth service can authenticate both client-based and cloud-based selectors
  • Allows remote de-authorization of selectors
  • Secure design/architecture

High Level Design of the Auth Service

Account management

  • Maintains accounts for users.
  • Each account is identified by a unique (to this service) account id (aka username)
  • Each account holds multiple selector entries, each of which consists of:
    • selector public key
    • selector serial number
    • selector name (human friendly)
    • selector state (active/disabled)


Register new user account

  • Selector requests CAPTCHA (GET /captcha)
  • Auth service returns CAPTCHA ID (selector may load captcha image by using GET /captcha/<captchaId>)
  • Selector checks user name (GET /user/<username>/<captchaId>/<captcha_answer>)
  • Auth service returns 404 http status code if user doesn't exists, otherwise 302 - found. (Selector may re-use that captchaId not more than 5 times.)
  • Selector sends add user account request containing username, hash-of-password, email address, email marketing permission, CAPTCHA ID and CAPTCHA answer, and (optionally) selector serial number (POST /user).
    • Auth service sends OTP via out-of-band channel (email, sms, etc)
    • Selector sends "add selector" message containing OTP, selector name, selector serial number and selector public key (POST /selector/<otp>) over either SSL or with message encrypted using auth service's certificate and http Authorization header (Authorization: HWS <session_token>)
    • returns with an access token which includes (selector public key, username)
  • If selector serial number is not sent, then account is created in non-serialized (low security) mode.


Adding a new selector to user's account

  • Selector requests list of supported transport channels
  • Auth service sends list with channel names (email, sms, etc) (it'll be pluggable feature, so it depends on deployment configuration)
  • Selector requests CAPTCHA
  • Auth service sends CAPTCHA ID (selector may load captcha image by using GET /captcha/<captchaId>)
  • Selector sends username, hash-of-password for obtain session token (POST /sessiontoken
  • Auth service returns session token
  • Selector sends "request add selector token" message containing, transport channel (email, sms, etc), address (it depends on selected transport channel  like email->email@example.com or sms->1-201-793-9022), CAPTCHA ID and CAPTCHA answer (POST /otp) and http Authorization header (Authorization: HWS <session_token>)
  • Auth service sends OTP via out-of-band channel (email, sms, etc)
  • Selector sends "add selector" message containing OTP, selector name, selector serial number and selector public key (POST /selector/<otp>) over either SSL or with message encrypted using auth service's certificate and http Authorization header (Authorization: HWS <session_token>)
  • returns with an access token which includes (selector public key, username)

Selector authentication and access token issuance

  • Receives a "request for access token" message from (non-cloud) selector containing (username, hash-of-password, selector serial number) in message that was signed by selector's private key (POST /accesstoken)
  • Returns a fresh access token containing (username, selector public key)
  • Access token is signed by private key of auth service
  • Access token contains an expiration date/time

Password reset

  • Selector requests CAPTCHA (GET /captcha)
  • Auth service sends CAPTCHA ID (selector may load captcha image by using GET  /captcha/<captchaId>)
  • Selector sends request "get reset password OTP" message containing username, selector serial number , CAPTCHA ID and CAPTCHA answer (POST /otppwr)
  • Auth service sends OTP via out-of-band channel which was used for adding last user selector
  • Selector sends request "reset password" message containing (username, OTP, selector serial number, new hash-of-password) over either SSL or with message encrypted using auth service's certificate (PUT /user/<otppwr>)
  • "reset password" request should be signed by selector private key
  • Auth service returns an access token which includes (selector public key, username)

Permanently Removing a selector from user's account

  • User logs-in to a selector authorized to their account, other than the one they want to remove.
  • User navigates to the "devices" tab. See UI Mockups.
  • User selects "permanently remove" for the selector to be removed. This removes the chosen selector from the account, including from the devices list.
  • If someone subsequently tries to use the removed selector, it will behave the same as for a new selector that had never been authorized to the account.

Temporarily locking a selector from user's account

  • User logs-in to a selector authorized to their account, other than the one they want to lock.
  • User navigates to the "devices" tab. See UI Mockups.
  • User selects "lock" for the selector to be removed. This locks the chosen selector from the account. The locked selector stays in the devices list, shown as locked.
  • The locked selector can be un-locked from the devices list in a similar fashion.
  • If a user tries to use a locked selector, they will get a message telling them that the selector is locked, and they will not be able to proceed.

Cloud-selector authentication

  • to-be-written: For clientless access (i.e., cloud selector) this could be a two-step process: Step 1: userid + password. Then auth service initiates an out-of-band (i.e. email, sms, voice call, etc.) OTP to the user. Then step 2 is user enters this OTP to get the access token.

High Level Design of the Higgins Selector

On startup

  • Selector generates an asymmetric (private/public) key pair
  • Selector validates auth service certificate
  • Selector sends (username, hash-of-password, selector serial number, selector public key) to auth service

Using access token to authenticate to services

  • After getting an access token from the auth service, the selector will, before using any other service (e.g. CardSync) send this access token to the service and get a session token in response
  • If the service responds with an error code that indicates that the access token has expired then it will request a fresh access token from the auth service and repeat the process

Secure local storage

  • After installation the selector securely stores for each local username/account
    • this selector's serial number
    • this selector's private key

Login user interface

  • Has UI that prompts the user for username and password
    • The purpose of the username is to allow a set of the user's selectors to be treated as a logical group by the auth service
    • The purpose of the password is to authenticate the user to the selector (and to a lesser extent the user to the auth service)

Authenticating the user

  • Selector pops up the UI described above
  • Selector checks that the username entered by the user matches the stored username and that the hash of the password stored locally matches the hash of the stored password
  • Selector sends "request for access token" message that contains (username, hash-of-password, proof of serial number possession) either (a) encrypted by using the auth service's certificate or (b) delivered over SSL
  • Selector gets an access token in response
  • Selector sends this access token to a Higgins service (e.g. CardSync service) and gets a session token in response
  • Selector uses this session token to access service

Credential storage

  • The selector never stores the password, only a hash of the password
  • The selector locally stores the username

Cloud selector authentication

  • to-be-written

Adding a new selector to user's auth service account

  • to-be-written

Removing a selector from the user's auth service account

  • to-be-written

Rest API

Access Token format

Access Token is a short lived bearer token issued by the Authentication Server to the Client.

The Access Token contains list of encoded (application/x-www-form-urlencoded) name/value parameters for enabling the Protected Service to determine the client authorization without querying any other resource. "Issuer" - represents issuer that issued token; "ExpiresOn" - represents the moment when the token is not to be accepted for further processing; "UserId" - represents user identifier.

The issuer is the Authentication Server URL.

The expiration date/time is recorded as the number of seconds that will pass from 1970-01-01T0:0:0Z until the moment of expiration as measured in UTC.

The last Access Token name/value parameter is SHA-256 with RSA signature: SHA256withRSA=<base 64 encoded signature>

The Access Token will be encrypted by using Protected Service certificate (public key) if Authentication Server has(or can load) Protected Service certificate.

Access Token signature

The Authentication Server signs access token by using the Authentication Server private key. The java code for signing token:

Signature rsaSignature = Signature.getInstance("SHA256withRSA"); 
rsaSignature.initSign(privateKey); 
rsaSignature.update(token); 
return rsaSignature.sign();

The Protected Service must validate signature. The java code example:

String[] t = plainToken.split("&amp;SHA256withRSA="); 
Signature rsaSignature = Signature.getInstance("SHA256withRSA"); 
rsaSignature.initVerify(publicKey);
rsaSignature.update(t[0].getBytes("UTF-8"));
Boolean verSign = rsaSignature.verify(new BASE64Decoder().decodeBuffer(t[1]));

Encrypting/Decrypting of Access Token

The Authentication Server encrypts access token by using Protected Service certificate (public key) if Authentication Server has(or can load) Protected Service certificate.

ByteArrayOutputStream encToken = new ByteArrayOutputStream();
ByteArrayInputStream plainToken = new ByteArrayInputStream(
		(accessTokenEntity.getSignedData() + "&SHA256withRSA=" 
                     + accessTokenEntity.getSignature()).getBytes("UTF-8"));
try {
	if (null != serviceKey) {
		// encrypt token
		byte buf[] = new byte[100];
		int bytesRead = 0;
		while ((bytesRead = plainToken.read(buf)) > 0) {
			encToken.write(SecureUtils.encrypt(buf, 0, 
                            bytesRead, serviceKey.getPublicKey(), 
                             "RSA/ECB/PKCS1Padding"));
		}
	}
	accessTokenEntity.setToken(base64Encoder.encode(encToken.toByteArray()));
} finally {
	encToken.close();
	plainToken.close();
}
ByteArrayOutputStream plainTkn = new ByteArrayOutputStream();
ByteArrayInputStream encToken = new ByteArrayInputStream(
             new BASE64Decoder().decodeBuffer(token.getToken()));
try {
	byte buf[] = new byte[128];
	int bytesRead = 0;
	while ((bytesRead = encToken.read(buf)) > 0) {
		Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
		cipher.init(Cipher.DECRYPT_MODE, issuerPrivateKey);
		plainTkn.write(cipher.doFinal(buf, 0, bytesRead));
	}
} finally {
	encToken.close();
	plainTkn.close();
}
 
String plainToken = new String(plainTkn.toByteArray(), "UTF-8");

API

HTTP operation Path Parameters Note
GET /captcha ___________________________ Generates new captcha and returns CaptchaTO
GET /captcha/<captchaId>

Path parameters:
String : captcheId 

Returns captcha image
 ! GET /channel ____________________________ Returns all supported transport channels


 ! POST
/accesstoken

Request parameters:
UserCredential : userCredential 

Validates user credential,

returns SAML access token

POST /sessiontoken

Request parameters:
CredentialTO : userCredential

Validates user credential,

return SessionTokenTO with status code 200
if user has 'serialized' selectors, but CredentialTO doesn't contain serial number status code will be 230, this session token may be used just for asking new access code GET /otp (see case 2)

POST

/user/check/<captchaId>/<answer>

/user/check (just for testing)

Path parameters:
String : captchaId
String : captcha answer

Request parameters:
BaseTO: id is user name


Validates captcha,
returns BaseTO with status code

404 if user doesn't exists,

otherwise 302 - found.

POST

/user/<captchaId>/<answer>

/user (just for testing)

Path parameters:
String : captchaId
String : captcha answer

Request parameters:
UserTO: userTO

Creates new user accounts,

sends Access Code by using  userTO.address value,

returns SessionTokenTO with status code 201

PUT /user/<otp>

Path parameters:
String : otp

Request parameters:
UserCredential : userCredential

Validates OTP,

updates user UserCredential,

returns BaseTO with status code 200

GET /user Headers:Authorization: HWS <session_token> Validates session token,
returns UserTO with empty credential set.
DELETE /user Headers:Authorization: HWS <session_token>

Validates session token,
deletes user account,
returns BaseTO with status code 200

POST

/otp/<captchaId>/<answer>

/otp (just for testing)

Headers:Authorization: HWS <session_token> Validates captcha,
sends Access Code to all confirmed email addresses,
returns BaseTO with status code 200  (see case 2)
POST

/otp/pw/<captchaId>/<answer>

/otp/pw (just for testing)

Path parameters:
String : captchaId
String : captcha answer

Request parameters:
BaseTO: id is user name

Validates captcha,
check userId,
sends password reset code to all confirmed email addresses,
returns BaseTO with status code 200
POST /address

Headers:Authorization: HWS <session_token>

Request parameters:
AddressTO :  address

Validates session token,
returns created AddressTO with status 201.

PUT /address

Headers:Authorization: HWS <session_token>

Request parameters:
AddressTO :  address

Validates session token,
returns updated  AddressTO

if old addres value does not equal new address value, confirmed field will be false.

POST /address/otp

Headers:Authorization: HWS <session_token>

Request parameters:

AddressTO :  address

Validates session token,
sends access code for confirming email address,

returns BaseTO with status code 200

POST /address/otp/<otp>

Headers:Authorization: HWS <session_token>

Path parameter
String : otp

Validates session token and access code (otp),
update corresponding address,
returns updated AddressTO.

DELETE /address/<addressId> Headers:Authorization: HWS <session_token> Validates session token,
deletes address,
returns BaseTO with status code 200
POST /selector/<otp>

Headers:
Authorization: HWS <session_token>

Path parameter
String : otp

Request parameters:
SelectorTO : selector

Validates session token and access code (otp),
generate new serial number,
persists selector, 
returns SelectorTO  with status code 201

PUT /selector

Headers:
Authorization: HWS <session_token>

Request parameters:
SelectorTO: selector

Validates session token,
update selector name, key and status,
returns SelectorTO
DELETE /selector/<selectorSerialNumber> Headers:
Authorization: HWS <session_token>
Path parameters:
String : selectorSerialNumber
Validates session token,
delete selector.


Authentication Service TOs

Authentication Service supports serialization transfer objects to XML. We're going to normalize API according to WRAP, so all parameters will be formatted as application/x-www-form-urlencoded (AZ-310). Serialization to google protobuf format is deprecated.

XML schema of Authentication Service transfer objects File:Schemas.zip.


Authentication Service TOs

Authentication Service Exceptions


Authentication Service TOs

Implementation characteristics

  1. RESTful web service
  2. Security is of course important
  3. Uses open standards where possible

Field Validation

Text input fields should be validated as follows. Users should be notified of any fields that do not validate, and have a chance to correct them.

  • USERNAME_REGEXP "[A-Za-z][A-Za-z0-9._-]{3,30}[A-Za-z0-9]"
    • The user name is 5-32 characters long; it must start with a (Latin) letter, end with a letter or digit, and can contain letters, digits, dashes, underlines, and periods.
  • PASSWORD_REGEXP "[\\S]{5,32}"
    • The password is 5-32 characters long; it must not start with white space. All other characters are allowed, since internally we’re using the password’s hash.
  • EMAIL_REGEXP "^[A-Za-z0-9._+-]+@(?:[A-Za-z0-9-]+[.])+[A-Za-z]{2,}$"
    • The e-mail address must start with at least one letter, digit, or ._+-, followed by @, then at least one letter or digit followed by a period, then two or more letters.
  • CAPTCHA_REGEXP - not defined
  • PASSPHRASE_REGEXP "[\\S]{5,60}"
    • The passphrase is 5-60 characters long; it must not start with white space.
  • DEVICE_NAME_REGEXP "[\\S]{5,60}"
    • The passphrase is 5-60 characters long; it must not start with white space.
  • AUTH_CODE_REGEXP "[0-9a-fA-F]{4}"
    • The auth code is just 4 hexadecimal digits.

Open Issues

  1. Are there any performance issues with all this public key stuff?
  2. Should we worry about "idle time"?
  3. We can't support non-secure http connection for non-serialized selectors due to we don't have selector public key. So Authentication Service has to redirect to https, or non-serialized selector has to generate new key pair every time and send public key with UserCredential.

See Also

Back to the top