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

PDS Client 2.0 JavaScript API

{{#eclipseproject:technology.higgins|eclipse_custom_style.css}}

Introduction

The JavaScript API allows the developer (the API consumer) to simply treat the PDS Client and any personal or managed data stores in the cloud as one big database. It allows you to read or write in a single operation a set of attributes and their values.

The JavaScript API is implemented by a NPAPI browser plugin that is used in the user’s “regular” browser as well as the Dashboard’s embedded browser. This API is intended to support a variety of apps that need access to data about the current user.

Applications

The following apps being developed in Higgins consume this API by Javascript calls specified by an app-card:

  • Password Manager
  • Form filler
  • App-Card Framework

Complexity Hiding

This API supports two ways of accessing the underlying data.

"Flat" APIs

In the "flat" version of the API calls, the consumer doesn't need to understand nor have to navigate the structured nature of that some attributes in the Persona Data Model 2.0 (PDM) have. Similarly it doesn't require the consumer to understand nor have to navigate the graph structure of the underlying p:Person nodes in this data model. Instead it hides all of these complexities.

For example, the fact that in the PDM we might have a p:person node of role “payer” with a vcard:adr link to a v:Address object that in turn has a vcard:street-name attribute and value is hidden. The getRPAttributes() consumer simply has to ask for the "payer street name" attribute and they will get back a literal string value like "123 main street”.

By hiding the underlying structures the API implementation, code can protect the underlying data structures from being directly accessed and possibly accidentally or maliciously modified such that they are in an inconsistent state.

"Structured" APIs

One consequence of the structure flattening and information hiding described above is that apps that by their very nature require read/write access to most or all of the underlying PDM objects can not use this API. This kind of app needs access to lower level APIs closer to the “raw” IdAS API that exposes all contexts and contained entities.

Types

Consumer Identifier

When a JavaScript app calls one of those APIs we need to identify: the current user, the AppCard, and relying party (web site where data is being shared) for access control purposes. For that purpose, we define the following structure:

struct consumer_id
{
   string app_id; //AppCard's ID
   string relying_party; // source/destination of shared data
};

Note that the current user can be determined inside the PDS Client and therefore needn't be passed as a parameter.

Context Identifier

When a JavaScript app calls one of those APIs we need to identify the context to read the data from or write the data to. This requires the following fields: the user that owns the context, the app that owns the context, and the issuer of the data. For that purpose, we define the following structure:

struct context_id
{
   string user_id; // Owning user's ID
   string app_id; // Owning AppCard's ID
   string issuer; // source/destination of data
};

Attribute Values

In 'simple input arg style' case, we need to transfer attributes with their values by the following structure:

struct att_vals
{
   string att_type; //Attribute
   string array values; //Array of its values
};

Return Codes

0 - success
other - error code

Flat Data Model Functions

setRPAttributes

getRPAttributes

string getRPAttributes
(
   in string ctxt,            // Either a contextId (UDI) or a GUID string that
                              // identifies the "context" within which these data attributes will
                              // be used--also the string must be syntactically clean enough
                              // that it can be used as the root of a newly minted contextId 
                              // (this contextId will be returned by this method).
                              // As an example of a GUID, consider that a case
                              // where a form-filler app is making the call and will submit the
                              // returned attributes to "staples.com/<some-path>". In this case
                              // the string "staples.com/<some-path>" can be used as the GUID.
   in string app,             // Identifier of the software agent (e.g. app-card app id 
                              // or HBX itself) that is making this call and conveying the 
                              // returned attributes to the RP. 
   in string atts,            // json request, see below
   in dateTime effective,     // Attributes returned should be accurate as of this date/time 
   in string where,           // json structure, see below
   in string array token_type // 
   in string issuer_policy    // As defined in the IMI spec
   in string privacy_url      // As defined in the IMI spec
   in string privacy_version  // As defined in the IMI spec
   in boolean interactive     // If true then pop up a selector UI in case of ambiguity 
                              // as to which p:Person nodes to use as sources 
   out string res             // json result
);
atts is an array of the following structures:
{
  string attribute     // URI of attribute in some namespace 
                       // (usually the RP's namespace or [[Flat Persona vocabulary]]
  boolean optional     // if true then this attribute is desired but not required)
  string authorities[] // list of domains that are considered by the caller as authoritative
                       // WRT this attribute. Only contexts whose h:issuer matches 
                       // may be used as the source of the attribute, if this list is 
                       // nil then values from any authority are acceptable including
                       // self asserted values.
}
where is an array of the following structures:
{
  string attribute        // URI of attribute in some namespace (usually the RP's 
                          // namespace or [[Flat Persona vocabulary]])
  string value-expression // must be a string consisting of one or more characters 
                          // followed by an asterisk (e.g. "25*") --meaning that the 
                          // value of the attribute must start with this string (e.g. "2599")
}
Either return an array of the following structures 
{
  string attribute // URI of attribute
  value            // value of the attribute
}
or... if the query is ambiguous and we are in non-interactive mode then return an array of entityIds of p:Person nodes

(A) Instantiate context if not present

If no context of id=ctxt exists [1] then

  1. Instantiate a context whose contextId is either ctxt or derived from ctxt
  2. If a template context can be found for this RP (e.g. staples.com) then
    1. Use it as the template (p:template) for the new context
  3. Else
    1. Use the common Flat Persona template as the template (p:template) for the new context. The Flat Persona template is merely a shared, singleton context whose p:vocabulary points to (a context containing) the Flat Persona vocabulary
  4. Instantiate a new p:Person within the context
  5. Add a link from "me" in the root context to this new p:Person

(B) Analyze the list of requested attributes

In this step we look at the requested attributes and look at the existing Person instances. The goal of the analysis phase is to find which p:Person nodes (if any) will be used as the source for which of the requested attributes. We try to find the smallest set of source Person nodes. In some simple cases a single Person node may be the source for all attribute values.

B := Attribute Request Analysis()

The output of the analysis stage is a set, B, of these blocks:

 block 
 {
   requested-attributes 
   {
     URI attribute
     boolean optional
     string issuers[]
   } [];
   entityId sourcePerson[];
 }

For each member, Bi, of B

  1. If the sizeOf(Bi.sourcePerson[])<=1 then continue
  2. If the Person node in context=ctxt has sub-Persons (linked by h:correlation links internal to the context) AND if it is a member of the list Bi.sourcePerson[] then remove all other person nodes from Bi.sourcePerson[].

(C) Display card selector

At this point it is possible that there remain sourcePerson[] sets with more than one member. If so, we'll ask the user to make a choice by displaying a card selector UI window and having them pick cards.

If there remain sourcePerson[] sets with more than one member within B AND if interactive is true then display the card selector window in the Dashboard app showing the i-card context of each context of each "ambiguous" Bi.sourcePerson[]. (If no such i-card context exists then create a generic one dynamically). If interactive is false then we'll have to give up on being able to provide the attributes in any block that has multiple Persons

  1. Wait for the user to click a card
  2. By clicking a card the user is giving consent to release these attributes (not only this one time but from now on) and (in the case where there were multiple cards that could contribute the same attribute(s) the user is disambiguating the situation—making a personal choice as to which card among the set of alternatives should be used.
  3. Each time a card is clicked, any remaining redundant card should be greyed out (or perhaps completely hidden)
  4. Repeat the above until there are no more cards to pick.

The effect of clicking cards is to remove all but one member from any sourcePerson[] sets that had more than one member

(D) Generate output

For each requested attribute, RA,

  1. If RA is not on the “approved for release” list [3] of the context (ctxt) then skip to the next requested attribute
  2. Lookup A’s associated mapping rule, R
  3. Lookup the mapped attribute, MA of R
  4. Trace R’s mapping path from P to see if P has a value for attribute MA
  5. If it does then
    1. Record this value to be returned. If there are multiple literal (leaf) values, return all of them. If there are multiple complex values (e.g. multiple values of osoc:jobs) then return all of them (and all of their substructure and values)
  6. Else
    1. Follow the p:source link that is a source for RA
    2. Repeat the above procedure using the target of p:source as the new “base” p:Person node

Return attributes/values.

Hmm.. we also said we're return the contextId (UDI) associated with ctxt

Errata (mistakes and omissions in the above master flow)

  1. An extra level of logical indirection is built into AppCard contexts and support for this needs to be added to the logic above. Let me explain. Whereas most contexts directly contain data (most notably p:Person and related objects), some contexts, namely AppCard contexts, are really pointers to data. Their p:Person node points to an entity in its associated AppData context. This is the extra level of indirection. If a p:subCorrelation link from, say, RootMe points to p:Person node P within an AppCard context, then the “real” person data lies at the entity pointed to by P’s resource-udr attribute.

References

  • [1] The ContextId of a context is the id of the RP with which it is associated
  • [2] Attribute URIs are either relative to the RP (e.g. staples.com attributes) or they are from Flat Persona vocabulary
  • [3] See Event vocabulary#Disclosure
  • [4] See Template vocabulary
  • [5] Details about segmenting the requested attributes: We look at each requested attribute. If the attribute has one or more role parameter(s) in its URI then we look at it/them. We also look to see if the mapping rule associated with this attribute (in the AttrributeMap) has any explicit role tags specified. If no roles are specified in either place then for the purposes of this segmentation that is considered the role "Null". From this analysis we can sort each of the requested attributes into a separate role-set. For example here are four role-sets: {Home}, {Home, Recipient}, {Null}, {Work}. Each of the requested attributes would be associated with one of these four.
  • [6] See GetRPAttributes Design Considerations
  • [7] See GetRPAttributes Example Flow

getSuggestions

Structured Data Model Functions

addEntityAttributes

setEntityAttributes

delEntityAttributes

getEntityAttributes

short getEntityAttributes
(
   in consumer_id, // issuer, appId - identifies app which asks the data
   in supplier_id, // issuer, appId - identifies app which provides the data
   in string atts, // json request, see below
   in string array token_type // see Action Support wiki page
   out string res // json result, see below
);

Dashboard Functions

The following APIs are not exposed to JavaScript running in browsers other than the Dashboard's embedded browser.

removePWData

getPWException

removePWException

removeRMCard

Copyright © Eclipse Foundation, Inc. All Rights Reserved.