User talk:Caveman

From AOLserver Wiki
Revision as of 21:53, 14 December 2005 by Caveman (talk | contribs)
Jump to navigation Jump to search

towards a data and authentication layer

It is possible that similar exists elsewhere (non-OpenACS) but I enjoy framework construction anyway. Services provided:

  1. authentication (password check)
  2. sequences
  3. data layer

Authentication/Authorization config (nsz):

# config: "/security/password/expression"
# {::sha1::hmac [lindex $args 1] [lindex $args 0]}
# config: "/security/password/query"
# {select password, salt from users where name='[ns_dbquoteval [lindex $args 0]]'}
# config: "/security/salt/length" "64"
# config: "/security/salt/dictionary" "0123456789abcdefghijkl..."

Basically the "expression" is used in a function, nsz_password to format a given clear-text password (varargs "args" to allow additional arguments to the function). The first argument is always the password.

The "query" is executed as part of password-based authentication. The form handler reaches nsz_auth "myname" "mypassword" and the query is executed using the input list "myname". All row data beyond the first column, which must always be the password, is appended to the input password "mypassword" to produce the hash/salted/hash input "xpassword". This input "xpassword" is compared with the result of the returned value for the first column from the database query. If there is a match, password authentication succeeds for the user.

Examples:

nsz_auth "sam" "correctpassword"
# Query returns "sadf8vcx8vxasd7f7...","asduf7z6dfa..."
# Expression eval for input passes "correctpassword","asduf7z6dfa..." and returns "sadf8vcx8vxasd7f7..."
# Return value matches query
# nsz_auth returns "sam"

nsz_auth "sam" "badpassword"
# Query returns "sadf8vcx8vxasd7f7...","asduf7z6dfa..."
# Expression eval for input passes "badpassword","asduf7z6dfa..." and returns "yyzkfosd232cx7c..."
# Return value does not match query
# nsz_auth raises error "bad password"

Different configurations could use simple clear-text passwords, no salt, etc, simply by changing their configuration:

# config: "nsz/security/password/expression"
# {lindex $args 0}
# config: "nsz/security/password/query"
# {select password from users where name='[ns_dbquoteval [lindex $args 0]]'}

The above would be the default configuration. For salt, the default would be size of 8 and dictionary of alphanumerics.

Function nsz_salt can take 0, 1, or 2 arguments and returns the generated salt. The first argument is the length of the salt, defaults to config value. The second argument is the dictionary for the salt, default to config value.

Question: How to make "users" table configurable? What about configuring which database pool to use? What about multiple authentication realms?


Sequences configuration should be as simple as specifying the database pool to use (default by default), the name of the sequence table, the size of the sequence chunk to claim when the local cache runs out of sequence numbers, and the number of retries before error during chunk claim. It could however be more complex, to specify the column names for the "name" and "value" of the sequence.

Config:

# config: "nso/sequence/default/poolname" (default by default)
# config: "nso/sequence/default/size" "100"
# config: "nso/sequence/default/retry" "5"
# config: "nso/sequence/default/table" "sequences_table"
# config: "nso/sequence/default/name" "name_field"
# config: "nso/sequence/default/value" "value_field"

Sequence defaults could be over-written per-sequence in similar fashion.

Example usage:

set nextId [nso_sequence next "my_seq_name"]
# returns 53 or error if fail

The function nso_sequence would thread-safe return the next sequence number it had available in its local nsv data, or if not available, claim the next chunk of 100 sequences numbers from the database:

# select value_field from sequences_table where name_field='my_seq_name'
# result is 125, attempt to claim 100 values
# update cave_sequences set value=225 where name_field='my_seq_name' and value_field=125

This would be retried up to 5 times.


Data layer notes:

Config would map names like "users" to database pools and table names. Default would be default database pool and identity table name.

Example usage:

# set nssValues [ns_set create]
# ns_set update $nssValues "name" "sam"
# ns_set update $nssValues "password" "mypassword"
# ns_set put $nssValues "mail" "sam@caveman.org"
# set nssUserKey [nso_row create "users" $nssValues]
# set nssNewValues [ns_set create]
# ns_set put $nssNewValues "mail" "samuelmb@gmail.com"
# nso_row update "users" $nssUserKey $nssNewValues

Using ns_set instead of a model type-checking "nso_set" at least for now for simplicity and it would be the simple case.

Additional config allows for data transforms:

# multi stage of filters and expressions:
#
# stage 0: accept-data-filter
#   e.g. "require a password is not null"
#   e.g. "require this integer be above zero"
#   e.g. "require id not be set"
#
# stage 1: transform-data-filter
# config: expressions to apply to row:
#   e.g. "generate a salt"
#     ns_set update $nssData "salt" [nsz_salt]
#   e.g. "transform the password"
#     ns_set update $nssData "password" [nsz_password [ns_set get $nssData "password"] [ns_set get $nssData "salt"]]
#   e.g. "generate the next id from sequence"
#     ns_set update $nssData "id" [nso_sequence next "my_seq_name"]
#
# stage 2: veto-data-filter?
#
# allow multiple "inheritance" of data rules? or just defining rules that
# can be referenced by multiple tables?

very draft state

useful links

philip.greenspun.com/doc/ data-pipeline