Secure Remote Access

Overview

CIS provides secure remote access to targeted remote systems. This allows Centrify users to access those systems without exposing the login password and without requiring a VPN connection to the corporate network on which the remote system lives. After the user logs out of the system, the password is automatically rotated for additional security.

These features improve security and reduce risks for share privileged accounts on remote systems.

This document demonstrates the API workflow for programatically discovering and accessing a remote Unix system.

Before continuing, ensure you are familiar with:

Step 1. Authenticate the User

Start the Authentication Process

Start the authentication process by invoking the /Security/StartAuthentication endpoint and passing in the ID of the tenant and the user name via the TenantId and User fields:

POST /Security/StartAuthentication

Formatted JSON Data
{  
   "TenantId":"aaa1234",
   "User":"[email protected]",
   "Version":"1.0",
   "AssociatedEntityType":"Portal",
   "AssociatedEntityName":"Portal",
   "ExtIdpAuthChallengeState":""
}

The response contains the session ID and challenge mechanisms:

{  
   "success":true,
   "Result":{  
      "ClientHints":{  
         "PersistDefault":false,
         "AllowForgotPassword":true,
         "AllowPersist":false
      },
      "TenantId":"aaa1234",
      "Summary":"NewPackage",
      "SessionId":"ueyV0v7H255Aj849o7dUT_WpWNwvlR9FqbYNoBtBY2A1",
      "Challenges":[  
         {  
            "Mechanisms":[  
               {  
                  "PromptSelectMech":"Password",
                  "Name":"UP",
                  "AnswerType":"Text",
                  "MechanismId":"GQqOSNCT50ihn1ovrOdP9oOiKeEIDsXh76sv1M8lGSo1",
                  "PromptMechChosen":"Enter Password"
               }
            ]
         }
      ],
      "Version":"1.0"
   },
   ...
}

Advance the Authentication

Invoke the /Security/AdvanceAuthentication endpoint for each security mechanism. In the following example, a password is being provided:

POST /Security/AdvanceAuthentication

{  
   "TenantId":"AAU0350",
   "SessionId":"ueyV0v7H255Aj849o7dUT_WpWNwvlR9FqbYNoBtBY2A1",
   "PersistentLogin":null,
   "MechanismId":"GQqOSNCT50ihn1ovrOdP9oOiKeEIDsXh76sv1M8lGSo1",
   "Answer":"mypassword",
   "Action":"Answer"
}

Once all of the security mechanisms have been satisfied, an authentication code will be returned in the Auth field for use in subsequent API calls:

{  
   "success":true,
   "Result":{  
      "EmailAddress":"[email protected]",
      "Auth":"CDC92...",
      "User":"[email protected]",
      "Summary":"LoginSuccess",
      "SystemID":"aaa1234",
      "CustomerID":"aaa1234",
      "PodFqdn":"support.my.centrify.com",
      "DisplayName":"John",
      "SourceDsType":"CDS",
      "UserId":"12341234-0f5c-4834-8894-bb9f749515f4",
      "UserDirectory":"CDS",
      "AuthLevel":"Normal"
   },
   ...
}

Step 2. Get the Resource Queries

The next step is to get the queries to use for finding the various resources to access. In the following example, ObjectType is set to Server to indicate that queries should be returned for finding various types of systems that can be accessed through CIS for your tenant:

POST /Collection/GetObjectCollectionsAndFilters

{  
   "ObjectType":"Server",
   "Args":{  
      "PageNumber":1,
      "PageSize":100000,
      "Limit":100000,
      "SortBy":"",
      "direction":"False",
      "Caching":-1
   }
}

The response contains SQL queries for various types of servers:

