RFC 3341

The Application Exchange (APEX) Access Service

๐Ÿ“… published July 2002, from ietf

RFC 3341: The Application Exchange (APEX) Access Service โœจ

Okay bestie, let's get the basics down first ๐ŸŽ€

  • Number: RFC 3341
  • Title: The Application Exchange (APEX) Access Service
  • Stream: Network Working Group
  • Category: Standards Track, so this is an Internet standards track protocol ๐Ÿ”ฅ
  • Date: July 2002
  • Authors:
    • M. Rose, Dover Beach Consulting, Inc.
    • G. Klyne, Clearswift Corporation
    • D. Crocker, Brandenburg InternetWorking
  • Obsoletes / Updates: the title block doesn't list anything it obsoletes or updates ๐Ÿ’…

Status of This Memo

Okay so this doc is an Internet standards track protocol for the whole Internet community, and it's literally asking people for discussion and suggestions for improvements ๐Ÿซถ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐Ÿ’Œ

Copyright (C) The Internet Society (2002).  All Rights Reserved.

Abstract

Here's the vibe: this memo describes the Application Exchange (APEX) access service, which is addressed as the well-known endpoint apex=access ๐Ÿฆ‹ The access service is the one that controls use of both the APEX "relaying mesh" and other APEX services. Main character energy, honestly ๐Ÿ‘‘

Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
   2.  Use and Management of Access Information . . . . . . . . . . .  3
   2.1 Querying Access Information  . . . . . . . . . . . . . . . . .  3
   2.2 Retrieval of Access Information  . . . . . . . . . . . . . . .  4
   2.3 Update of Access Information . . . . . . . . . . . . . . . . .  5
   3.  Format of Access Entries . . . . . . . . . . . . . . . . . . .  9
   3.1 Finding the Appropriate Entry: Matching Owners and Actors  . . 11
   3.2 Creating and Updating Access Entries . . . . . . . . . . . . . 14
   4.  The Access Service . . . . . . . . . . . . . . . . . . . . . . 14
   4.1 Use of XML and MIME  . . . . . . . . . . . . . . . . . . . . . 15
   4.2 The Query Operation  . . . . . . . . . . . . . . . . . . . . . 16
   4.3 The Get Operation  . . . . . . . . . . . . . . . . . . . . . . 17
   4.4 The Set Operation  . . . . . . . . . . . . . . . . . . . . . . 18
   4.5 The Reply Operation  . . . . . . . . . . . . . . . . . . . . . 20
   5.  Registration: The Access Service . . . . . . . . . . . . . . . 20
   6.  The Access Service DTD . . . . . . . . . . . . . . . . . . . . 21
   7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 23
       References . . . . . . . . . . . . . . . . . . . . . . . . . . 23
       Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 24
   A.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 25
       Full Copyright Statement . . . . . . . . . . . . . . . . . . . 26

1. Introduction โœจ

So this memo describes an access service that's built on top of the APEX [1] "relaying mesh" ๐Ÿ•ธ๏ธ The APEX access service is the thing that controls use of both the relaying mesh and other APEX services.

APEX is basically a best-effort datagram service at its core ๐Ÿ“ฆ Within one administrative domain, all relays must be able to handle messages for any endpoint in that domain. APEX services are logically defined as endpoints, but since they have such ubiquitous semantics, they don't necessarily have to be tied to a single physical endpoint. So they may be provisioned co-resident with each relay inside an administrative domain, even though they're logically provided on top of the relaying mesh, i.e.,

      +----------+     +----------+    +----------+    +---------+
      |   APEX   |     |   APEX   |    |   APEX   |    |         |
      |  access  |     | presence |    |  report  |    |   ...   |
      | service  |     |  service |    | service  |    |         |
      +----------+     +----------+    +----------+    +---------+
           |                |               |               |
           |                |               |               |
   +----------------------------------------------------------------+
   |                                                                |
   |                            APEX core                           |
   |                                                                |
   +----------------------------------------------------------------+

That is, applications talk to an APEX service by exchanging data with a "well-known endpoint" (WKE) ๐Ÿงš

APEX applications talk to the access service by exchanging data with the well-known endpoint apex=access in the matching administrative domain. For example, apex=access@example.com is the endpoint for the access service in the example.com administrative domain ๐Ÿ’–

