1. Overview
Memuser is a simple tool for storing and retrieving user information. All data is stored in memory, nothing is persisted. The API used is based loosely on the SCIM protocol, which is essentially JSON with some standardized semantics.
Why? Memuser was created to help with testing some security integration scenarios without having to deal with the overhead of persisting user information. We want to be able to test out User data integration scenarios and not worry so much about the normal data lifecycle issues. Of course, real systems will need to deal with these issues, but we don’t want to hinder our ability to model the lifecycle of user information when we are building out our user security model.
If you have a tool that can provision SCIM users, you can probably use it to manage users in Memuser.
2. Starting
2.1. From a docker image
The easiest way to start memuser is with docker:
$ docker run --rm -d -p9080:8080 --name memuser gclayburg/memuser
When finished, stop it with:
$ docker stop memuser
2.2. From source
You could also run the application as a standalone jar file once you build it yourself:
$ git clone git@github.com:gclayburg/memuser.git $ cd memuser $ ./gradlew build $ ls -l build/libs/*jar $ java -jar build/libs/memuser-0.9.1-SNAPSHOT.jar
Make sure you specify the correct version you built. |
Stop it with Ctrl-c
3. Create Minimal User
3.1. request
Let’s jump into creating a user. When Memuser is started, there are no users loaded. Let’s create one:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users' -i -X POST \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
'
$ echo '
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
' | http POST 'http://localhost:8080/api/multiv2/specdomain1/Users' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
POST /api/multiv2/specdomain1/Users HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 66
Host: localhost:8080
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
3.2. response
HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 457
{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.903-06:00",
"lastModified" : "2024-03-31T22:33:25.903-06:00"
},
"userName" : "alicesmith",
"active" : false,
"displayName" : "Alice P Smith"
}
This is a minimal user. Only the userName
field is required.
The returned JSON response includes the exact user that the Memuser server created. The extra fields are per the SCIM spec.
4. GET User
4.1. request
Take a look at the id
field. This was generated by Memuser and is guaranteed to be unique and never changing among all users that it knows about. id
is also part of meta.location
. We can use this field to retrieve our generated user:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' -i -X GET \
-H 'Accept: application/scim+json'
$ http GET 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' \
'Accept:application/scim+json'
GET /api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57 HTTP/1.1
Accept: application/scim+json
Host: localhost:8080
4.2. response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 457
{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.903-06:00",
"lastModified" : "2024-03-31T22:33:25.903-06:00"
},
"userName" : "alicesmith",
"active" : false,
"displayName" : "Alice P Smith"
}
5. Duplicate userName
Lets try creating alice again:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users' -i -X POST \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
'
$ echo '
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
' | http POST 'http://localhost:8080/api/multiv2/specdomain1/Users' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
POST /api/multiv2/specdomain1/Users HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 66
Host: localhost:8080
{
"userName": "alicesmith",
"displayName": "Alice P Smith"
}
5.1. response
HTTP/1.1 409 Conflict
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 138
{
"detail" : "userName alicesmith already exists",
"status" : "409",
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:Error" ]
}
userName
must be unique.
6. FAQ
6.1. Why is there both a userName
and id
?
One reason is that this allows users to change their userName in Memuser without necessarily notifying clients. For example, lets say Alice gets married to Tom Jones. She changes her last name from Smith to Jones. Alice is happy. She comes in to work on Monday and updates her HR records to change her last name to Smith. She would like to log on to her computer with alicejones and not alicesmith. It sounds like a simple request, but it can cause headaches when we are dealing with many interconnected IT systems that require user identity. There may be multiiple places that need to get updated. If they aren’t all updated, Alice would at best see strange errors.
So instead, we store the initial userName in Memuser when we first create the user on behalf of the client. Our client stores a reference to it using the unique id
. The client may also keep track of the userName
, but it realizes this userName
stored in Memuser could change at any point. Since the client knows Alice by her id
and not userName
, it may not even need to be updated when the userName
changes in Memuser.
6.2. Does the client or server have the most accurate userName
?
There is nothing in the SCIM protocol itself to determine this. It is up to you to determine a convention that works for your workflow. You will need to decide where the authoritative sources are for each user attribute. The SCIM protocol really shines in simplifying and standardizing how independent but related user domains can reason about user relationships.
7. Change userName
7.1. request
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' -i -X PUT \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName" : "alicejones",
"active" : false
}'
$ echo '{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName" : "alicejones",
"active" : false
}' | http PUT 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
PUT /api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57 HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 100
Host: localhost:8080
{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName" : "alicejones",
"active" : false
}
7.2. response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 358
{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.903-06:00",
"lastModified" : "2024-03-31T22:33:25.950-06:00"
},
"userName" : "alicejones",
"active" : false
}
Alice’s userName changes, the id
and meta.location
do not.
Notice displayName no longer exists for Alice. We changed the existing Alice with a PUT request. Memuser will replace the entire user with what was sent in the request.
|
8. Replace entire User
8.1. request
If we want Memuser to retain all user fields during a userName change, we need to send a full PUT request like this:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' -i -X PUT \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"id": "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName": "alicejones",
"displayName": "Alice P Smith"
}
'
$ echo '
{
"id": "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName": "alicejones",
"displayName": "Alice P Smith"
}
' | http PUT 'http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
PUT /api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57 HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 114
Host: localhost:8080
{
"id": "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"userName": "alicejones",
"displayName": "Alice P Smith"
}
8.2. response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 393
{
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.903-06:00",
"lastModified" : "2024-03-31T22:33:25.963-06:00"
},
"userName" : "alicejones",
"active" : false,
"displayName" : "Alice P Smith"
}
9. Create user with full name
9.1. request
Lets create a user with a few more fields:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users' -i -X POST \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"userName": "tomjones",
"name": {
"formatted": "Dr. Tom J Jones",
"familyName": "Jones",
"givenName": "Tom",
"middleName": "Jackson",
"honorificPrefix": "Dr."
},
"displayName": "Tom Jones"
}
'
$ echo '
{
"userName": "tomjones",
"name": {
"formatted": "Dr. Tom J Jones",
"familyName": "Jones",
"givenName": "Tom",
"middleName": "Jackson",
"honorificPrefix": "Dr."
},
"displayName": "Tom Jones"
}
' | http POST 'http://localhost:8080/api/multiv2/specdomain1/Users' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
POST /api/multiv2/specdomain1/Users HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 222
Host: localhost:8080
{
"userName": "tomjones",
"name": {
"formatted": "Dr. Tom J Jones",
"familyName": "Jones",
"givenName": "Tom",
"middleName": "Jackson",
"honorificPrefix": "Dr."
},
"displayName": "Tom Jones"
}
9.2. response
HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 619
{
"id" : "091f2f5b-a9e8-4de4-a5b2-4ab8b7b84a23",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/091f2f5b-a9e8-4de4-a5b2-4ab8b7b84a23",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.970-06:00",
"lastModified" : "2024-03-31T22:33:25.970-06:00"
},
"userName" : "tomjones",
"active" : false,
"name" : {
"formatted" : "Dr. Tom J Jones",
"familyName" : "Jones",
"givenName" : "Tom",
"middleName" : "Jackson",
"honorificPrefix" : "Dr."
},
"displayName" : "Tom Jones"
}
The fields included here are optional name
fields documented in the SCIM spec.
10. Create arbitrary User
10.1. request
We can also create a Memuser user with fields that aren’t necessarily SCIM defined User resource fields:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users' -i -X POST \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"userName": "harry",
"displayName": "Tom Jones",
"mailcode": "CHP",
"emailaddress": "tomjones@gmail.com"
}
'
$ echo '
{
"userName": "harry",
"displayName": "Tom Jones",
"mailcode": "CHP",
"emailaddress": "tomjones@gmail.com"
}
' | http POST 'http://localhost:8080/api/multiv2/specdomain1/Users' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
POST /api/multiv2/specdomain1/Users HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 118
Host: localhost:8080
{
"userName": "harry",
"displayName": "Tom Jones",
"mailcode": "CHP",
"emailaddress": "tomjones@gmail.com"
}
10.2. response
HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 511
{
"id" : "95c5159d-0242-4c5b-9623-9a51e7e4dfaf",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/95c5159d-0242-4c5b-9623-9a51e7e4dfaf",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.978-06:00",
"lastModified" : "2024-03-31T22:33:25.978-06:00"
},
"userName" : "harry",
"active" : false,
"displayName" : "Tom Jones",
"mailcode" : "CHP",
"emailaddress" : "tomjones@gmail.com"
}
Here, we are using Memuser to model an application that expects users to have a mailcode
and emailaddress
top-level field. Notice we did not define mailcode
or emailaddress
anywhere. Memuser is dynamic. It does not know ahead of time if these fields should be stored as an integer, string or some other datatype. It doesn’t even have a notion of data validation. This is by design. Other than fields like id
and userName
, Memuser does not enforce a rigid definition of what fields are required or allowed for users. JSON is flexible and so is Memuser. Data validation is left up to the client.
11. Get User List
11.1. request
Here is a standard SCIM style request to retrieve a list of our users:
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users/' -i -X GET \
-H 'Accept: application/scim+json'
$ http GET 'http://localhost:8080/api/multiv2/specdomain1/Users/' \
'Accept:application/scim+json'
GET /api/multiv2/specdomain1/Users/ HTTP/1.1
Accept: application/scim+json
Host: localhost:8080
11.2. response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Total-Count: 4
Link: <http://localhost:8080/api/multiv2/specdomain1/Users/?page=0&size=20>; rel="last",<http://localhost:8080/api/multiv2/specdomain1/Users/?page=0&size=20>; rel="first"
Content-Type: application/scim+json
Content-Length: 2220
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:ListResponse" ],
"totalResults" : 4,
"itemsPerPage" : 4,
"startIndex" : 1,
"Resources" : [ {
"id" : "3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/3b3e7428-62e5-40d9-a59e-a3df8e4ded57",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.903-06:00",
"lastModified" : "2024-03-31T22:33:25.963-06:00"
},
"userName" : "alicejones",
"active" : false,
"displayName" : "Alice P Smith"
}, {
"id" : "6cf2b52b-0733-4429-84a8-8037674e3539",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/6cf2b52b-0733-4429-84a8-8037674e3539",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.938-06:00",
"lastModified" : "2024-03-31T22:33:25.938-06:00"
},
"userName" : "alicebell",
"active" : false
}, {
"id" : "091f2f5b-a9e8-4de4-a5b2-4ab8b7b84a23",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/091f2f5b-a9e8-4de4-a5b2-4ab8b7b84a23",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.970-06:00",
"lastModified" : "2024-03-31T22:33:25.970-06:00"
},
"userName" : "tomjones",
"active" : false,
"name" : {
"formatted" : "Dr. Tom J Jones",
"familyName" : "Jones",
"givenName" : "Tom",
"middleName" : "Jackson",
"honorificPrefix" : "Dr."
},
"displayName" : "Tom Jones"
}, {
"id" : "95c5159d-0242-4c5b-9623-9a51e7e4dfaf",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/95c5159d-0242-4c5b-9623-9a51e7e4dfaf",
"resourceType" : "User",
"created" : "2024-03-31T22:33:25.978-06:00",
"lastModified" : "2024-03-31T22:33:25.978-06:00"
},
"userName" : "harry",
"active" : false,
"displayName" : "Tom Jones",
"mailcode" : "CHP",
"emailaddress" : "tomjones@gmail.com"
} ]
}
The list is formatted according to the SCIM ListResponse
12. Rigid User Fields
Field | Special Notes |
---|---|
|
required for every user; must be unique among all users |
|
unique identifier generated by Memuser for each new user |
|
ignored |
13. HTTP verbs
RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its use of HTTP verbs.
Verb | Usage |
---|---|
|
Used to retrieve a resource |
|
Used to create a new resource |
|
Used to update an existing resource, including partial updates |
|
Used to delete an existing resource |
14. HTTP status codes
RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its use of HTTP status codes.
Status code | Usage |
---|---|
|
The request completed successfully |
|
A new resource has been created successfully. The resource’s URI is available from the response’s
|
|
An update to an existing resource has been applied successfully |
|
The request was malformed. The response body will include an error providing further information |
|
The requested resource did not exist |
15. Troubleshooting
Memuser is based on spring boot, so there are a few settings that can be adjusted. These examples show the configuration in the properties file format, but there are many other ways settings are externalized in spring boot, including environment variables, command line parameters and yaml.
15.1. startup
If you have troubles starting up, try turning on debug from upbanner:
upbanner.debug=true <1>
memuser.show-headers=true <2>
memuser.user-count=10000 <3>
upbanner:
debug: true <1>
memuser:
show-headers: true <2>
user-count: 10000 <3>
1 | on startup, print out many debugging details to the stdout log about the environment it is running on |
2 | show all incoming http request headers to the stdout log |
3 | on startup, add 10000 users to the domain, default is 0. |
15.2. Fine tuning
PATCH requests normally return HTTP code 200 when successful. Some systems (ahem, Microsoft) seems to expect a return code of 204.
It seems both can be considered correct as per RFC7644 section 3.5.2:
On successful completion, the server either MUST return a 200 OK response code and the entire resource within the response body, subject to the "attributes" query parameter (see Section 3.9), or MAY return HTTP status code 204 (No Content) and the appropriate response headers for a successful PATCH request. The server MUST return a 200 OK if the "attributes" parameter is specified in the request. |
This setting will force memuser to return 204 instead of 200 for successful patch requests:
memuser.patch-requests-return204=true
16. Security
16.1. password
The password
field can be specified in a user create request or a change request, but per the SCIM spec, the value is never returned in clear text. Memuser goes one step further and does not even store password
. However, this is only true for the password field named exactly password
.
$ curl 'http://localhost:8080/api/multiv2/specdomain1/Users' -i -X POST \
-H 'Content-Type: application/scim+json' \
-H 'Accept: application/scim+json' \
-d '
{
"userName": "billy",
"password": "qwerty1234",
"userpassword": "asdfghjkl"
}
'
$ echo '
{
"userName": "billy",
"password": "qwerty1234",
"userpassword": "asdfghjkl"
}
' | http POST 'http://localhost:8080/api/multiv2/specdomain1/Users' \
'Content-Type:application/scim+json' \
'Accept:application/scim+json'
POST /api/multiv2/specdomain1/Users HTTP/1.1
Content-Type: application/scim+json
Accept: application/scim+json
Content-Length: 86
Host: localhost:8080
{
"userName": "billy",
"password": "qwerty1234",
"userpassword": "asdfghjkl"
}
16.1.1. response
HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/scim+json
Content-Length: 449
{
"id" : "0b2977e4-b22e-4a93-9158-83b26571fa32",
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User" ],
"meta" : {
"location" : "http://localhost:8080/api/multiv2/specdomain1/Users/0b2977e4-b22e-4a93-9158-83b26571fa32",
"resourceType" : "User",
"created" : "2024-03-31T22:33:26.001-06:00",
"lastModified" : "2024-03-31T22:33:26.001-06:00"
},
"userName" : "billy",
"active" : false,
"userpassword" : "asdfghjkl"
}
16.2. TLS/HTTPS support
For convenience, there is a TLS certificate bundled for the hostname gibberishhostname.example.com
. It is only intended to be used testing purposes. It is signed by a self-signed CA certificate, and not by any well known trusted CA.
To use this certificate and require memuser to be accessed over TLS, you’ll need to set properties like this. The server.port
can be adjusted, but the rest can not if you use the bundled insecuretlswrapperwithgibberishhostname.p12
file.
security.require-ssl=true
server.port=443
server.ssl.key-store=classpath:insecuretlswrapperwithgibberishhostname.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=gibberishhostname
security:
require-ssl: true
server:
port: 443
ssl:
key-store: classpath:insecuretlswrapperwithgibberishhostname.p12
key-store-password: changeit
key-store-type: PKCS12
key-alias: gibberishhostname
16.3. Authentication
By default, there is no authentication required to make http requests to memuser. However, memuser can be deployed to require basic authentication.
16.3.1. Basic Authentication defaults
Set this property to require basic authentication credentials:
spring.profiles.active=secure
This will force clients to supply basic authentication credentials. The username is "user". The password is "password".
16.3.2. Custom username and password
If you want to use your own credentials, set environment variables named MEMUSER_USERNAME and MEMUSER_PASSWORD. For example, lets use scott/tiger:
MEMUSER_USERNAME=scott MEMUSER_PASSWORD=tiger