{  
   "success":true,
   "Result":{  
      "IsAggregate":false,
      "Count":11,
      "Columns":[  
         {  
            "Name":"ID",
            "IsHidden":false,
            "DDName":null,
            "Title":"ID",
            "DDTitle":null,
            "Description":null,
            "Type":12,
            "Format":null,
            "Width":25,
            "TableKey":null,
            "ForeignKey":null,
            "TableName":null
         },
         ...
      ],
      "FullCount":11,
      "Results":[  
         {  
            "Entities":[  
               {  
                  "Type":"Collection",
                  "Key":"@All Servers",
                  "IsForeignKey":false
               }
            ],
            "Row":{  
               "Rank":10,
               "CollectionType":"SqlDynamic",
               "Filters":"SELECT * FROM (Select Server.ID, Server.AgentVersion, Server.ComputerClass, Server.Description, Server.FQDN, Server.LastState, Server.HealthStatus, Server.IsFavorite, Server.IPAddress, Server.Joined, Server.OperatingSystem, Server.Name, Server.UserID, Server.SessionType, Server.Port, Server.ProxyUser, Server.AllowRemote, Server.DefaultCheckoutTime, Server.AllowMultipleCheckouts, Server.ProxyUserIsManaged, Server.ManagementMode, Server.ManagementPort, Server.JoinedBy, Server.PasswordProfileID, Server.JoinedDate, Server.AllowHealthCheck, Server.HealthCheckInterval, Server.AllowPasswordRotation, Server.MinimumPasswordAge, Server.PasswordRotateDuration, Server.AllowPasswordHistoryCleanUp, Server.PasswordHistoryCleanUpDuration, Server.ProxyCollectionList, Server.TimeZoneID,Server.LmiEnabled, Server.DiscoveredTime as ServerDiscoveredTime from Server ORDER BY Name COLLATE NOCASE)",
               "Name":"All Systems",
               "Description":"All Systems",
               "ID":"@All Servers",
               "ObjectType":"Server",
               "Builtin":true
            }
         },
         {  
            "Entities":[  
               {  
                  "Type":"Collection",
                  "Key":"@Unix Servers",
                  "IsForeignKey":false
               }
            ],
            "Row":{  
               "Rank":20,
               "CollectionType":"SqlDynamic",
               "Filters":"SELECT * FROM (Select Server.ID, Server.AgentVersion, Server.ComputerClass, Server.Description, Server.FQDN, Server.LastState, Server.HealthStatus, Server.IsFavorite, Server.IPAddress, Server.Joined, Server.OperatingSystem, Server.Name, Server.UserID, Server.SessionType, Server.Port, Server.ProxyUser, Server.AllowRemote, Server.DefaultCheckoutTime, Server.AllowMultipleCheckouts, Server.ProxyUserIsManaged, Server.ManagementMode, Server.ManagementPort, Server.JoinedBy, Server.PasswordProfileID, Server.JoinedDate, Server.AllowHealthCheck, Server.HealthCheckInterval, Server.AllowPasswordRotation, Server.MinimumPasswordAge, Server.PasswordRotateDuration, Server.AllowPasswordHistoryCleanUp, Server.PasswordHistoryCleanUpDuration, Server.ProxyCollectionList, Server.TimeZoneID,Server.LmiEnabled, Server.DiscoveredTime as ServerDiscoveredTime from Server ORDER BY Name COLLATE NOCASE) WHERE ComputerClass = \"Unix\"",
               "Name":"Unix Systems",
               "Description":"Unix Systems",
               "ID":"@Unix Servers",
               "ObjectType":"Server",
               "Builtin":true
            }
         },
         {  
            "Entities":[  
               {  
                  "Type":"Collection",
                  "Key":"@Windows Servers",
                  "IsForeignKey":false
               }
            ],
            "Row":{  
               "Rank":20,
               "CollectionType":"SqlDynamic",
               "Filters":"SELECT * FROM (Select Server.ID, Server.AgentVersion, Server.ComputerClass, Server.Description, Server.FQDN, Server.LastState, Server.HealthStatus, Server.IsFavorite, Server.IPAddress, Server.Joined, Server.OperatingSystem, Server.Name, Server.UserID, Server.SessionType, Server.Port, Server.ProxyUser, Server.AllowRemote, Server.DefaultCheckoutTime, Server.AllowMultipleCheckouts, Server.ProxyUserIsManaged, Server.ManagementMode, Server.ManagementPort, Server.JoinedBy, Server.PasswordProfileID, Server.JoinedDate, Server.AllowHealthCheck, Server.HealthCheckInterval, Server.AllowPasswordRotation, Server.MinimumPasswordAge, Server.PasswordRotateDuration, Server.AllowPasswordHistoryCleanUp, Server.PasswordHistoryCleanUpDuration, Server.ProxyCollectionList, Server.TimeZoneID,Server.LmiEnabled, Server.DiscoveredTime as ServerDiscoveredTime from Server ORDER BY Name COLLATE NOCASE) WHERE ComputerClass = \"Windows\"",
               "Name":"Windows Systems",
               "Description":"Windows Systems",
               "ID":"@Windows Servers",
               "ObjectType":"Server",
               "Builtin":true
            }
         }
         ...
      ],
      "ReturnID":""
   },
   "Message":null,
   "MessageID":null,
   "Exception":null,
   "ErrorID":null,
   "ErrorCode":null,
   "InnerExceptions":null
}