Note that within a single administrative domain, the relaying mesh uses the APEX access service to figure out whether an originator is allowed to transmit data to a recipient (c.f., Step 5.3 of Section 4.4.4.1 of [1]). Lowkey a very important job ๐Ÿ˜ญ

2. Use and Management of Access Information ๐ŸŽ€

Access information is organized around access entries. Each one contains:

  • an owner: an APEX address that the entry is associated with;
  • an actor: an APEX address that's granted permission to perform some action in the context of the owner;
  • a list of actions; and,
  • a timestamp showing when the service last created or modified the access entry.

The access entry for a given owner controls access to a potentially large range of different APEX services, like data delivery, access control, and presence information ๐ŸŒˆ Section 4.5 of [1] also talks about APEX access policies that govern things like peer authentication, message relaying, and so on.

Managing access information falls into three categories:

  • applications may query the access service to see if one or more actions are allowed;
  • applications may retrieve access information associated with an owner/actor combination; and,
  • applications may modify (i.e., create, replace, or delete) access information associated with an owner/actor combination.

Each one gets its own section, so let's go through them in order ๐Ÿ’…

2.1 Querying Access Information

When an application wants to figure out whether one or more actions are allowed for an owner/actor combination, it sends a "query" element to the service. Like this ๐Ÿ‘€

    +-------+                  +-------+
    |       | -- data -------> |       |
    | appl. |                  | relay |
    |       | <--------- ok -- |       |
    +-------+                  +-------+

  C: <data content='#Content'>
         <originator identity='fred@example.com' />
         <recipient identity='apex=access@example.com' />
         <data-content Name='Content'>
             <query owner='fred@example.com' transID='1'
                    actor='barney@example.com'
                    actions='core:data presence:subscribe' />
         </data-content>
     </data>
  S: <ok />

The service responds right away with either an allow or a deny operation, and it uses the same transaction-identifier. "allow" means that all of the actions listed in the query are permitted ๐Ÿ™Œ For example:

                                 +-------+                  +-------+
                                 |       | <------- data -- |       |
                                 | relay |                  |access |
                                 |       | -- ok ---------> |  svc. |
                                 +-------+                  +-------+

    C: <data content='#Content'>
           <originator identity='apex=access@example.com' />
           <recipient identity='fred@example.com' />
           <data-content Name='Content'>
               <allow transID='1' />
           </data-content>
       </data>
    S: <ok />

or

    C: <data content='#Content'>
           <originator identity='apex=access@example.com' />
           <recipient  identity='fred@example.com' />
           <data-content Name='Content'>
               <deny transID='1' />
           </data-content>
       </data>
    S: <ok />

2.2 Retrieval of Access Information

When an application wants to pull up the access entry for an owner/actor combination (usually so it can update that access information afterwards), it sends a "get" element to the service ๐Ÿ” Here's how that looks:

    +-------+                  +-------+
    |       | -- data -------> |       |
    | appl. |                  | relay |
    |       | <--------- ok -- |       |
    +-------+                  +-------+

  C: <data content='#Content'>
         <originator identity='fred@example.com' />
         <recipient identity='apex=access@example.com' />
         <data-content Name='Content'>
             <get transID='2'
                  owner='fred@example.com'
                  actor='*@example.com' />
         </data-content>
     </data>
  S: <ok />

The service responds right away with a set operation that has the access entry and the same transaction-identifier ๐Ÿง For example:

                                +-------+                  +-------+
                                |       | <------- data -- |       |
                                | relay |                  |access |
                                |       | -- ok ---------> |  svc. |
                                +-------+                  +-------+

  C: <data content='#Content'>
         <originator identity='apex=access@example.com' />
         <recipient identity='fred@example.com' />
         <data-content Name='Content'>
             <set transID='2'>
                 <access owner='fred@example.com'
                         actor='*@example.com'
                         actions='core:data presence:subscribe'
                         lastUpdate='2000-05-14T13:02:00-08:00' />
             </set>
         </data-content>
     </data>
  S: <ok />

2.3 Update of Access Information ๐Ÿ’…

