Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: updated to reflect better encryption of stored owner password

...

We'll show you how these rulesets can be written, and we provide reference rulesets. These two rulesets are referred to in this page as the "reference account management ruleset" and the "reference account ruleset". You may use these rulesets as-is, or you may create your own. To use them as-is, you would go to the "Rulesets" tab of your Root Pico in the UI, enter this URL into the box and click the button "install ruleset from URL".

...

Code Block
  rule owner_admin {
    select when owner admin
    pre {
      txnId = event:attr("txnId");
      legit = (txnId == meta:txnId);
    }
    if legit then noop();
    fired {
      ent:owner_id := "Root";
      raise owner event "pwd_needs_encoding" attributes ent:password :={ "password": "toor" };
    }
  }

Account Management ruleset

...

  • owner:admin
  • owner:creation
  • owner:eci_provided
  • owner:authenticate
  • owner:code_presented
  • owner:new_password

In addition, it must share this function:

  • code

...

The account ruleset may provide an event to securely store the owner-provided password. In the reference ruleset, this is owner:pwd_needs_encoding

In addition, it must share this function:

  • code

Event owner:admin

This event may be sent by your account management ruleset as part of its initialization. It establishes an initial password for the Root Pico, which you should manually change to secure your pico engine. The reference ruleset does this with a single rule.

Code Block
  rule owner_admin {
    select when owner admin
    pre {
      txnId = event:attr("txnId");
      legit = (txnId == meta:txnId);
    }
    if legit then noop();
    fired {
      ent:owner_id := "Root";
      raise owner event "pwd_needs_encoding" attributes { ent:"password ":= "toor" };
    }
  }

Event owner:creation

...

Code Block
  rule owner_creation {
    select when owner creation
    if ent:owner_id != "Root" then noop();
    fired {
      ent:owner_id := event:attr("owner_id");
      ent:method   := event:attr("method");
      raise owner event "pwd_needs_encoding" attributes { ent:"password ":= event:attr("password") };
    }
  }

Event owner:eci_provided

...

This event is sent by the UI when the owner pushes the "Login" button on the password entry form, and has as attributes the nonce and the owner-supplied password. Your account ruleset should verify that the nonce attribute matches the saved value recorded when it reacted to the owner:eci_provided event. Your ruleset must send a directive, with a name of your choice, whose options must include pico_id and eci and may include other values. If the password or nonce are incorrect, your ruleset must not send a directive. The reference ruleset does this with one rule.

Code Block
    rule owner_authenticate {
    select when owner authenticate
    if event:attr("nonce") == ent:nonce && passwordOK()
event:attr("password"))
    then send_directive("success",{"pico_id":meta:picoId,"eci":meta:eci});
    alwaysfired {
      raise owner event "noncepwd_needs_usedencoding"; attributes { "password": event:attr("password") }
   }

The function passwordOK is defined in the reference ruleset.

Code Block
    passwordOK = functionif pwd_needs_encoding();
{    }
  ent:password.defaultsTo("") == "" || ent:password == event:attr("password")
    }

...

  finally {
      raise owner event "nonce_used";
    }
  }

The function passwordOK is defined in the reference ruleset.

Code Block
    one_way_hash = function(password) {
      math:hash("sha256",ent:password{"salt"} + ":" + password)
    }
    passwordOK = function() {
      ent:password{"password"} == one_way_hash(password)
    }

The function pwd_needs_encoding is used in the reference ruleset to take advantage of a moment when we have in hand a correct owner password. We may wish to re-encrypt the password under certain conditions. In this example, we will encrypt the password if an earlier version of the ruleset had stored the owner-supplied password as a plain string.

Code Block
    pwd_needs_encoding = function() {
      ent:password.typeof() == "String"
    }

This allows for graceful upgrading of password storage mechanisms. Flushing this ruleset in your pico engine which had an earlier version will result in the password being encrypted upon the next successful login attempt by each owner.

Event owner:code_presented

This event is sent by the UI when the owner pushes the "Login" button on the code words entry form, and has as attributes the nonce and the owner-supplied code words (code). Your account ruleset should verify that the nonce attribute matches the saved value recorded when it reacted to the owner:eci_provided event. If the code words are correct, your ruleset must send a directive, with a name of your choice, whose options must include pico_id and eci and may include other values. If the code words or nonce are incorrect, your ruleset must not send a directive. The reference ruleset does this with one rule.

Code Block
  rule owner_match_code {
    select when owner code_presented
    if event:attr("code") == ent:code && event:attr("nonce") == ent:nonce then
      send_directive("success",{"pico_id":meta:picoId,"eci":meta:eci});
    always {
      raise owner event "nonce_used";
    }
  }

Event owner:new_password

This event is sent by the UI when the owner pushes the "LoginNew Password" button on the code words entry formthe Change Password entry form in the owner pico's "About" tab, and has as attributes the nonce current password and the owner-supplied code words (code) new_password. Your account ruleset should verify that the nonce attribute matches the saved value recorded when it reacted to the owner:eci_provided event. If the code words are correct, your ruleset must send a directive, with a name of your choice, whose options must include pico_id and eci and may include other values. If the code words or nonce are incorrect, your ruleset must not send a directivethe current password. Your ruleset must record the new password. The reference ruleset does this with one rule.

Code Block
  rule owner_matchnew_codepassword {
    select when owner codenew_presentedpassword
    if passwordOK(event:attr("codepassword") == ent:code && event:attr("nonce") == ent:nonce then       send_directive("success",{"pico_id":meta:picoId,"eci":meta:eci}noop();
    alwaysfired {
      ent:method := ent:method.defaultsTo("password");
      raise owner event "nonce_used""pwd_needs_encoding" attributes { "password": event:attr("new_password") };
    }
  }

Event owner:

...

pwd_needs_

...

encoding

This event is sent by the UI when the owner pushes the "New Password" button on the Change Password entry form in the owner pico's "About" tab, and has as attributes the current password and the owner-supplied new_password. Your account ruleset should verify the current password. Your ruleset must record the new password. The reference ruleset does this with one raised by every rule in the reference account ruleset which has access to the owner's password in clear text. Your account ruleset may have a similar rule.

Code Block
  rule owner_pwd_needs_encoding {
    select when owner pwd_newneeds_encoding password {
re#^(.*)$# setting (password)
   select whenpre owner{
new_password     if passwordOK()salt then= nooprandom:uuid();
    }
    fired {
      ent:password := {};
      ent:password{"salt"} := salt;
      ent:methodpassword{"password"} := ent:method.defaultsTo("password"one_way_hash(password);
      ent:password{"last_encoding"} := eventtime:attrnow("new_password");
    }
  }

Function code

Your account ruleset must be able to provide the current code words (established when it reacted to the owner:eci_provided event) when requested by the owner, who uses the URL provided when he created his owner pico. The reference ruleset defines this function, and which it must also mention in the shares clause of its meta block.

Code Block
    code = function() {
      ent:code || "code words expired"
    }

Technical notes

...

Besides the reference rulesets shown on this page, there are official rulesets, named io.picolabs.account_management and io.picolabs.owner_authentication, located in GitHub. Because of their location, they will already be registered in your node pico engine. You may choose to use these rulesets instead of creating your own. You may find it instructive to compare them with the reference rulesets, which they will eventually replace.

...