Cybersecurity
DevOps Cloud (ADM)
IT Operations Cloud
In this article I'll demontrate how to use the curl and jq utilities in a bash command line to interact with Identity Applications via its REST API. The Identity Applications use the OAuth2 protocol for authentication and authorization. So before we can work with the Identity Apps, we first get an access token from OSP.
While curl is installed even if you select a minimal Linux distribution, jq packages are an add-on and available from extra modules:
In the OAuth terminology curl (and bash) are a client. We assume you are running on a secure server or workstation with restricted access to the client credentials. Thus we have a confidential client.
The easiest way to register a new OAuth client with OSP (our Authorization Server) is to edit the ism-configuration.properties
file by hand and add the following three properties:
com.netiq.playgound.clientID = playgound
com.netiq.playgound.clientPass = secret
com.netiq.playgound.redirect.url = https://webapp.example.com/oauth.html
Choose a clientID
(playgound)
of your liking and adjust the property names accordingly. redirect.url
is not relevant for scripts using the resource owner password credentials grant.
Instead of using a plain text client secret, you should generate an obfuscated clientPass value with:
java -jar /opt/netiq/idm/apps/tomcat/lib/obscurity-*jar "secret"
Restart OSP.
In addition to an OAuth client, you also need a user in the identity vault. We will be using the Resource Owner Password Credentials Grant, so you need the user's username and its password. Some methods require the user to have administrative privileges.
You need to know your OAuth2 issuer URL. For OSP installed with NetIQ Identity Manager this defaults to https://idmapps.example.com:8543/osp/a/idm/auth/oauth2
. From this you can retrieve the OAuth2/OpenID endpoints with:
export BASE_URL="https://idmapps.example.com:8543"
export OAUTH2_ISSUER="${BASE_URL}/osp/a/idm/auth/oauth2"
curl -fsS "$OAUTH2_ISSUER/.well-known/openid-configuration" \
| jq . \
| tee openid-configuration.json
export AUTHORIZATION_ENDPOINT="$(jq -r .authorization_endpoint openid-configuration.json)"
export TOKEN_ENDPOINT="$(jq -r .token_endpoint openid-configuration.json)"
export USERINFO_ENDPOINT="$(jq -r .userinfo_endpoint openid-configuration.json)"
export REVOCATION_ENDPOINT="$(jq -r .revocation_endpoint openid-configuration.json)"
export INTROSPECTION_ENDPOINT="$(jq -r .introspection_endpoint openid-configuration.json)"
export CLIENT_ID="playground"
read -sp "password for client $CLIENT_ID: " CLIENT_PASSWORD && echo && export CLIENT_PASSWORD
export USERNAME="uaadmin"
read -sp "password for user $USERNAME: " PASSWORD && echo && export PASSWORD
Get tokens and store them in token.json
.
curl -fsS \
--request POST \
--url $TOKEN_ENDPOINT \
--user "$CLIENT_ID:$CLIENT_PASSWORD" \
--data "grant_type=password" \
--data "username=$USERNAME" \
--data "password=$PASSWORD" \
-o token.json # login
By deafult, OSP access tokens expire after 60 seconds. To get a new access token and store it in access_token.json
(to avoid overwriting your refresh token) use:
curl -fsS \
--request POST \
--url $TOKEN_ENDPOINT \
--user "$CLIENT_ID:$CLIENT_PASSWORD" \
--data "grant_type=refresh_token" \
--data "refresh_token=$(jq -r .refresh_token token.json)" \
| jq '.exp = (now .expires_in | floor) | .exp_date = (.exp | todate)' \
> access_token.json # refresh access token
The 2nd jq command adds two expiration timestamp properties: exp
and exp_date
:
{
"access_token": "eH8AIIWvy8yaZFDx6PJqpgJIkrNxoq_M3gVQfcpzAwnOM9rBpm-EyvsZmVh0i-AOMaM3rf8CF-g9rpEv7rXQx1Ev1kRLVqor6kY8zMDywtM3EiSwxFi-t50YAvYKxSoBuBg2ZUBp2wEb4k48MqLowJF93ko8i-hNVIXOZIh1wvFmEL4DR1VEZWIAKj6krq8v8WlHUETxnMUrhAMBxsPHHoCit_TXwehRM5vPaUxhpK-L_SpAd89tCAJjd0MN_PGmd0qbK_TepJkc7LL3G8S8lO_ENeV8lejz9PK3tEtgIlWGg-PI",
"token_type": "Bearer",
"expires_in": 60,
"exp": 1598006322,
"exp_date": "2020-08-21T10:38:42Z"
}
Introspect access token:
curl -fsS \
--request POST \
--url $INTROSPECTION_ENDPOINT \
--user "$CLIENT_ID:$CLIENT_PASSWORD" \
--data "token=$(jq -r .access_token access_token.json)" \
| jq . # check access token
Introspect refresh token and use jq to calculate its remaining life time in a human readable format:
curl -fsS \
--request POST \
--url $INTROSPECTION_ENDPOINT \
--user "$CLIENT_ID:$CLIENT_PASSWORD" \
--data "token=$(jq -r .refresh_token token.json)" \
| jq 'if .exp
then
.exp_date = (.exp | todate) # expiration date in ISO 8601 format
| .exp_duration = ((.exp - now ) | floor) # remaining lifetime in seconds
| .remaining = "\(.exp_duration / 86400 | floor)d \(.exp_duration / 3600 % 24 | floor)h \(.exp_duration / 60 % 60 | floor)m \(.exp_duration % 60 | floor)s"
else
.exp_duration = 0
end' # check refresh token
curl -fsS \
--url "$USERINFO_ENDPOINT" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
--header "accept: application/json" \
| jq .
curl -fsS \
--url "$BASE_URL/IDMProv/rest/access/info/version" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq .
curl -fsS \
--url "$BASE_URL/IDMProv/rest/admin/driverstatus/info" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq .
curl -fsS \
--url "$BASE_URL/IDMProv/rest/admin/logging/list" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq .
curl -fsS \
--url "$BASE_URL/IDMProv/rest/access/statistics/memoryinfo" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq .
curl -fsS \
--url "$BASE_URL/IDMProv/rest/access/statistics/threadinfo" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq .
curl -fsS \
--request DELETE \
--url "$BASE_URL/IDMProv/rest/admin/cache/holder/items?cacheHolderID=All Cache" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq . # flush all caches
See REST API documentation for all available methods.
curl -fsS \
--request DELETE \
--url "$BASE_URL/IDMDCS-CORE/rpt/collectors/data" \
--header "authorization: $(jq -r '.token_type " " .access_token' access_token.json)" \
| jq . # purge reporting db
Every login generates a new refresh token. These are stored in the oidpInstanceData
attribute on the user object. This space is limited. You therefore must revoke your refresh token once you're done. Otherwise the user might fail to login again after some time.
curl -fsS \
--request POST \
--url $REVOCATION_ENDPOINT \
--user "$CLIENT_ID:$CLIENT_PASSWORD" \
--data "token_type_hint=refresh_token" \
--data "token=$(jq -r .refresh_token token.json)" # logout
Top Comments