okay so this is where the access entries get updated ๐Ÿซถ when an app wants to create or modify an access entry for an owner/actor combo, it sends a set element to the service with the new entry in it. here's the vibe:

    +-------+                  +-------+
    |       | -- data -------> |       |
    | appl. |                  | relay |
    |       | <--------- ok -- |       |
    +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='wilma@example.com' />
         <recipient identity='apex=access@example.com' />
         <data-content Name='Content'>
             <set transID='1'>
                 <access owner='fred@example.com'
                         actor='*@example.com'
                         actions='core:data presence:subscribe'
                         lastUpdate='2000-05-14T13:02:00-08:00' />
             </set>
         </data-content>
     </data>
  S: <ok />

ngl the lastUpdate attribute is the main character here ๐Ÿ‘‘ Step 4 of Section 4.4 says you need to supply lastUpdate in order to update an entry, so apps have to successfully retrieve an access entry before they try to modify it. no shortcuts bestie ๐Ÿ™ˆ (and admins should make sure any app allowed to modify an entry is also allowed to retrieve it, iykyk ๐Ÿ’œ)

the service responds right away with a reply operation that has the same transaction-identifier:

                               +-------+                  +-------+
                               |       | <------- data -- |       |
                               | relay |                  |access |
                               |       | -- ok ---------> |  svc. |
                               +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='apex=access@example.com' />
         <recipient identity='wilma@example.com' />
         <data-content Name='Content'>
             <reply code='250' transID='1' />
         </data-content>
     </data>
  S: <ok />

Steps 6.2 and 9.2 of Section 4.4 mean the access service has to update the lastUpdate attribute of an access entry whenever it's created or modified ๐Ÿฆ‹

the service also immediately sends a set operation to the owner attribute tied to the access entry:

                               +-------+                  +-------+
                               |       | <------- data -- |       |
                               | relay |                  |access |
                               |       | -- ok ---------> |  svc. |
                               +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='apex=access@example.com' />
         <recipient identity='fred@example.com' />
         <data-content Name='Content'>
             <set transID='1'>
                 <access owner='fred@example.com'
                         actor='*@example.com'
                         actions='core:data presence:subscribe'
                         lastUpdate='2000-05-14T23:02:00-08:00' />
             </set>
         </data-content>
     </data>
  S: <ok />

now deleting ๐Ÿฅ€ when an app wants to delete the access entry for an owner/actor combo, it sends a set element to the service leaving out the permitted actions:

    +-------+                  +-------+
    |       | -- data -------> |       |
    | appl. |                  | relay |
    |       | <--------- ok -- |       |
    +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='wilma@example.com' />
         <recipient identity='apex=access@example.com' />
         <data-content Name='Content'>
             <set transID='2'>
                 <access owner='fred@example.com'
                         actor='*@example.com'
                         lastUpdate='2000-05-14T13:02:00-08:00' />
             </set>
         </data-content>
     </data>
  S: <ok />

the service immediately responds with a reply operation containing the same transaction-identifier:

                               +-------+                  +-------+
                               |       | <------- data -- |       |
                               | relay |                  |access |
                               |       | -- ok ---------> |  svc. |
                               +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='apex=access@example.com' />
         <recipient identity='wilma@example.com' />
         <data-content Name='Content'>
             <reply code='250' transID='2' />
         </data-content>
     </data>
  S: <ok />

and then the service also immediately sends a set operation to the owner attribute on the access entry:

                               +-------+                  +-------+
                               |       | <------- data -- |       |
                               | relay |                  |access |
                               |       | -- ok ---------> |  svc. |
                               +-------+                  +-------+
  C: <data content='#Content'>
         <originator identity='apex=access@example.com' />
         <recipient identity='fred@example.com' />
         <data-content Name='Content'>
             <set transID='2'>
                 <access owner='fred@example.com'
                         actor='*@example.com'
                         lastUpdate='2000-05-14T13:02:00-08:00' />
             </set>
         </data-content>
     </data>
  S: <ok />

Because there are no actions left on this access entry, the owner can tell it's been deleted ๐Ÿซ 

plot twist: deleting an access entry for one owner/actor combo might NOT actually remove permission ๐Ÿ˜ญ that's because access control allows limited wildcarding of actors, so the delete can end up modifying permission instead. that's why there's a special action, all:none, to handle it.