Step 3. Execute a Query to get the Remote Resources

Choose a query from the response in the previous call, using the various fields returned to determine the most appropriate query (e.g. use the Entities > Key field to identify the query for listing all servers).

Once a query has been identified, invoke the /RedRock/query endpoint and pass the query string via the Script field:

POST /RedRock/query

{  
   "Script":"SELECT * FROM (Select Server.ID, Server.AgentVersion, Server.ComputerClass, Server.Description, Server.FQDN, Server.LastState, Server.HealthStatus, Server.IsFavorite, Server.IPAddress, Server.Joined, Server.OperatingSystem, Server.Name, Server.UserID, Server.SessionType, Server.Port, Server.ProxyUser, Server.AllowRemote, Server.DefaultCheckoutTime, Server.AllowMultipleCheckouts, Server.ProxyUserIsManaged, Server.ManagementMode, Server.ManagementPort, Server.JoinedBy, Server.PasswordProfileID, Server.JoinedDate, Server.AllowHealthCheck, Server.HealthCheckInterval, Server.AllowPasswordRotation, Server.MinimumPasswordAge, Server.PasswordRotateDuration, Server.AllowPasswordHistoryCleanUp, Server.PasswordHistoryCleanUpDuration, Server.ProxyCollectionList, Server.TimeZoneID,Server.LmiEnabled, Server.DiscoveredTime as ServerDiscoveredTime from Server ORDER BY Name COLLATE NOCASE)",
   "Args":{  
      "PageNumber":1,
      "PageSize":100,
      "Limit":100000,
      "SortBy":"",
      "direction":"False",
      "Caching":-1
   }
}

The response contains the list of servers which satisfy the query:

