Signing in to the API if single sign-on is enabled

If single sign-on (SSO) has been enabled, you must issue a series of API requests to obtain an authentication token from AD FS that is valid for the Grid Management API or the Tenant Management API.

Before you begin

  • You know the SSO username and password for a federated user who belongs to a StorageGRID user group.
  • If you want to access the Tenant Management API, you know the tenant account ID.

About this task

This is only a sample workflow that does not protect the password from being seen by other users.

This workflow might time out if you perform it too slowly. You might see the error: A valid SubjectConfirmation was not found on this Response.

If you have a URL-encoding issue, you might see the error: Unsupported SAML version.

Steps

  1. Declare the variables needed to sign in.
    export SAMLUSER='my-sso-username'
    export SAMLPASSWORD='my-password'
    export SAMLDOMAIN='my-domain'
    export TENANTACCOUNTID=’12345’
    export STORAGEGRID_ADDRESS='storagegrid.example.com'
    export AD_FS_ADDRESS='adfs.example.com'
    Note: To access the Grid Management API, use 0 as TENANTACCOUNTID.
  2. To receive a signed authentication URL, issue a POST request to /api/v3/authorize-saml, and remove the additional JSON encoding from the response.
    This example shows a POST request for a signed authentication URL for TENANTACCOUNTID. The results will be passed to python -m json.tool to remove the JSON encoding.
    curl -X POST "https://$STORAGEGRID_ADDRESS/api/v3/authorize-saml" \
      -H "accept: application/json" -H  "Content-Type: application/json" \
      --data "{\"accountId\": \"$TENANTACCOUNTID\"}" | python -m json.tool
    The response for this example includes a signed URL that is URL-encoded, but it does not include the additional JSON-encoding layer.
    {
        "apiVersion": "3.0",
        "data": "https://adfs.example.com/adfs/ls/?SAMLRequest=fZHLbsIwEEV%2FJTuv7...sSl%2BfQ33cvfwA%3D&RelayState=12345",
        "responseTime": "2018-11-06T16:30:23.355Z",
        "status": "success"
    }
  3. Save the SAMLRequest from the response for use in subsequent commands.
    export SAMLREQUEST='fZHLbsIwEEV%2FJTuv7...sSl%2BfQ33cvfwA%3D'
  4. Get a full URL that includes the client request ID from AD FS.
    One option is to request the login form using the URL from the previous response.
    curl "https://$AD_FS_ADDRESS/adfs/ls/?SAMLRequest=$SAMLREQUEST&RelayState=$TENANTACCOUNTID" | grep 'form method="post" id="loginForm"'
    The response includes the client request ID:
    <form method="post" id="loginForm" autocomplete="off" novalidate="novalidate" onKeyPress="if (event && event.keyCode == 13) Login.submitLoginRequest();" action="/adfs/ls/?
    SAMLRequest=fZHRToMwFIZfhb...UJikvo77sXPw%3D%3D&RelayState=12345&client-request-id=00000000-0000-0000-ee02-0080000000de" >
    
    
  5. Save the client request ID from the response.
    export SAMLREQUESTID='00000000-0000-0000-ee02-0080000000de'
  6. Send your credentials to the form action from the previous response.
    curl -X POST "https://$AD_FS_ADDRESS/adfs/ls/?SAMLRequest=$SAMLREQUEST&RelayState=$TENANTACCOUNTID&client-request-id=$SAMLREQUESTID" \
      --data "UserName=$SAMLUSER@$SAMLDOMAIN&Password=$SAMLPASSWORD&AuthMethod=FormsAuthentication" --include
    

    AD FS returns a 302 redirect, with additional information in the headers.

    Note: If multi-factor authentication (MFA) is enabled for your SSO system, the form post will also contain the second password or other credentials.
    HTTP/1.1 302 Found
    Content-Length: 0
    Content-Type: text/html; charset=utf-8
    Location: https://adfs.example.com/adfs/ls/?SAMLRequest=fZHRToMwFIZfhb...UJikvo77sXPw%3D%3D&RelayState=12345&client-request-id=00000000-0000-0000-ee02-0080000000de
    Set-Cookie: MSISAuth=AAEAADAvsHpXk6ApV...pmP0aEiNtJvWY=; path=/adfs; HttpOnly; Secure
    Date: Tue, 06 Nov 2018 16:55:05 GMT
    
  7. Save the MSISAuth cookie from the response.
    export MSISAuth='AAEAADAvsHpXk6ApV...pmP0aEiNtJvWY='
  8. Send a GET request to the specified location with the cookies from the authentication POST.
    curl "https://$AD_FS_ADDRESS/adfs/ls/?SAMLRequest=$SAMLREQUEST&RelayState=$TENANTACCOUNTID&client-request-id=$SAMLREQUESTID" \
      --cookie "MSISAuth=$MSISAuth" --include
    
    The response headers will contain AD FS session information for later logout usage, and the response body contains the SAMLResponse in a hidden form field.
    HTTP/1.1 200 OK
    Cache-Control: no-cache,no-store
    Pragma: no-cache
    Content-Length: 5665
    Content-Type: text/html; charset=utf-8
    Expires: -1
    Server: Microsoft-HTTPAPI/2.0
    P3P: ADFS doesn't have P3P policy, please contact your site's admin for more details
    Set-Cookie: SamlSession=a3dpbnRlcnMtUHJpbWFyeS1BZG1pbi0xNzgmRmFsc2Umcng4NnJDZmFKVXFxVWx3bkl1MnFuUSUzZCUzZCYmJiYmXzE3MjAyZTA5LThmMDgtNDRkZC04Yzg5LTQ3NDUxYzA3ZjkzYw==; path=/adfs; HttpOnly; Secure
    Set-Cookie: MSISAuthenticated=MTEvNy8yMDE4IDQ6MzI6NTkgUE0=; path=/adfs; HttpOnly; Secure
    Set-Cookie: MSISLoopDetectionCookie=MjAxOC0xMS0wNzoxNjozMjo1OVpcMQ==; path=/adfs; HttpOnly; Secure
    Date: Wed, 07 Nov 2018 16:32:59 GMT
    
    <form method="POST" name="hiddenform" action="https://storagegrid.example.com:443/api/saml-response">
      <input type="hidden" name="SAMLResponse" value="PHNhbWxwOlJlc3BvbnN...1scDpSZXNwb25zZT4=" /><input type="hidden" name="RelayState" value="12345" />
  9. Save the SAMLResponse from the hidden field:
    export SAMLResponse='PHNhbWxwOlJlc3BvbnN...1scDpSZXNwb25zZT4='
  10. Using the saved SAMLResponse, make a StorageGRID /api/saml-response request to generate a StorageGRID authentication token.
    For RelayState, use the tenant account ID or use 0 if you want to sign in to the Grid Management API.
    curl -X POST "https://$STORAGEGRID_ADDRESS:443/api/saml-response" \
      -H "accept: application/json" \
      --data-urlencode "SAMLResponse=$SAMLResponse" \
      --data-urlencode "RelayState=$TENANTACCOUNTID" \
      | python -m json.tool
    
    The response includes the authentication token.
    {
        "apiVersion": "3.0",
        "data": "56eb07bf-21f6-40b7-af0b-5c6cacfb25e7",
        "responseTime": "2018-11-07T21:32:53.486Z",
        "status": "success"
    }
  11. Save the authentication token in the response as MYTOKEN.
    export MYTOKEN=56eb07bf-21f6-40b7-af0b-5c6cacfb25e7"
    You can now use MYTOKEN for other requests, similar to how you would use the API if SSO was not being used.