for example, say we've got these two access entries:

    <access owner='fred@example.com'
            actor='barney@example.com'
            actions='core:data presence:subscribe presence:watch'
            lastUpdate='2000-05-14T13:20:00-08:00' />

    <access owner='fred@example.com'
            actor='*@example.com'
            actions='core:data'
            lastUpdate='2000-05-14T13:20:00-08:00' />

deleting the first one will not remove all permissions for the actor barney@example.com. instead, the first access entry should be modified like this:

    <access owner='fred@example.com'
            actor='barney@example.com'
            actions='all:none'
            lastUpdate='2000-05-14T13:20:00-08:00' />

3. Format of Access Entries โœจ

okay now the structure ๐Ÿงš each administrative domain is responsible for keeping one or more "access entries" for each of its endpoints and their associated subaddresses, whether or not those addresses are currently attached to the relaying mesh.

you need a separate access entry for each actor, or group of actors, that you're giving access permission to. Section 6 defines the syntax for access entries. every access entry has an "owner" attribute, an "actor" attribute, an "actions" attribute, a "lastUpdate" attribute, and no content:

  • the owner attribute is the address (endpoint or subaddress) the access entry belongs to;
  • the actor attribute is an entity or group of entities that the access permissions apply to, as described below;
  • the actions attribute is the permissions granted to the actor in the context of the owner; and,
  • the lastUpdate attribute is the date and time the service last created or modified the access entry.

an action is written as a service/operation pair, so presence:publish means the "publish" operation of the "presence" service. two service values are reserved:

  • "all" refers to all services, e.g., all:data; and,
  • "core" refers to the service implemented by the relaying mesh, e.g., the core:data permission is consulted by the relaying mesh (c.f., Step 5.3 of Section 4.4.4.1 of [1]).

and two operation values are reserved too:

  • "all" refers to all operations, e.g., presence:all; and,
  • "none" refers to no operations whatsoever, e.g., all:none.