{  
   "success":true,
   "Result":{  
      "IsAggregate":false,
      "Count":11,
      "Columns":[  
         {  
            "Name":"ID",
            "IsHidden":false,
            "DDName":"_ID",
            "Title":"ID",
            "DDTitle":"ID",
            "Description":"Row Identifier (primary key)",
            "Type":12,
            "Format":null,
            "Width":0,
            "TableKey":"Primary",
            "ForeignKey":null,
            "TableName":"Server"
         },
         ...
      ],
      "FullCount":11,
      "Results":[  
         {  
            "Entities":[  
               {  
                  "Type":"Server",
                  "Key":"abcdabcd-7461-4be6-982f-afb256770c3e",
                  "IsForeignKey":false
               }
            ],
            "Row":{  
               "ID":"abcdabcd-7461-4be6-982f-afb256770c3e",
               "AllowMultipleCheckouts":null,
               "DefaultCheckoutTime":null,
               "JoinedBy":null,
               "MinimumPasswordAge":null,
               "LmiEnabled":null,
               "ProxyUser":"",
               "UserID":null,
               "PasswordHistoryCleanUpDuration":null,
               "ManagementMode":null,
               "AllowHealthCheck":null,
               "JoinedDate":null,
               "Joined":null,
               "LastState":"OK",
               "SessionType":"Ssh",
               "PasswordProfileID":null,
               "ProxyUserIsManaged":null,
               "IPAddress":null,
               "PasswordRotateDuration":null,
               "ManagementPort":null,
               "AgentVersion":null,
               "Description":"",
               "ProxyCollectionList":null,
               "FQDN":"172.27.9.220",
               "Name":"csssup-ubuntu",
               "AllowRemote":null,
               "HealthCheckInterval":null,
               "ComputerClass":"Unix",
               "ServerDiscoveredTime":"\/Date(1516060925480)\/",
               "OperatingSystem":"Ubuntu",
               "AllowPasswordHistoryCleanUp":null,
               "Port":null,
               "HealthStatus":"OK",
               "AllowPasswordRotation":null,
               "IsFavorite":false,
               "TimeZoneID":null
            }
         },
         ...
      ],
      "ReturnID":""
   },
   "Message":null,
   "MessageID":null,
   "Exception":null,
   "ErrorID":null,
   "ErrorCode":null,
   "InnerExceptions":null
}

Step 4. Get Effective Row Rights

Identify the server in the response from the previous request for which a remote access session is to be started.

Using the Key value which identifies that server, invoke the /Acl/GetEffectiveRowRights endpoint to get a grant string, and pass the server identity via the 'RowKey' field:

POST Acl/GetEffectiveRowRights

{  
   "Rows":[  
      {  
         "Table":"Server",
         "RowKey":"abcdabcd-7461-4be6-982f-afb256770c3e",
         "ReduceSysadmin":true
      }
   ]
}

The results contains a grant string for the server:

{  
   "success":true,
   "Result":[  
      {  
         "GrantStr":"0000000000000000000000000000000000000000000000110000000011111111",
         "RowKey":"abcdabcd-7461-4be6-982f-afb256770c3e",
         "Table":"Server"
      }
   ],
   "Message":null,
   "MessageID":null,
   "Exception":null,
   "ErrorID":null,
   "ErrorCode":null,
   "InnerExceptions":null
}

Step 5. Get the Login Accounts

The next step is to get the login accounts for the system by invoking the /ServerManage/GetAccountsForLogin endpoint and passing the server ID via the host field:

POST /ServerManage/GetAccountsForLogin

{  
   "domainOnly":"false",
   "filter":"",
   "host":"abcdabcd-7461-4be6-982f-afb256770c3e",
   "Args":{  
      "PageNumber":1,
      "PageSize":100000,
      "Limit":100000,
      "SortBy":"",
      "direction":"False",
      "Caching":-1
   }
}

The result contains information for each of the accounts on that system:

{  
   "success":true,
   "Result":[  
      {  
         "accountId":"tyuityui-9fe3-4f2a-8924-0ca3b0f6de0b",
         "name":"[email protected]",
         "authority":"resource.centrify.com",
         "authorityType":"AD",
         "requestRequired":false
      },
      {  
         "accountId":"dddddddd-1d1d-473b-9ca4-cbc2d53b6061",
         "name":"root",
         "authority":"csssup-ubuntu",
         "authorityType":"Local",
         "requestRequired":false
      }
   ],
   "Message":null,
   "MessageID":null,
   "Exception":null,
   "ErrorID":null,
   "ErrorCode":null,
   "InnerExceptions":null
}

Try the API in Postman:
Try the API in Postman.
Click here for help with using our sample Postman collection.

Step 6. Get the Server Session

Now that the ID of the system and login account have been acquired, the next step is to acquire the HTML code necessary to start session and display a browser window so the user can access the remote system.

Invoke the /serversession/jumpterm endpoint setting the mode parameter to 1. Pass the account ID via the pvacct query parameter and the system ID via the host query parameter:

