chap-rest.xml revision 4a48635cccc646ac479830fd4df0ee8e10c5bd8d
<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! http://creativecommons.org/licenses/by-nc-nd/3.0/
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! src/main/resources/legal-notices/CC-BY-NC-ND.txt.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2013 ForgeRock AS
!
-->
<chapter xml:id='chap-rest'
xmlns='http://docbook.org/ns/docbook'
version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'
xmlns:xinclude='http://www.w3.org/2001/XInclude'>
<title>Using RESTful Web Services</title>
<indexterm><primary>REST API</primary></indexterm>
<para>This chapter shows how to use the OpenAM RESTful interfaces for direct
integration between web client applications and OpenAM.</para>
<section xml:id="about-openam-rest-api">
<title>About the RESTful API</title>
<para>OpenAM offers a RESTful API for these access and identity management
operations:</para>
<itemizedlist>
<listitem>
<para><link linkend="rest-api-auth">Authentication</link> (login)</para>
</listitem>
<listitem>
<para><link linkend="rest-api-auth">Logout</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-tokens">Token attribute retrieval</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-tokens">Token validation</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-authz">Authorization</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-oauth2">OAuth 2.0 Authorization</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-logging">Logging</link></para>
</listitem>
<listitem>
<para><link linkend="rest-api-crud">Identity management</link> (creating,
reading, updating, deleting identities)</para>
</listitem>
</itemizedlist>
<para>To call the API, access URLs under <literal>identity/</literal> where
OpenAM is deployed, such as
<literal>https://openam.example.com:8443/openam/identity/</literal>.</para>
<para>You can select the output format returned by specifying
<literal>json/</literal> or <literal>xml/</literal> in the URL after
<literal>identity/</literal>. For example, to return JSON, specify
<literal>https://openam.example.com:8443/openam/identity/json/</literal>.</para>
<para>For the examples in this chapter, OpenAM has c66Encode for cookies
activated. The encoding ensures that OpenAM tokens need not be percent
encoded before being submitted with a request. Thus, an example token
looks like this.</para>
<literallayout class="monospaced">token.id=AQIC5wM2LY4SfczntBbXvEAOuECbqMY3J4NW3byH6xwgkGE.*AAJTSQACMDE.*</literallayout>
<para>Without c66Encode activated, the same token might look like this.</para>
<literallayout class="monospaced">token.id=AQIC5wM2LY4SfczntBbXvEAOuECbqMY3J4NW3byH6xwgkGE=@AAJTSQACMDE=#</literallayout>
<para>In the latter example, you would have to <link
xlink:href="http://en.wikipedia.org/wiki/Percent-encoding">percent
encode</link> the <literal>=</literal>, <literal>@</literal>, and
<literal>#</literal> characters in your requests.</para>
<para>In this chapter, long URLs are wrapped to fit the printed page.</para>
</section>
<section xml:id="rest-api-auth">
<title>Authentication &amp; Logout</title>
<indexterm>
<primary>Authentication</primary>
<secondary>REST API</secondary>
</indexterm>
<indexterm>
<primary>Session tokens</primary>
<secondary>REST API</secondary>
</indexterm>
<para>Simple authentication with a user name and password returns a
token.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate?
username=bjensen
&amp;password=hifalutin"
token.id=AQIC5wM2LY4SfcxvdvHOXjtC_eWSs2RB54tgvgK8SuYi7aQ.*AAJTSQACMDE.*</screen>
<para>If you must specify parameters as when authenticating to
<literal>/UI/Login</literal>, you provide a percent encoded string of the
parameters as the value of the <literal>uri</literal> parameter.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate?
username=bjensen
&amp;password=hifalutin
&amp;uri=realm=%2F%26module=DataStore"
token.id=AQIC5wM2LY4SfcxvdvHOXjtC_eWSs2RB54tgvgK8SuYi7aQ.*AAJTSQACMDE.*</screen>
<para>You log out using the token to end the user session.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/logout?
subjectid=AQIC5wM2LY4SfcxvdvHOXjtC_eWSs2RB54tgvgK8SuYi7aQ.*AAJTSQACMDE.*"</screen>
</section>
<section xml:id="rest-api-tokens">
<title>Token Validation &amp; Attribute Retrieval</title>
<para>You check whether a token is valid as follows.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/isTokenValid?
tokenid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*"
boolean=true</screen>
<para>An invalid token returns a <errorcode>401</errorcode> and an error
page.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/isTokenValid?
tokenid=INVALID"
&lt;html&gt;...HTTP Status 401...&lt;/html&gt;</screen>
<para>With a valid token, you can retrieve attributes about the subject.
OpenAM returns a series of <replaceable>name</replaceable>,
<replaceable>value</replaceable> pairs.</para>
<indexterm>
<primary>User data</primary>
<secondary>REST access</secondary>
</indexterm>
<screen>$ curl "https://openam.example.com:8443/openam/identity/attributes?
subjectid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*"
userdetails.token.id=
AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
userdetails.attribute.name=uid
userdetails.attribute.value=bjensen
userdetails.attribute.name=mail
userdetails.attribute.value=bjensen@example.com
userdetails.attribute.name=sn
userdetails.attribute.value=Jensen
userdetails.attribute.name=userpassword
userdetails.attribute.value={SSHA}rhusOfYpkapDWEHcfT2Y7y83LMuC++F4Abqvig==
userdetails.attribute.name=cn
userdetails.attribute.value=Babs Jensen
userdetails.attribute.value=Barbara Jensen
userdetails.attribute.name=givenname
userdetails.attribute.value=Barbara
userdetails.attribute.name=dn
userdetails.attribute.value=uid=bjensen,ou=people,dc=example,dc=com
userdetails.attribute.name=telephonenumber
userdetails.attribute.value=+1 408 555 1862
userdetails.attribute.name=objectclass
userdetails.attribute.value=organizationalPerson
userdetails.attribute.value=person
userdetails.attribute.value=posixAccount
userdetails.attribute.value=inetOrgPerson
userdetails.attribute.value=krbprincipalaux
userdetails.attribute.value=krbTicketPolicyAux
userdetails.attribute.value=top</screen>
<para>You can specify attributes to limit what you retrieve.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/attributes?
subjectid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
&amp;attributenames=mail
&amp;attributenames=uid"
userdetails.token.id=
AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
userdetails.attribute.name=uid
userdetails.attribute.value=bjensen
userdetails.attribute.name=mail
userdetails.attribute.value=bjensen@example.com</screen>
<para>When retrieving attributes, you can refresh the session thus setting
the idle time to 0, by adding the boolean parameter
<literal>refresh=true</literal> to the query string.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/attributes?
subjectid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
&amp;attributenames=cn
&amp;refresh=true"
userdetails.token.id=
AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
userdetails.attribute.name=cn
userdetails.attribute.value=Babs Jensen
userdetails.attribute.value=Barbara Jensen</screen>
</section>
<section xml:id="rest-api-authz">
<title>Authorization</title>
<indexterm>
<primary>Policy</primary>
<secondary>REST API</secondary>
</indexterm>
<para>You can call on OpenAM to decide whether to authorize access to a
protected resource based on a valid token. Of course, you must percent
encode the resource URI.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authorize?
uri=http%3A%2F%2Fwww.example.com%3A8080%2Fexamples%2Findex.html
&amp;subjectid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*"
boolean=true</screen>
<para>To indicate access denied, OpenAM returns
<literal>boolean=false</literal>.</para>
<para>Additionally, you can access entitlements and entitlement policy
decisions using the REST interface. In order to access the entitlements
interface, you cannot however use the authentication token as is.
Instead you must encode the token as performed in
<link
xlink:href="http://sources.forgerock.org/browse/~raw,r=6/openam/trunk/opensso/www/public/use/docs/fampdf/Encoder.java"
><filename>Encoder.java</filename></link>, and then URL-encode the
result.</para>
<para>The entitlements REST interface uses the following path suffixes and
query string parameters.</para>
<itemizedlist>
<para>Path suffixes for entitlements include the following.</para>
<listitem>
<para><literal>ws/1/entitlement/decision</literal>: request a decision
pertaining to a single resource</para>
</listitem>
<listitem>
<para><literal>ws/1/entitlement/decisions</literal>: request decisions
pertaining to multiple resources</para>
</listitem>
<listitem>
<para><literal>ws/1/entitlement/entitlement</literal>: request decisions
for a specified resource URL and all resources underneath</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>Query string parameters for entitlements include the following.</para>
<listitem>
<para><literal>subject=<replaceable>encoded-token</replaceable></literal>,
where the encoded token is as describe above.</para>
</listitem>
<listitem>
<para><literal>action=get</literal>, or <literal>action=post</literal>,
which identifies the user agent action when requesting a decision.</para>
</listitem>
<listitem>
<para><literal>application=iPlanetAMWebAgentService</literal></para>
</listitem>
<listitem>
<para><literal>resource=<replaceable>resource-url</replaceable></literal>,
or multiple <literal>resources=<replaceable>resource-url</replaceable></literal>
parameters for multiple decisions.</para>
</listitem>
<listitem>
<para><literal>env=<replaceable>requestDnsName%3Dfqdn</replaceable></literal>,
<literal>env=<replaceable>requestIP%3Ddotted-quads</replaceable></literal>,
<literal>env=<replaceable>requestTime%3Dseconds-since-epoch</replaceable></literal>,
and <literal>env=<replaceable>requestDnsName%3Dtime-zone</replaceable></literal>
where <replaceable>time-zone</replaceable> is from Java
<literal>TimeZone.getTimeZone().getID()</literal>. The
<literal>env</literal> parameters thus express conditions.</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="rest-api-oauth2">
<title>OAuth 2.0 Authorization</title>
<indexterm>
<primary>OAuth 2.0</primary>
<secondary>REST API</secondary>
</indexterm>
<itemizedlist>
<para>OpenAM exposes the following REST endpoints for different OAuth 2.0
purposes.</para>
<listitem>
<para>Endpoints for <link linkend="rest-api-oauth2-client-endpoints">OAuth
2.0 clients and resource servers</link>, mostly defined in RFC 6749,
<link xlink:href="http://tools.ietf.org/html/rfc6749" xlink:show="new"
><citetitle>The OAuth 2.0 Authorization Framework</citetitle></link>, with
an additional <literal>tokeninfo</literal> endpoint useful to resource
servers.</para>
</listitem>
<listitem>
<para>An endpoint for <link linkend="rest-api-oauth2-token-admin-endpoint"
>OAuth 2.0 token administration</link>. This is specific to OpenAM.</para>
</listitem>
<listitem>
<para>An endpoint for <link linkend="rest-api-oauth2-client-admin-endpoint"
>OAuth 2.0 client administration</link>. This is specific to OpenAM.</para>
</listitem>
</itemizedlist>
<para>When accessing the APIs, browser-based REST clients can rely on OpenAM
to handle the session as usual. First authenticate with OpenAM. Then perform
the operations in the browser session.</para>
<para>Clients not running in a browser can authenticate as described in
<xref linkend="rest-api-auth" />, whereby OpenAM returns a
<literal>token.id</literal> value. Clients pass the
<literal>token.id</literal> value in a header named after the
authentication cookie, by default <literal>iplanetDirectoryPro</literal>.</para>
<section xml:id="rest-api-oauth2-client-endpoints">
<title>OAuth 2.0 Client &amp; Resource Server Endpoints</title>
<para>As described in the <citetitle>Administration Guide</citetitle> chapter
on <link xlink:href="admin-guide#chap-oauth2"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Managing OAuth
2.0 Authorization</citetitle></link>, OpenAM exposes REST endpoints for
making calls to OpenAM acting as an authorization server.</para>
<xinclude:include href="/shared/variablelist-oauth2-endpoints.xml" />
<para>The <literal>/oauth2/authorize</literal>, and
<literal>/oauth2/access_token</literal> endpoints function as described
in RFC 6749.</para>
<para>The <literal>/oauth2/authorize</literal> endpoint is protected by the
policy created during OAuth 2.0 authorization server configuration, which
grants all authenticated users access.</para>
<para>The <literal>/oauth2/tokeninfo</literal> endpoint takes an HTTP GET
on <literal>/oauth2/tokeninfo?access_token=<replaceable
>token-id</replaceable></literal>, and returns information about the
token.</para>
<para>Resource servers &#8212; or any party having the token ID &#8212; can
get token information through this endpoint without authenticating. This
means any application or user can validate the token without having to be
registered with OpenAM.</para>
<para>The following example shows OpenAM issuing an access token, and
then returning token information.</para>
<screen>$ curl
--request POST
--user "myClientID:password"
--data "grant_type=password&amp;username=demo&amp;password=changeit&amp;scope=cn%20mail"
https://openam.example.com:8443/openam/oauth2/access_token
{
"expires_in": 599,
"token_type": "Bearer",
"refresh_token": "f6dcf133-f00b-4943-a8d4-ee939fc1bf29",
"access_token": "f9063e26-3a29-41ec-86de-1d0d68aa85e9"
}
$ curl https://openam.example.com:8443/openam/oauth2/tokeninfo
?access_token=f9063e26-3a29-41ec-86de-1d0d68aa85e9
{
"mail": "demo@example.com",
"scope": [
"mail",
"cn"
],
"cn": "demo",
"realm": "/",
"token_type": "Bearer",
"expires_in": 577,
"access_token": "f9063e26-3a29-41ec-86de-1d0d68aa85e9"
}</screen>
<para>The resource server making decisions about whether the token is valid
can thus use the <literal>/oauth2/tokeninfo</literal> endpoint to retrieve
expiration information about the token. Depending on the scopes
implementation, the JSON response about the token can also contain scope
information. As described in the <citetitle>Administration Guide</citetitle>,
the default scopes implementation in OpenAM considers scopes to be names of
attributes in the resource owner's user profile. Notice that the JSON
response contains the values for those attributes from the user's profile,
as in the preceding example, with scopes set to <literal>mail</literal> and
<literal>cn</literal>.</para>
</section>
<section xml:id="rest-api-oauth2-token-admin-endpoint">
<title>OAuth 2.0 Token Administration Endpoint</title>
<para>The OpenAM-specific OAuth 2.0 token administration endpoint lets
administrators read, list, and delete OAuth 2.0 tokens. OAuth 2.0 clients
can also manage their own tokens.</para>
<para>Resource owners can manage OAuth 2.0 tokens that they authorized by
using the web-based OAuth 2 Token Manager. See the <citetitle>Administration
Guide</citetitle> section on <link
xlink:href="admin-guide#oauth2-manage-tokens"
xlink:role="http://docbook.org/xlink/role/olink"
><citetitle>Managing OAuth 2.0 Tokens</citetitle></link> for details.</para>
<para>OpenAM exposes the token administration endpoint at
<literal>/frrest/oauth2/token</literal>, such as
<literal>https://openam.example.com:8443/openam/frrest/oauth2/token</literal>.</para>
<note>
<para>This endpoint location is likely to change in the future.</para>
</note>
<para>To get a token, perform an HTTP GET on
<literal>/frrest/oauth2/token/<replaceable>token-id</replaceable></literal>,
as in the following example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate?
username=amadmin&amp;password=password"
token.id=AQIC5wM2LY4Sfcxs...EwNDU2NjE0*
$ curl
--request POST
--user "myClientID:password"
--data "grant_type=password&amp;username=demo&amp;password=changeit&amp;scope=cn%20mail"
https://openam.example.com:8443/openam/oauth2/access_token
{
"expires_in": 599,
"token_type": "Bearer",
"refresh_token": "f838e7d4-7e84-4743-af7c-9a9c42c2969e",
"access_token": "9c6a48fc-44b1-4a0c-b4f0-672fba468b0f"
}
$ curl
--header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*"
https://openam.example.com:8443/openam/frrest/oauth2/token/9c6a48fc...fba468b0f
{
"scope": [
"mail",
"cn"
],
"type": [
"access_token"
],
"username": [
"demo"
],
"realm": [
"/"
],
"id": [
"9c6a48fc-44b1-4a0c-b4f0-672fba468b0f"
],
"parent": [
"f838e7d4-7e84-4743-af7c-9a9c42c2969e"
],
"expiry_time": [
"1355741494888"
],
"client_id": [
"myClientID"
]
}</screen>
<para>To list tokens, perform an HTTP GET on
<literal>/frrest/oauth2/token/?_query_id=<replaceable>conditions</replaceable></literal>,
where <replaceable>conditions</replaceable> is a comma-separated list of
<literal><replaceable>field</replaceable>=<replaceable>value</replaceable></literal>
conditions. The <replaceable>field</replaceable>s are taken from the fields
returned in the token object through this endpoint.</para>
<variablelist>
<varlistentry>
<term><literal>"expiry_time"</literal></term>
<listitem>
<para>Token expiration time in milliseconds since 00:00:00 UTC, January 1,
1970.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"type"</literal></term>
<listitem>
<para>Either <literal>"access_token"</literal> or
<literal>"refresh_token"</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"username"</literal></term>
<listitem>
<para>OAuth 2.0 client to whom the token was issued.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"realm"</literal></term>
<listitem>
<para>The realm for which the token was issued.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"id"</literal></term>
<listitem>
<para>Unique ID of the token.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The following example shows a search for current access tokens that
were issued to <literal>myClientID</literal>.</para>
<screen>$ curl
--header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*"
https://openam.example.com:8443/openam/frrest/oauth2/token/?_queryID
=username%3DmyClientID%2Ctype%3Daccess_token
{
"result": [
{
"scope": [
"mail",
"cn"
],
"id": [
"1b836369-4fcf-4fb2-b819-ee4b1314d4f1"
],
"type": [
"access_token"
],
"username": [
"myClientID"
],
"realm": [
"/"
],
"expiry_time": [
"1355741986154"
]
},
{
"scope": [
"mail",
"cn"
],
"type": [
"access_token"
],
"username": [
"myClientID"
],
"realm": [
"/"
],
"id": [
"5f1763fc-37ae-4698-9e84-d301d49e1f7e"
],
"expiry_time": [
"1355741982091"
]
}
],
"pagedResultsCookie": null,
"remainingPagedResults": -1
}</screen>
<para>To delete a token, perform an HTTP DELETE on
<literal>/frrest/oauth2/token/<replaceable>token-id</replaceable></literal>,
as in the following example.</para>
<screen>$ curl
--request POST
--data "grant_type=client_credentials&amp;username=demo&amp;password=changeit
&amp;client_id=myClientID&amp;client_secret=password&amp;scope=cn%20mail"
https://openam.example.com:8443/openam/oauth2/access_token
{
"expires_in": 599,
"token_type": "Bearer",
"access_token": "867aaab2-61d7-4b78-9b80-4f9098034540"
}
$ curl
--request DELETE
--header "iplanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*"
https://openam.example.com:8443/openam/frrest/oauth2/token/867aaab2..098034540
{
"success": "true"
}</screen>
</section>
<section xml:id="rest-api-oauth2-client-admin-endpoint">
<title>OAuth 2.0 Client Administration Endpoint</title>
<para>The OAuth 2.0 administration endpoint lets OpenAM administrators and
agent administrators create (that is, register) and delete OAuth 2.0
clients.</para>
<para>OpenAM exposes this endpoint at <literal>/frrest/oauth2/client</literal>,
such as
<literal>https://openam.example.com:8443/openam/frrest/oauth2/client</literal>.</para>
<note>
<para>This endpoint location is likely to change in the future.</para>
</note>
<para>To create an OAuth 2.0 client, perform an HTTP POST to
<literal>/frrest/oauth2/client/?_action=create</literal>
with a JSON object fully specifying the client, as in the following
example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=amadmin&amp;password=password"
token.id=AQIC5wM...3MTYxOA..*
$ curl --request POST --header "iplanetDirectoryPro: AQIC5wM...3MTYxOA..*"
--header "Content-Type: application/json"
--data '{"client_id":["testClient"],
"realm":["/"]
"userpassword":["secret12"],
"com.forgerock.openam.oauth2provider.clientType":["Confidential"],
"com.forgerock.openam.oauth2provider.redirectionURIs":
["www.client.com","www.example.com"],
"com.forgerock.openam.oauth2provider.scopes":["cn","sn"],
"com.forgerock.openam.oauth2provider.defaultScopes":["cn"],
"com.forgerock.openam.oauth2provider.name":["My Test Client"],
"com.forgerock.openam.oauth2provider.description":["OAuth 2.0 Client"]
}'
http://openam.example.com:8080/openam/frrest/oauth2/client/?_action=create
{"success":"true"}</screen>
<variablelist>
<para>When creating an OAuth 2.0 client, use the following fields in your
JSON object.</para>
<varlistentry>
<term><literal>"client_id"</literal></term>
<listitem>
<para>(Required) This field takes an array containing the client
identifier as defined in RFC 6749.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"realm"</literal></term>
<listitem>
<para>(Required) This field takes an array containing the OpenAM realm
in which to create the client as defined in RFC 6749.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"userpassword"</literal></term>
<listitem>
<para>(Required) This field takes an array containing the client
secret as defined in RFC 6749.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.clientType"</literal></term>
<listitem>
<para>(Required) This field takes an array containing the client
type, either <literal>"Confidential"</literal> or
<literal>"Public"</literal> as defined in RFC 6749.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.redirectionURIs"</literal></term>
<listitem>
<para>(Optional for confidential clients) This field takes an array of
client redirection endpoints as defined in RFC 6749.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.scopes"</literal></term>
<listitem>
<para>(Optional) This field takes an array of scopes as defined in RFC
6749. The default scopes implementation takes scopes to be names of
attributes in the resource owner profile.</para>
<para>Specify localized scopes in <literal><replaceable
>scope</replaceable>|<replaceable>locale</replaceable>|<replaceable
>localized description</replaceable></literal> format.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.defaultScopes"</literal></term>
<listitem>
<para>(Optional) This field takes an array of default scopes set
automatically when tokens are issued.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.name"</literal></term>
<listitem>
<para>(Optional) This field takes an array containing the client name to
display to the resource owner when the resource owner must authorize
client access to protected resources.</para>
<para>Specify localized names in <literal><replaceable
>locale</replaceable>|<replaceable>localized name</replaceable></literal>
format.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"com.forgerock.openam.oauth2provider.description"</literal></term>
<listitem>
<para>(Optional) This field takes an array containing the description to
display to the resource owner when the resource owner must authorize
client access to protected resources.</para>
<para>Specify localized descriptions in <literal><replaceable
>locale</replaceable>|<replaceable>localized description</replaceable></literal>
format.</para>
</listitem>
</varlistentry>
</variablelist>
<para>To delete an OAuth 2.0 client, perform an HTTP DELETE on
<literal>/frrest/oauth2/client/<replaceable>client-id</replaceable></literal>,
as in the following example.</para>
<screen>$ curl --request DELETE
--header "iplanetDirectoryPro: AQIC5wM...3MTYxOA..*"
https://openam.example.com:8443/openam/frrest/oauth2/client/testClient
{"success":"true"}</screen>
</section>
</section>
<section xml:id="rest-api-logging">
<title>Logging</title>
<para>You can send OpenAM messages to log, specifying the message content
and the log file in which to write your message.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate?
username=amadmin
&amp;password=password"
token.id=AQIC5wM2LY4SfcwyCZkk-1JXzx6q1EzgagabHfBjMidb5jI.*AAJTSQACMDE.*
$ curl "https://openam.example.com:8443/openam/identity/log?
appid=AQIC5wM2LY4SfcwyCZkk-1JXzx6q1EzgagabHfBjMidb5jI.*AAJTSQACMDE.*
&amp;subjectid=AQIC5wM2LY4SfcxuxIP0VnP2lVjs7ypEM6VDx6srk56CN1Q.*AAJTSQACMDE.*
&amp;logname=rest.access
&amp;message=Hello%20World"</screen>
<para>Logging takes a valid <literal>appid</literal> token for the subject
with access to log the message, and also a <literal>subjectid</literal> token
for the user whom the message concerns. If the tokens are valid and the
access rights correct, your message ends up in the log specified.</para>
<screen>$ cat openam/openam/log/rest.access
#Version: 1.0
#Fields: time Data LoginID ContextID IPAddr LogLevel Domain
LoggedBy MessageID ModuleName NameID HostName
"2011-09-14 16:38:17" /home/mark/openam/openam/log/
"cn=dsameuser,ou=DSAME Users,o=openam" aa307b2dcb721d4201
"Not Available" INFO o=openam "cn=dsameuser,ou=DSAME Users,o=openam"
LOG-1 rest.access "Not Available"192.168.56.2
"2011-09-14 16:38:17" "Hello World" id=bjensen,ou=user,o=openam
8a4025a2b3af291d01 "Not Available" INFO o=openam
id=amadmin,ou=user,o=openam "Not Available" rest.access "Not Available"
192.168.56.2</screen>
</section>
<section xml:id="rest-api-crud">
<title>Identity Management</title>
<indexterm>
<primary>User data</primary>
<secondary>REST access</secondary>
</indexterm>
<para>This section shows how you create, read, update, and delete identities
using the RESTful APIs.</para>
<itemizedlist>
<para>OpenAM has two REST APIs for managing identities.</para>
<listitem>
<para>Under the <literal>/json/users</literal> endpoint, you find the
newer JSON-based API.</para>
<para>Examples in this section show authentication using the API described
in <xref linkend="rest-api-auth" />. For browser-based clients, you
can rely on OpenAM cookies rather than construct the header in your
application.</para>
<itemizedlist>
<para>The following sections cover this JSON-based API.</para>
<listitem><para><xref linkend="rest-api-create" /></para></listitem>
<listitem><para><xref linkend="rest-api-read" /></para></listitem>
<listitem><para><xref linkend="rest-api-update" /></para></listitem>
<listitem><para><xref linkend="rest-api-delete" /></para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>Under the <literal>/identity</literal> endpoint, you find the
backwards-compatible, legacy API.</para>
<itemizedlist>
<para>The following sections cover this backwards-compatible API.</para>
<listitem><para><xref linkend="rest-api-create-legacy" /></para></listitem>
<listitem><para><xref linkend="rest-api-read-legacy" /></para></listitem>
<listitem><para><xref linkend="rest-api-update-legacy" /></para></listitem>
<listitem><para><xref linkend="rest-api-delete-legacy" /></para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<section xml:id="rest-api-create">
<title>Creating Identities</title>
<para>OpenAM lets administrators create a user profile by making an HTTP
POST of the JSON representation of the profile to
<literal>/json/users/?_action=create</literal>, as shown in the following
example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=amadmin&amp;password=password"
token.id=AQIC5w...2NzEz*
$ curl --request POST --header "iplanetDirectoryPro: AQIC5w...2NzEz*"
--header "Content-Type: application/json"
--data '{ "name": "bjensen", "userpassword": "secret12",
"mail": "bjensen@example.com" }'
https://openam.example.com:8443/openam/json/users/?_action=create
{
"name": "bjensen",
"realm": "/",
"uid": [
"bjensen"
],
"mail": [
"bjensen@example.com"
],
"sn": [
"bjensen"
],
"userpassword": [
"{SSHA}0pXpKLPRKCGY7g3YqZygJmKMW6IC2BLJimmlwg=="
],
"cn": [
"bjensen"
],
"inetuserstatus": [
"Active"
],
"dn": [
"uid=bjensen,ou=people,dc=openam,dc=forgerock,dc=org"
],
"objectclass": [
"person",
"sunIdentityServerLibertyPPService",
"sunFederationManagerDataStore",
"inetorgperson",
"iPlanetPreferences",
"iplanet-am-auth-configuration-service",
"organizationalperson",
"sunFMSAML2NameIdentifier",
"inetuser",
"iplanet-am-managed-person",
"sunAMAuthAccountLockout",
"iplanet-am-user-service",
"top"
],
"universalid": [
"id=bjensen,ou=user,dc=openam,dc=forgerock,dc=org"
]
}</screen>
<para>Alternatively, administrators can create user profiles with specific
user IDs by doing an HTTP PUT of the JSON representation of the changes to
<literal>/json/users/<replaceable>user-id</replaceable></literal>, as
shown in the following example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=amadmin&amp;password=password"
token.id=AQIC5w...2NzEz*
$ curl --request PUT --header "iplanetDirectoryPro: AQIC5w...2NzEz*"
--header "Content-Type: application/json"
--data '{ "userpassword": "secret12", "mail": "bjensen@example.com" }'
https://openam.example.com:8443/openam/json/users/bjensen
{
"name": "bjensen",
"realm": "/",
"uid": [
"bjensen"
],
"mail": [
"bjensen@example.com"
],
"sn": [
"bjensen"
],
"userpassword": [
"{SSHA}e4DJoxvYVW/nsp62XJf29ZADE16YQgrxK+XuKA=="
],
"cn": [
"bjensen"
],
"inetuserstatus": [
"Active"
],
"dn": [
"uid=bjensen,ou=people,dc=openam,dc=forgerock,dc=org"
],
"objectclass": [
"person",
"sunIdentityServerLibertyPPService",
"sunFederationManagerDataStore",
"inetorgperson",
"iPlanetPreferences",
"iplanet-am-auth-configuration-service",
"organizationalperson",
"sunFMSAML2NameIdentifier",
"inetuser",
"iplanet-am-managed-person",
"sunAMAuthAccountLockout",
"iplanet-am-user-service",
"top"
],
"universalid": [
"id=bjensen,ou=user,dc=openam,dc=forgerock,dc=org"
]
}</screen>
<para>As shown in the examples, OpenAM returns the JSON representation of
the profile on successful creation. On failure, OpenAM returns a JSON
representation of the error including the
<link xlink:href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
xlink:show="new">HTTP status code</link>.</para>
</section>
<section xml:id="rest-api-read">
<title>Reading Identities</title>
<para>OpenAM lets users read their own profiles, and lets administrators read
other user's profiles by requesting an HTTP GET on
<literal>/json/users/<replaceable>user-id</replaceable></literal>, as shown
in the following example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=amadmin&amp;password=password"
token.id=AQIC5w...2NzEz*
$ curl --header "iplanetDirectoryPro: AQIC5w...2NzEz*"
https://openam.example.com:8443/openam/json/users/demo
{
"name": "demo",
"realm": "/",
"uid": [
"demo"
],
"sn": [
"demo"
],
"userpassword": [
"{SSHA}S14oR2gusLWtiDkAS4twj63slXNNaMKpwrOWdw=="
],
"cn": [
"demo"
],
"inetuserstatus": [
"Active"
],
"dn": [
"uid=demo,ou=people,dc=openam,dc=forgerock,dc=org"
],
"objectclass": [
"person",
"sunIdentityServerLibertyPPService",
"sunFederationManagerDataStore",
"inetorgperson",
"iPlanetPreferences",
"iplanet-am-auth-configuration-service",
"organizationalperson",
"sunFMSAML2NameIdentifier",
"inetuser",
"iplanet-am-managed-person",
"sunAMAuthAccountLockout",
"iplanet-am-user-service",
"top"
],
"universalid": [
"id=demo,ou=user,dc=openam,dc=forgerock,dc=org"
]
}</screen>
<para>As shown in the example, OpenAM returns the JSON representation of the
profile on success. On failure, OpenAM returns a JSON representation of the
error including the
<link xlink:href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
xlink:show="new">HTTP status code</link>.</para>
</section>
<section xml:id="rest-api-update">
<title>Updating Identities</title>
<para>OpenAM lets users update their own profiles, and lets administrators
update other user's profiles. To update an identity, do an HTTP PUT of the
JSON representation of the changes to
<literal>/json/users/<replaceable>user-id</replaceable></literal>.</para>
<para>The following example shows how users can update their own
profiles.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=demo&amp;password=changeit"
token.id=AQIC5...Y3MTAx*
$ curl --request PUT --header "iplanetDirectoryPro: AQIC5...Y3MTAx*"
--header "Content-Type: application/json"
--data '{ "mail": "demo@example.com" }'
https://openam.example.com:8443/openam/json/users/demo
{
"name": "demo",
"realm": "/",
"uid": [
"demo"
],
"mail": [
"demo@example.com"
],
"sn": [
"demo"
],
"userpassword": [
"{SSHA}S14oR2gusLWtiDkAS4twj63slXNNaMKpwrOWdw=="
],
"cn": [
"demo"
],
"inetuserstatus": [
"Active"
],
"dn": [
"uid=demo,ou=people,dc=openam,dc=forgerock,dc=org"
],
"objectclass": [
"person",
"sunIdentityServerLibertyPPService",
"sunFederationManagerDataStore",
"inetorgperson",
"iPlanetPreferences",
"iplanet-am-auth-configuration-service",
"organizationalperson",
"sunFMSAML2NameIdentifier",
"inetuser",
"iplanet-am-managed-person",
"sunAMAuthAccountLockout",
"iplanet-am-user-service",
"top"
],
"universalid": [
"id=demo,ou=user,dc=openam,dc=forgerock,dc=org"
]
}</screen>
<para>As shown in the example, OpenAM returns the JSON representation of the
profile on success. On failure, OpenAM returns a JSON representation of the
error including the
<link xlink:href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
xlink:show="new">HTTP status code</link>.</para>
</section>
<section xml:id="rest-api-delete">
<title>Deleting Identities</title>
<para>OpenAM lets administrators delete a user profile by making an HTTP
DELETE call to
<literal>/json/users/<replaceable>user-id</replaceable></literal>, as shown
in the following example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate
?username=amadmin&amp;password=password"
token.id=AQIC5w...2NzEz*
$ curl --request DELETE --header "iplanetDirectoryPro: AQIC5w...2NzEz*"
https://openam.example.com:8443/openam/json/users/bjensen
{"success":"true"}</screen>
<para>On success, OpenAM returns a JSON object indicating success. On
failure, OpenAM returns a JSON representation of the error including the
<link xlink:href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
xlink:show="new">HTTP status code</link>.</para>
</section>
<section xml:id="rest-api-create-legacy">
<title>Creating Identities (Legacy API)</title>
<para>OpenAM lets you create user profiles, and also create web and J2EE
policy agent profiles. When you create an entry, you must provide the
following parameters.</para>
<variablelist>
<varlistentry>
<term>admin</term>
<listitem>
<para>Valid token for the user with permissions to add the identity</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity_name</term>
<listitem>
<para>A unique name for the identity to create</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity_attribute_names</term>
<listitem>
<para>LDAP attribute names for attributes to create</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity_attribute_values_<replaceable>name</replaceable></term>
<listitem>
<para>LDAP attribute values for the identity to create. For example,
<literal>identity_attribute_names=sn&amp;identity_attribute_values_sn=Jensen</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity_realm</term>
<listitem>
<para>The realm in which to create the identity</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity_type</term>
<listitem>
<para>Either <literal>user</literal> or <literal>AgentOnly</literal></para>
</listitem>
</varlistentry>
</variablelist>
<screen>$ curl "https://openam.example.com:8443/openam/identity/authenticate?
username=amadmin
&amp;password=password"
token.id=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
$ curl "https://openam.example.com:8443/openam/identity/create?
admin=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
&amp;identity_name=testuser
&amp;identity_attribute_names=cn
&amp;identity_attribute_values_cn=Test%20User
&amp;identity_attribute_names=sn
&amp;identity_attribute_values_sn=User
&amp;identity_attribute_names=userpassword
&amp;identity_attribute_values_userpassword=secret12
&amp;identity_realm=%2F
&amp;identity_type=user"</screen>
</section>
<section xml:id="rest-api-read-legacy">
<title>Reading &amp; Searching for Identities (Legacy API)</title>
<para>Reading is similar to attribute retrieval, as described in
<xref linkend="rest-api-tokens" />, but obtained using the token of
a user with permissions to perform the search, as shown in the following
example.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/read?
admin=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
&amp;name=testuser
&amp;attributes_names=realm
&amp;attributes_values_realm=%2F"
identitydetails.name=testuser
identitydetails.type=user
identitydetails.realm=o=openam
identitydetails.attribute=
identitydetails.attribute.name=uid
identitydetails.attribute.value=testuser
identitydetails.attribute=
identitydetails.attribute.name=sn
identitydetails.attribute.value=User
identitydetails.attribute=
identitydetails.attribute.name=userpassword
identitydetails.attribute.value={SSHA}AzpT+N1sjrQhL1wfX2ETWh/Aqbd+lH9LOlhDqg==
identitydetails.attribute=
identitydetails.attribute.name=cn
identitydetails.attribute.value=Test User
identitydetails.attribute=
identitydetails.attribute.name=inetuserstatus
identitydetails.attribute.value=Active
identitydetails.attribute=
identitydetails.attribute.name=dn
identitydetails.attribute.value=uid=testuser,ou=people,dc=example,dc=com
identitydetails.attribute=
identitydetails.attribute.name=objectclass
identitydetails.attribute.value=person
identitydetails.attribute.value=sunIdentityServerLibertyPPService
identitydetails.attribute.value=inetorgperson
identitydetails.attribute.value=sunFederationManagerDataStore
identitydetails.attribute.value=iPlanetPreferences
identitydetails.attribute.value=iplanet-am-auth-configuration-service
identitydetails.attribute.value=organizationalperson
identitydetails.attribute.value=sunFMSAML2NameIdentifier
identitydetails.attribute.value=inetuser
identitydetails.attribute.value=iplanet-am-managed-person
identitydetails.attribute.value=iplanet-am-user-service
identitydetails.attribute.value=sunAMAuthAccountLockout
identitydetails.attribute.value=top
identitydetails.attribute=
identitydetails.attribute.name=universalid
identitydetails.attribute.value=id=testuser,ou=user,o=openam</screen>
<para>You can search for user IDs by providing the following
parameters.</para>
<variablelist>
<varlistentry>
<term>admin</term>
<listitem>
<para>Valid token for the user with access to perform the search</para>
</listitem>
</varlistentry>
<varlistentry>
<term>attributes_names</term>
<listitem>
<para>LDAP attribute names for attributes to search</para>
</listitem>
</varlistentry>
<varlistentry>
<term>attributes_values_<replaceable>name</replaceable></term>
<listitem>
<para>LDAP attribute values for the identity to search. For example,
<literal>attribute_names=sn&amp;attribute_values_sn=Jensen</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>filter</term>
<listitem>
<para>Additional LDAP filter component to limit the search results
returned</para>
</listitem>
</varlistentry>
</variablelist>
<screen>$ curl "https://openam.example.com:8443/openam/identity/search?
admin=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
&amp;attributes_names=sn
&amp;attributes_values_sn=Jensen
&amp;attributes_names=mail
&amp;attributes_values_mail=bjensen*
&amp;attributes_names=realm
&amp;attributes_values_realm=%2F"
string=bjensen</screen>
</section>
<section xml:id="rest-api-update-legacy">
<title>Updating Identities (Legacy API)</title>
<para>You can update an identity with the same parameters used to create
identities, provided the token corresponds to a user with access to
update the identity.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/update?
admin=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
&amp;identity_name=testuser
&amp;identity_attribute_names=mail
&amp;identity_attribute_values_mail=testuser%40example.com
&amp;identity_realm=%2F
&amp;identity_type=user"</screen>
</section>
<section xml:id="rest-api-delete-legacy">
<title>Deleting Identities (Legacy API)</title>
<para>You can also delete an identity.</para>
<screen>$ curl "https://openam.example.com:8443/openam/identity/delete?
admin=AQIC5wM2LY4SfcxSYA8eG-vrNHb_W7nG8XkfAGyRyuaebDY.*AAJTSQACMDE.*
&amp;identity_name=testuser
&amp;identity_realm=%2F
&amp;identity_type=user"</screen>
</section>
</section>
</chapter>