an actor is an APEX address, written using the "entity" syntax from Section 2.2 of [1]. but both the "local" and "domain" parts can contain limited wildcarding ๐ŸŒˆ

  • the "local" part is one of:
    • a literal string (e.g., fred);
    • a subaddress wildcard (e.g., fred/* or apex=pubsub/*); or,
    • the value apex=*, which means all APEX services;
    • the value *, which means any address other than an APEX service.
  • the "domain" part is one of:
    • a FQDN (e.g., example.com);
    • a domain wildcard (e.g., *.example.com); or,
    • the value *, which means all administrative domains.

note that with a domain wildcard, the wildcard itself matches zero or more subdomains. so *.example.com matches example.com, foo.example.com, bar.foo.example.com, and so on.

every owner gets the following default entries ๐Ÿ’œ but any explicitly supplied entry with the same actor value overrides them:

actor='local@domain'  actions='all:all'
actor='apex=*@domain' actions='all:all'
actor='apex=*@*'      actions='core:data'
actor='*@*'           actions='all:none'

where local@domain is the owner the access entry is for.

for example, this explicit entry:

actor='*@*'           actions='core:data'

lets endpoints from any domain use the relaying mesh to send data to the owner, but it does not override the default entry for apex=*@domain, which gives all APEX services in the owner's domain access to all actions ๐Ÿฆ‹

fun fact: APEX endpoint names can legitimately contain the character *, but access entries use * for wildcarding. so the two-character sequence \* is used to avoid the ambiguity in the "actor" attribute. likewise, if you want to explicitly specify an endpoint name containing \ in the "actor" attribute, you use the two-character sequence \\.

heads up: this convention only applies to the "actor" attribute of the "get" operation and of the "access" entry inside the "set" operation. it is not used in the "query" operation, because that operation doesn't allow wildcarding.

so to specify the endpoint named a\b*c@example.com in the "get" operation or in an "access" entry, the string a\\b\*c@example.com is used. but in the "query" operation, the string a\b*c@example.com is used. (of course, name allocation is a local matter, so you can skip all this drama by just not using endpoint names with * or \ ๐Ÿ’€โœจ)

3.1 Finding the Appropriate Entry: Matching Owners and Actors โœจ

Okay bestie, actor wildcarding means more than one access entry can apply to the same owner/actor combo ๐Ÿ‘€ So how does the service pick the right one when it answers a query operation? Here's the tea ๐Ÿ’…

  • Only look at the access entries tied to the given owner.
  • Only keep the entries whose actor value matches the actor address in the query. If there's a wildcard character (*) in the actor value, it's only a match if every wildcard can be swapped for a non-empty run of characters (one or more) to get exactly the address from the query ๐Ÿงฉ
  • Then rank whatever's left:
    • Use the exactness of the match with the domain part of the actor value as the primary key; and,
    • Use the exactness of the match with the local part of the actor value as the secondary key.
  • When matching the domain part, an exact match is the best match. Otherwise, the shorter the wildcard match, the higher the priority.

For example, if the actor's domain is "bar.foo.example.com", a match against an entry of ".foo.example.com" is better than a match against an entry of ".example.com" ๐Ÿ†

  • When matching the local part, an exact match is the best match. Otherwise, the shorter the wildcard match, the higher the priority. This is true whether the wildcarding is for a subaddress or a service. (Note that a local part with a wildcard subaddress does not have a non-empty match with the same local part without a subaddress ๐Ÿ™ˆ)

Let's look at an example with these access entries:

<access owner='fred@example.com'
        actor='wilma@example.com'
        actions='all:all'
        lastUpdate='2000-05-14T13:20:00-08:00' />
<access owner='fred@example.com'
        actor='mr.slate@example.com'
        actions='core:data'
        lastUpdate='2000-05-14T13:20:00-08:00' />
<access owner='fred/appl=wb@example.com'
        actor='barney/appl=wb@example.com'
        actions='core:data'
        lastUpdate='2000-05-14T13:20:00-08:00' />
<access owner='fred@example.com'
        actor='*@example.com'
        actions='core:data presence:subscribe presence:watch'
        lastUpdate='2000-05-14T13:20:00-08:00' />

<access owner='fred@example.com'
        actor='*@*'
        actions='core:data'
        lastUpdate='2000-05-14T13:20:00-08:00' />

Briefly, here's who gets what ๐Ÿฆ‹

  • For addresses within the "example.com" administrative domain:
    • "fred", "wilma", and all APEX services within the "example.com" administrative domain are allowed access to all operations for "fred@example.com" ๐Ÿ‘‘
    • "mr.slate" is allowed access only to send data through the relaying mesh to "fred@example.com" ๐Ÿ“จ
    • "barney/appl=wb" is allowed access only to send data to "fred/appl=wb", a subaddress of "fred@example.com" ๐ŸŽ€
    • any other address within the "example.com" administrative domain is allowed access to send data and invoke the "subscribe" and "watch" operations of the APEX presence service with respect to "fred@example.com" ๐ŸŒธ
  • For any address outside the "example.com" administrative domain, the address is allowed access to send data, regardless of whether it is an APEX service ๐ŸŒ

Note that although the four default entries are always available, the explicit entry for actor "@" overrides the corresponding default entry. Plot twist! ๐Ÿ’œ

3.2 Creating and Updating Access Entries โœจ

The get and set operations are the basic tools for creating and updating access rules, and they do no special wildcard processing ๐Ÿ› ๏ธ

An actor value for an access entry may contain limited wildcard characters. Those only have special meaning when you're doing a query operation (cf., Section 3.1). When you're retrieving or updating entries, actor values are treated simply as literal names ๐Ÿ“

4. The Access Service ๐ŸŒท

Section 5 contains the APEX service registration for the access service:

  • Within an administrative domain, the service is addressed using the well-known endpoint of apex=access.
  • Section 6 defines the syntax of the operations exchanged with the service.
  • A consumer of the service starts the conversation by sending data containing a query, get, or set operation.
  • The service replies to these operations.
  • When an access entry is changed, the service sends a notification to the owner associated with the changed entry.

An implementation of the service must maintain information about access entries in persistent storage ๐Ÿ’พ

Consult Section 6.1.1 of [1] for a discussion on the properties of long-lived transaction-identifiers ๐Ÿงš

4.1 Use of XML and MIME ๐ŸŽ€

Section 4.1 of [1] describes how arbitrary MIME content is exchanged as a BEEP [2] payload. For example, to transmit:

<data content='...'>
    <originator identity='fred@example.com' />
    <recipient identity='apex=access@example.com' />
</data>

where "..." refers to:

<query owner='fred@example.com' transID='1'
       actor='barney@example.com'
       actions='core:data presence:subscribe' />

then the corresponding BEEP message might look like this:

C: MSG 1 2 . 42 1234
C: Content-Type: multipart/related; boundary="boundary";
C:               start="<1@example.com>";
C:               type="application/beep+xml"
C:
C: --boundary
C: Content-Type: application/beep+xml
C: Content-ID: <1@example.com>
C:
C: <data content='cid:2@example.com'>
C:     <originator identity='fred@example.com' />
C:     <recipient identity='apex=access@example.com' />
C: </data>
C: --boundary
C: Content-Type: application/beep+xml
C: Content-ID: <2@example.com>
C:
C: <query owner='fred@example.com' transID='1'
C:        actor='barney@example.com'
C:        actions='core:data presence:subscribe' />
C: --boundary--
C: END

or this:

C: MSG 1 1 . 42 267
C: Content-Type: application/beep+xml
C:
C: <data content='#Content'>
C:     <originator identity='fred@example.com' />
C:     <recipient identity='apex=access@example.com' />
C:     <data-content Name='Content'>
C:         <query owner='fred@example.com' transID='1'
C:                actor='barney@example.com'
C:                actions='core:data presence:subscribe' />
C:     </data-content>
C: </data>
C: END

4.2 The Query Operation ๐Ÿ”

When an application wants to see if a particular operation is allowed, it sends a query element to the service ๐Ÿ’Œ

The query element has an owner attribute, an actor attribute, an actions attribute, a transID attribute, and no content:

  • the owner attribute specifies the address associated with the access entry;
  • the actor attribute specifies the address (without wildcarding) for which access permissions are queried;
  • the actions attribute specifies one or more actions for which permission is queried; and,
  • the transID attribute specifies the transaction-identifier associated with this operation.

When the service receives a query element, we call the owner attribute the "subject". The service runs through these steps ๐Ÿ•ต๏ธโ€โ™€๏ธ

  1. If the subject is outside this administrative domain, a reply element having code 553 is sent to the originator.
  2. If the subject does not refer to a valid address, a reply element having code 550 is sent to the originator.
  3. If the subject's access entry matching the originator does not contain an access:query token, a reply element having code 537 is sent to the originator.
  4. The subject's access entry matching the actor attribute of the query element is selected (cf., Section 3.1).
  5. If all of the permissions in the actions attribute of the query element are contained in the selected access entry, then an allow element is sent to the originator.
  6. Otherwise, a deny element is sent to the originator.

Regardless of whether an allow, deny, or reply element is sent to the originator, the transID attribute is identical to the value found in the query element sent by the originator ๐Ÿซถ

4.3 The Get Operation ๐Ÿงพ

Before creating or updating an access entry for some owner/actor combination, an application will usually need to retrieve any existing access entry. It does this by sending a get element to the service. In particular, a successful response returns a lastUpdate value that is necessary when sending a subsequent set element ๐Ÿ”

The get element has an owner attribute, an actor attribute, a transID attribute, and no content:

  • the owner attribute specifies the address associated with the access entry;
  • the actor attribute specifies the address (with possible wildcarding) for which access permissions are retrieved; and,
  • the transID attribute specifies the transaction-identifier associated with this operation.

When the service receives a get element, we call the owner attribute the "subject". The service runs through these steps ๐Ÿ•ต๏ธโ€โ™€๏ธ

  1. If the subject is outside this administrative domain, a reply element having code 553 is sent to the originator.
  2. If the subject does not refer to a valid address, a reply element having code 550 is sent to the originator.
  3. If the subject's access entry matching the originator does not contain an access:get token, a reply element having code 537 is sent to the originator.
  4. The subject's access entry whose actor attribute identically matches the actor attribute of the get element is selected.
  5. If no such entry exists, a reply element having code 551 is sent to the originator.
  6. Otherwise, a set element corresponding to the selected access entry is sent to the originator.

Regardless of whether a set or reply element is sent to the originator, the transID attribute is identical to the value found in the get element sent by the originator ๐Ÿ’–

4.4 The Set Operation ๐Ÿ’…

okay so this is where the magic happens ๐Ÿ”ฅ when an application wants to modify an access entry (create it, replace it, or delete it), it sends a set element to the service.

The set element has a transID attribute and contains an access element:

  • the transID attribute specifies the transaction-identifier associated with this operation; and,
  • the access element contains the access entry to be created, replaced, or deleted.

The access element has an owner attribute, an actor attribute, an optional actions attribute, an optional lastUpdate attribute, and no content:

  • the owner attribute specifies the address associated with the access entry;
  • the actor attribute specifies the address (with possible wildcarding) for which access permissions are specified;
  • the actions attribute (present only to add or replace an entry) specifies one or more actions for which permission is to be determined; and,
  • the lastUpdate attribute (present only to replace or delete an entry) specifies the current timestamp of the access entry that is to be replaced.

when the service gets a set element, the owner attribute of the access element is called the "subject" ๐Ÿ‘‘ the service then does these steps:

  1. If the subject is outside this administrative domain, a reply element having code 553 is sent to the originator.
  2. If the subject does not refer to a valid address, a reply element having code 550 is sent to the originator.
  3. If the subject's access entry matching the originator does not contain an access:set token, a reply element having code 537 is sent to the originator.
  4. The subject's access entry whose actor attribute identically matches the actor attribute of the set element is selected.
  5. If no such entry exists and the lastUpdate attribute is present in the supplied set element, a reply element having code 555 is sent to the originator.
  6. If no such entry exists and the lastUpdate attribute is absent in the supplied set element, then:
    1. The access entry for the owner/actor combination is created from the supplied access element.
    2. The lastUpdate attribute of that access entry is set to the service's notion of the current date and time.
    3. A reply element having code 250 is sent to the originator.
    4. A set element corresponding to the newly-created access entry is sent to the subject's address.
  7. If the selected entry exists, but its lastUpdate attribute is not semantically identical to the lastUpdate attribute of the supplied access element, a reply element having code 555 is sent to the originator.
  8. If the actions attribute of the supplied access element is not present, then:
    1. The selected entry is deleted.
    2. A reply element having code 250 is sent to the originator.
    3. A set element corresponding to the owner/actor combination, but lacking an actions attribute, is sent to the subject's address.
  9. Otherwise:
    1. The access entry for the owner/actor combination is updated from the supplied access element.
    2. The lastUpdate attribute of the updated access entry is set to the service's notion of the current date and time (which should be different from the lastUpdate value associated with any replaced entry).
    3. A reply element having code 250 is sent to the originator.
    4. A set element corresponding to the newly-updated access entry is sent to the subject's address.

when the service sends the reply element, the transID attribute matches the value found in the set element that the originator sent โœจ

4.5 The Reply Operation ๐ŸŽ€

while processing operations, the service might respond with a reply element. Consult Sections 10.2 and 6.1.2 of [1], respectively, for the definition and an exposition of the syntax of the reply element ๐Ÿค“

5. Registration: The Access Service ๐Ÿฆ‹

  • Well-Known Endpoint: apex=access
  • Syntax of Messages Exchanged: c.f., Section 6
  • Sequence of Messages Exchanged: c.f., Section 4
  • Access Control Tokens: access:query, access:get, access:set
  • Contact Information: c.f., the "Authors' Addresses" section of this memo

6. The Access Service DTD ๐Ÿงš

here's the whole DTD, verbatim, because it's the one thing you can't paraphrase ๐Ÿ™ˆ

<!--
  DTD for the APEX access service, as of 2001-06-19

  Refer to this DTD as:

    <!ENTITY % APEXACCESS PUBLIC "-//IETF//DTD APEX ACCESS//EN" "">
    %APEXACCESS;
  -->

<!ENTITY % APEXCORE PUBLIC "-//IETF//DTD APEX CORE//EN" "">
%APEXCORE;

<!--
  DTD data types:

       entity        syntax/reference     example
       ======        ================     =======
    access actor
       ACTOR         an ENDPOINT or a     *@example.com
                     wildcard

    permitted actions
       ACTIONS       a list of access     "core:any access:query"
                     tokens
  -->

<!ENTITY  % ACTOR   "CDATA">
<!ENTITY  % ACTIONS "NMTOKENS">

<!--
  Synopsis of the APEX access service

    service WKE: apex=access

    message exchanges:

        consumer initiates    service replies
        ==================    ================
        query                 allow, deny, or reply
        get                   set or reply
        set                   reply

        service initiates     consumer replies
        =================     ================
        set                   (nothing)

    access control:

        token                 target
        ==========            ======
        access:query          for "owner" of "access" element
        access:get            for "owner" of "access" element
        access:set            for "owner" of "access" element
  -->

<!ELEMENT query       EMPTY>
<!ATTLIST query
          owner       %ENDPOINT;        #REQUIRED
          actor       %ACTOR;           #REQUIRED
          actions     %ACTIONS;         #REQUIRED
          transID     %UNIQID;          #REQUIRED>

<!ELEMENT get         EMPTY>
<!ATTLIST get
          owner       %ENDPOINT;        #REQUIRED
          actor       %ACTOR;           #REQUIRED
          transID     %UNIQID;          #REQUIRED>

<!ELEMENT set         (access)>
<!ATTLIST set
          transID     %UNIQID;          #REQUIRED>

<!ELEMENT allow       EMPTY>
<!ATTLIST allow
          transID     %UNIQID;          #REQUIRED>

<!ELEMENT deny        EMPTY>
<!ATTLIST deny
          transID     %UNIQID;          #REQUIRED>

<!--
  access entries
  -->

<!ELEMENT access      EMPTY>
<!ATTLIST access
          owner       %ENDPOINT;        #REQUIRED
          actor       %ACTOR;           #REQUIRED
          actions     %ACTIONS;         #IMPLIED
          lastUpdate  %TIMESTAMP;       #IMPLIED>

7. Security Considerations ๐Ÿ”

this is the serious part, so pay attention ๐Ÿ‘€

Consult [1]'s Section 11 for a discussion of security issues.

In addition, timestamps issued by the the access service may disclose location information. If this information is considered sensitive, the special timezone value "-00:00" may be used (after converting the local time accordingly).

References ๐Ÿ“š

[1] Rose, M., Klyne, G. and D. Crocker, "The Application Exchange Core", RFC 3340, July 2002.

[2] Rose, M., "The Blocks Extensible Exchange Protocol Core", RFC 3080, March 2001.

Authors' Addresses ๐Ÿ“ฎ

Marshall T. Rose Dover Beach Consulting, Inc. POB 255268 Sacramento, CA 95865-5268 US

Phone: +1 916 483 8878 EMail: mrose@dbc.mtview.ca.us

Graham Klyne Clearswift Corporation 1310 Waterside Arlington Business Park Theale, Reading RG7 4SA UK

Phone: +44 11 8903 8903 EMail: Graham.Klyne@MIMEsweeper.com

David H. Crocker Brandenburg Consulting 675 Spruce Drive Sunnyvale, CA 94086 US

Phone: +1 408 246 8253 EMail: dcrocker@brandenburg.com URI: http://www.brandenburg.com/

Appendix A. Acknowledgements ๐Ÿซถ

the authors gratefully acknowledge the contributions of Neil Cook, Darren New, Chris Newman, Scott Pead, and Bob Wyman ๐Ÿ’œ

Copyright (C) The Internet Society (2002). All Rights Reserved.

okay so you're totally allowed to copy this document and pass it around, and to make derivative works that comment on it, explain it, or help people implement it. You can publish and distribute those, in whole or in part, with no restriction of any kind, as long as the copyright notice and this paragraph stay on all copies and derivative works.

however, this document itself may not be modified in any way, like removing the copyright notice or the references to the Internet Society or other Internet organizations. The exceptions are when it's needed for developing Internet standards (in which case the copyright procedures in the Internet Standards process must be followed), or when it's being translated into languages other than English.

the limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns ๐ŸŒˆ

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement ๐Ÿ’–

funding for the RFC Editor function is currently provided by the Internet Society โœจ

๐Ÿ“ฆ where this page comes from