GET /serversession/jumpterm?mode=1&pvacct=dddddddd-1d1d-473b-9ca4-cbc2d53b6061&hostname=csssup-ubuntu&height=480&width=640&debug=false&token=&host=abcdabcd-7461-4be6-982f-afb256770c3e&colrows=&title=Login%20session%20csssup-ubuntu

The response contains the HTML indicating how to render the remote terminal window

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
X-CFY-TX-PN: Pod9
X-CFY-TX-ID: 5da94240bbc84fcf8056175b532f634c
X-CFY-TX-DT: Mi8xMi8yMDE4IDU6MTk6MjUgUE0_
X-Frame-Options: SAMEORIGIN
P3P: CP="NON COR ADMa CURa DEVa OUR IND COM UNI NAV INT PRE LOC ONL PHY STA ONL"
X-CFY-TX-TM: 157
Set-Cookie: antixss=k7fkHgxR28e_LmPvaWG4Fg__-HWPt3M1f5gWW3BT7bxuDag__-dImPD1A3pR_0xIXnkZ21Tw__-WrUho88cTg_DtvESULbtgA__-LS971c84V3ycyD4qIcxHeQ__-bPcBoJBIzWH3zMb54gPmBA__-n6WNZMK9lcgEq6K_R_Z22w__-ilI45jB0S4IdTwakrYuf7w__; path=/; secure
Set-Cookie: sessdata=L3dVSF...; path=/; secure; HttpOnly
Set-Cookie: podloc=eyJkZXZkb2cuY...; domain=centrify.com; expires=Fri, 31-Dec-9999 23:59:59 GMT; path=/; secure
Set-Cookie: userdata=eyJEYXR...; expires=Wed, 14-Mar-2018 17:19:25 GMT; path=/; secure
X-Robots-Tag: noindex, nofollow
Date: Mon, 12 Feb 2018 17:19:25 GMT
Content-Length: 4346


<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=8,9,10" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <link rel="shortcut icon"/>

            <link rel="stylesheet" type="text/css" href="/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/centrify-all_01.css?_ver=1518281911"/>
            <link rel="stylesheet" type="text/css" href="/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/centrify-all_02.css?_ver=1518281911"/>
            <link rel="stylesheet" type="text/css" href="/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/centrify-all_03.css?_ver=1518281911"/>

        <style>
            .x-viewport body{
                overflow: hidden !important;
                background-color: #000;
            }
        </style>

        <script src="/vfslow/lib/ui/jsutil/resources/locale/en.js?_ver=1518281911"></script>
            <script src="/vfslow/lib/ui/jsutil/resources/locale/en.js?_ver=1518281911"></script>
        <link href='/vfslow/lib/ui/../uibuild/compiled/jsutil/production/resources/fonts/Roboto.css?_ver=1518281911' rel='stylesheet' type='text/css'>
        <link href='/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/fonts/Icon-Set.css?_ver=1518281911' rel='stylesheet' type='text/css'>
        <script type="text/javascript">
            var ServerConfig = {
                ResourceBase: "/vfslow/lib/ui/",
                ExtLocation: "/vfslow/lib/ui//ext/src",
                DisableCacheSetting: false,
                LoadBase: "/vfslow/lib/ui/",
                Version: "1518281911",
                AppBase:"1518281911",
                SkinDef:  {"themeColor":"#363a40","theme":"centrify","adminRegisTxtCSSCls":"","cssDirectory":"compiled/centrify/production/resources","emailImage":"/logos/logo-centrify-1.png","footer":{"termsUrl":"https://www.centrify.com/eula/","termsText":"footer_term","privacyText":"footer_policy","copyrightText":"&copy; 2004-{0} Centrify Corporation.","privacyUrl":"https://www.centrify.com/privacypolicy.asp"},"navigationColor":"#979797","loginCssDirectory":"compiled/jsutil/production/resources","backgroundColor":"#FFFFFF","newHelpRoot":"{helpRootServer}/","pageIcon":"/logos/centrify-16-1.png","proxy":{"download64Bit":"Cloud-Management-Suite-win64.zip"},"helpDirectoryBrandName":"","mfa":{"waitGif":"/ellipses_anim.gif","stepsFolder":"/steps/"},"loginImage":"/logos/centrify-breach-stops-here.png","macEnrollDialogImage":"/enroll/centrify-macs.png","brand":"centrify","helpRoot":"{helpRootServer}/{1}/centrify/{2}/index.html","name":"Centrify","portalImage":"/logos/centrify-main-logo.png","aboutWindowIcon":"/logos/centrify-main-logo.png"},
                droppedPacketThreshold: 25,
                droppedPacketThresholdTime: 120,
                heartBeatTime: 5,
                useFastForwardOnDrop: true,
                continueOnDropped: true,
                sendFailureCountLimit: 200,
                challengeSessionId: "LHUUVpHKsU-8vxxJzcVGNUiuhdNmw4DIKEWfGmW475w1",
                MissingBuildFilesFail: false,
                signalRTransport: "auto",
                ManDef: {}
            };

            window.Jsutil = window.Jsutil || {};
            //Do not show login automatically when we utilize jsutil.
            Jsutil.bypassLogin = true;
        </script>
        <script src="/vfslow/lib/ui/jsutil/external/term.js?_ver=1518281911"></script>
        <script src="/vfslow/lib/ui/../uibuild/compiled/jsutil/production/app.js?_ver=1518281911"></script>
        <style type="text/css">
            html {
                height: 100%;
            }

            body {
                height:100%;
                font-size: 12px;
                background: black;
            }

            .no-script-alert {
                background: #fff;
                text-align: left;
                padding: 10px 20px 10px 45px;
                border-top: 2px solid #ffd324;
                border-bottom: 2px solid #ffd324;
            }

        </style>
    <script type="text/javascript" src="/vfslow/lib/ui/terminals/ssh.js?_ver=1518281911"></script>
</head>
<body>
</body>
</html>

Step 7. Negotiate an SSH session

Negotiate an SSH session terminal by invoking the /signalr/negotiate endpoint:

GET /signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22sshtermhub%22%7D%5D&_=1518455965170 HTTP/1.1

The response contains information about the connection including a unique ConnectionToken for use in subsequent API calls:

{  
   "Url":"/signalr",
   "ConnectionToken":"VYIL...",
   "ConnectionId":"deea698f-2d47-4bb8-9301-8adabac6bbb1",
   "KeepAliveTimeout":20.0,
   "DisconnectTimeout":30.0,
   "ConnectionTimeout":110.0,
   "TryWebSockets":true,
   "ProtocolVersion":"1.5",
   "TransportConnectTimeout":5.0,
   "LongPollDelay":0.0
}

Step 8. Connect to the SSH Session

Connect to the remote SSH session by invoking the /signalr/connect endpoint and pass the token returned from the /signalr/negotiate endpoint via the ConnectionToken query parameter:

GET /signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=VYIL...&connectionData=%5B%7B%22name%22%3A%22sshtermhub%22%7D%5D&tid=6 HTTP/1.1

The response contains information about the connection including the number of bytes sent and received:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Server: Microsoft-IIS/10.0
X-Content-Type-Options: nosniff
Sec-WebSocket-Accept: J9RUnHzBXXnP29a2L5E2tmVxkoA=
Connection: Upgrade
X-Robots-Tag: noindex, nofollow
Date: Mon, 12 Feb 2018 17:19:25 GMT
EndTime: 09:19:53.134
ReceivedBytes: 622
SentBytes: 201

Step 9. Start the SSH Session

Start the SSH session by invoking the /signalr/start endpoint and pass the token returned from the /signalr/negotiate endpoint via the ConnectionToken query parameter:

GET /signalr/start?transport=webSockets&clientProtocol=1.5&connectionToken=VYIL...&connectionData=%5B%7B%22name%22%3A%22sshtermhub%22%7D%5D&_=1518455965171 HTTP/1.1

The response indicates that the session was started:

{  
   "Response":"started"
}