04-22-2020 07:44 AM - edited 04-22-2020 01:54 PM
Imagine sitting in an interview room with a bunch of techies, firing questions at you, assessing you, sizing you up and you walking in with confidence and trepidation knowing fully well you really want the job but also that you are really good at what you do, but somehow things are not going quite well as you would want or envisage and then in the midst of all the pandemonium and barrage of questions, you hear these words: "Do you know how OAuth works"??
And you bet, my ears felt like ( did I just hear that) and in my head I am like "O what?"
If you want to know the result of that interview you would have to stay with me till the very end...But for now lets get into the matter of OAuth.
OAuth is simply an Authorization protocol defined by RFC 6749. OAuth allows an end user ( like me) to authorize an application (like Jabber) to gain access to a third party service ( like CUCM) without sharing their credentials with the application.
OAuth is becoming the defacto authorization protocol within UC collaboration solutions and vendors like Cisco and Microsoft have deployed it within their solution stacks. Some UC solutions deploying or requiring OAuth are
OAuth is an authorization framework specification that comprises of different components. The diagram below gives the components used within the Cisco Oauth deployment.
The diagram below shows the Oauth architecture used within CUCM and the interactions between the end user and various components in the Oauth deployment
CUCM uses tokens to authorize access to resources once user has been successfully authenticated. Depending on the CUCM version and the Oauth grant flow model used, CUCM uses either
The process of Authentication involves a user confirming their identity and approving what information can be accessed. Once the user has been successfully authenticated, access token is issued to the 3rd party using OAuth by the authorization server. Cisco implementation offers two tokens that will be issued for authorizing access to resources
OAuth supports multiple grant flows however CUCM deployment supports the following:
CUCM Version | OAuth Flow model | Authentication method | Tokens issued |
10.5 <= cucm-version < 11.5.1(SU3) | Implicit Flow | SAML SSO only | access token |
>= 11.5.1(SU3) | Authorization code grant flow | Local user, LDAP and SAML SSO | access token, refresh token |
CUCM OAuth server generates a set of encryption and signing keys used for signing and encrypting OAuth tokens. These keys are automatically distributed within Unified CM clusters to call control and IM and presence nodes. Unity connection and Expressway-C servers are also able to fetch encryption and signing keys using a REST API.
The signing/encryption key set is used to validate/decrypt tokens presented by jabber clients when authorization to a resource is requested
OAuth provides several benefits to both end users and UC administrators. Some of these benefits are highlighted below:
The recommended and supported versions for OAuth are shown below:
To enable OAuth perform the following procedure
1. Go to Cisco Unified Communications Manager Admin > System > Enterprise Parameters > SSO and OAuth Configuration and
"Select OAuth with Refresh Login Flow" set Enable support OAuth feature. ( adjust timers if desired)
NB: There is no configuration change required on IM&P nodes. CUCM will automatically push this settings to all the IM&P nodes in the cluster.
There is an exception to this and that is when centralized IM&P cluster is deployed. Additional configuration is required on the IM&P cluster to fetch the OAuth token keys from the CUCM clusters
Two steps are required to enable unity connection for OAuth:
To obtain the signing and encryption keys Unity must be configured with the Unified CM host details and a user account enabled for Unified CM AXL access
Go to AuthZ Servers > Add New
Now that the theory is explained and understood we now take a deep dive into the inner workings of OAuth in MRA deployment.
The selected trace analysis was taking while troubleshooting an issue with OAuth login flow and I thought it might provide an excellent source of learning. Sit tight, here we go....
++ Summary of Issue ++
After enabling OAuth on CUCM and Expressway-C, users attempted to login, got the CUCM browser page ( shown in step 4 of the architecture diagram), entered in user credentials but got "unable to communicate with server"
For all who are familiar with the Jabber MRA call flow, the first request that jabber sends ( after _collabe-edge SRV lookup) used to be "get_edge_config" However to support OAuth flow, the first request that jabber sends now is
"get_edge_sso"
The next few lines we will detail the requests and responses used in OAuth flow with Jabber
Request-sequence |
Request Sent |
{1: get_edge_sso} |
GET https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/get_edge_sso?email=aokanlawon@lab.com |
++ Expressway-E receives the request ++ 2020-03-24T16:31:00.962-06:00 labucexpye01 traffic_server[16087]: UTCTime="2020-03-24 22:31:00,962" Module="network.http.trafficserver" Level="INFO": Detail="Receive Request" Txn-id="2004" Src-ip="81.157.160.37" Src-port="59252" Msg="GET https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/get_edge_sso?email=aokanlawon@lab.com HTTP/1.1"
++ Expwe-responds with 200 OK With Token-reuse set to True ( NB: Request is forwarded to ExpwC and C sends to CUCM and CUCM responds based on the Refresh login configuration ++
2020-03-24T16:31:00.963-06:00 labucexpye01 traffic_server[16087]: UTCTime="2020-03-24 22:31:00,962" Module="network.http.trafficserver" Level="DEBUG": Detail="Sending response" Response-code="200" Txn-id="2004" Dst-ip="81.157.160.37" Dst-port="59252" <Response> <SingleSignOn> <Status enabled="false"/> <Token reuse="true"/> </SingleSignOn> </Response> </SSOResult>
++ Once Token re-use is set to True, Expressway-E will then presents Jabber with a login form ( via the built in web browser) Once the user has entered all the login details, Jabber sends an Authorize Response with the client ID to be used for the authentication++ |
Request-Sequence |
Request Sent |
{2: "authorize?response_type=code&realm=local&client_id="} |
"GET https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/authorize?response_type=code&realm=local&client_id=.... |
++ Jabber confirms Token reuse is enabled ++ 2020-03-24 22:31:00,442 INFO [0x00002b04] [rvices\impl\system\SingleSignOn.cpp(206)] [Single-Sign-On-Logger] [CSFUnified::SingleSignOn::Impl::isAuthenticatorTokenReuseEnabled] - TokenReuse enabled for 1001
++ Jabber states that services needs authorization and we need credentials for authentication ++ 2020-03-24 22:31:00,442 INFO [0x00002b04] [\impl\system\UserProfileManager.cpp(153)] [UserProfileManager] [CSFUnified::UserProfileManager::Impl::getCredentialsForAuthenticator] - for authenticator: 1001
++ Jabber sends authorization response with client id++ 2020-03-24 22:31:00,442 DEBUG [0x00002b04] [bwindowplugin\browsercontroller.cpp(167)] [PluginUtils] [BrowserController::NavigateTo] - Enter - url = https://labucexpwye01.bouldermedicalcenter.com:8443/Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/authorize?response_type=code&realm=local&client_id=C1b4b988f3efa1c3fc97d0d0a36f6b97f244b4fafe55e8d9d7
++ Expressway-E recieves the the Authorization response ++ 2020-03-24T16:31:01.569-06:00 labucexpye01 traffic_server[16087]: UTCTime="2020-03-24 22:31:01,569" Module="network.http.trafficserver" Level="INFO": Detail="Receive Request" Txn-id="2005" Src-ip="81.157.160.37" Src-port="59254" Msg="GET https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/authorize?response_type=code&realm=local&client_id=C1b4b988f3efa1c3fc97d0d0a36f6b97f244b4fafe55e8d9d78774 e305bae9ab1&device_id=2c23dad7-ab7e-4686-a461-b23cffbaa15e&email=aokanlawon@lab.com&state=1771145038 HTTP/1.1" |
++ Next Jabber sends Authentication request with client_id established earlier ++
Request-Sequence |
Request Sent |
{3: "localauthentication"} |
"POST https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/localauthentication HTTP/1.1" |
+++ Next Jabber sends a POST request for local authentication with its client_id++
2020-03-24T16:31:22.729-06:00 labucexpye01 traffic_server[16087]: UTCTime="2020-03-24 22:31:22,729" Module="network.http.trafficserver" Level="INFO": Detail="Receive Request" Txn-id="2007" Src-ip="81.157.160.37" Src-port="59254" Msg="POST https:///Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/localauthentication HTTP/1.1" Module="network.http.trafficserver" Level="DEBUG": Detail="Receive Request" Txn-id="2007" Src-ip="81.157.160.37" Src-port="59254"
+++ Next Expressway-E sends POST request to C +++ +++ Expressway-C receives the request +++
2020-03-24T16:31:22.739-06:00 labucexpyc01 traffic_server[14358]: UTCTime="2020-03-24 22:31:22,739" Module="network.http.trafficserver" Level="INFO": Detail="Receive Request" Txn-id="6114" Src-ip="127.0.0.1" Src-port="33688" Last-via-addr="10.10.1.44" Msg="POST http://vcs_control.lab.com:8443/Ym91bGRlcm1lZGljYWxjZW50ZXIuY29t/localauthentication HTTP/1.1"
+++ Expressway-C will do two things here
|
+++ Now Jabber will send a POST request to get access_token and will embed the following information in the POST request +++
1. authorization code
2. client_id
Request-Sequence |
Request |
{7: "access_token"} |
|POST //cucm.lab.com:8443/ssosp/token/access_token |
2020-03-24T16:31:23.789-06:00 labucexpyc01 edgeconfigprovisioning UTCTime="2020-03-24 22:31:23,789" Module="network.http.sso.server" Level="DEBUG" Action="Send" Url="https://av-cucm.lab.com:8443/ssosp/token/access_token" grant_type=authorization_code
+++ CUCM responds with 200 OK containing +++
|
OAuth process is now complete and Jabber will then start the normal service requests process but rather than using user credentials, will use the authorization header which will contain the access_token that has been obtained.
++ get_edge_config with Authorization header and access_token embedded ++
HTTPMSG: |
++ Back to the issue +++
Now that we understand the flow and we can see that the OAuth flow successfully completes, we now focus on why the client still could not login. For this we need to turn to Jabber PRT logs,
From the Jabber logs, here is what I see:
+++ 2020-03-31 12:12:54,998 ERROR [0x000006c8] [rwerx\jwcpp\xmppcore\src\client.cpp(192)] [csf.jwcpp] [gloox::Client::handleNormalNode] - @XmppSDK: #0, The server doesn't offer any SASL authentication mechanism that we can support
++ Jabber says that there is no Simple Authentication and Security Layer (SASL) authentication mechanism it can support ++ Questions is why? We have already established that Jabber is going to use OAuth for this session and has successfully obtained the required tokens. So what is going on.??
To understand what is going on, we need to know that Jabber needs to know the supported SASL authentication mechanism in the XMPP features advertised by Expressway-C. This in-turn depends on the advertised SASL authentication supported by IM&P server. So the next logical place to go is to find what SASL mechanism is advertised by both IM&P and Expressway-C
1. ++ Expressway-C request to get supported sasl mechanism supported by IM&P ++
NB: OAUTHBEARER ( is included in the SASL mechanism supported. This is required for OAuth to work)
The issue turns out that even though OAuth was enabled and the first stage of obtaining OAuth tokens was successful, expressway-C configuration was stuck on OAuth not been enabled: Looking at the xconfiguration API of expressway-C we saw "OAuthLocal:off" This should be on.
A reboot of the server fixed the issue:
This is the correct configuration
Troubleshooting Tips1. Some quick thing to check when having issues, verify the keys on all servers in the cluster
2. Refresh servers in Expressway-C to ensure that expressway has the keys to validate access tokens from CUCM Conclusion:This was a long one, I guess by now you know I do not do short articles/blogs. I guess the complexities of some of these solutions cant easily be written. OAuth is a great solution, I encourage you deploy it for your customers. As for my job interview, lets just say that I am still looking for a job. If you know someone or your team needs a good guy like myself. Please reach out to me. |
@Ayodeji Okanlawon When you mean impact, are you saying that any token refresh message does not travel over apple push notification service channel? None of the OAuth diagram mention APNS channel interaction and i know by experience that some message related to token refresh does travel over the APNS. Still have not figure out the entire picture fully.
All Oauth interaction is done via MRA not via the Apple cloud, so I don't see how refresh tokens will be sent via APPN. Remember that APPN just provides a socket to reach an apple device that has gone into back ground. For all MRA client interactions, like OAuth, SIP registrations, service discovery that will be done via Expressway. This is perhaps why there is no documentation on this because they are very separate things.
@Ayodeji Okanlawon This is what happened: APNS Configured. Jabber in background..Receive a message on apple device that token has expired that you have to renew. Click on message on apple device and that place jabber in foreground and have to re-authenticate. Then, there is interaction over APNS that relates to token expiration. Maybe not the token itself but it is on the flow.
I understand the flow. That first part where Jabber receives the message is normal. This is delivered over the APPN messaging channel since jabber was not reachable. However the process of refreshing the token cant go via APPN. Expressway must be in the call flow to interact with CUCM to obtain tokens, validate tokens etc...Pull jabber logs and you should be able to verify this.
@Ayodeji Okanlawon Those details on how expiration messages go over APNS are no mentioned anywhere. I know it by experience and log traces but ignored on every CCO document.
I see what you mean, thank you for bringing this up. Hopefully Cisco will improve the documentation for this
Great article, especially the troubleshooting section! But where does the AuthZ Server in the Unity Connection configuration come from? I know it must point to the CUCM Pub that's running the AuthZ service, but how is the URL derived?
Thanks,
Ryan
The URL is just the address of your CUCM AuthZ server. ( don't forget to rate the doc!)
@Ayodeji Okanlawon. Thanks for an excellent guide.
Would it be possible to use external/3rd party Authentication server like Azure AD ?
You can't use azure AD with CUCM. It's not supported.
Hi Team
In the scenario with two Expressway cluster (a different cluster for each DC ) should we care about jabber Oauth token as we have 2 expressway-E cluster , and the public SRV DNS for is configured in round robin between to two DC (Exp-E ) no GEO DNS is available
BR
Yes you should. The authentication is handled by the users home cluster as defined on the end user object. It’s not relevant that you have multiple expressways for MRA for this specifics.
Great doc!
Is it possible to use/configure OAuth just for MRA and also for jabber and 78xx phones with CUCM 12.5.1? We dont want to use Oauth internally because we dont want to use encrypted media internally. I saw some cisco presentation when this was mentioned but it was not so clearly and detailed explained so we dont know. There was written that Oauth needs to be turned on on the CUCM device security profile and this is only possible when ecrypted mode is selected there so just with SRTP.
Thanks
Tomas
Holy smokes! This is amazing!
Like Anthony, as soon as I saw who wrote it I got all excited.
Do you by chance have a PDF version that we can download?
Maren
Thanks @Ayodeji Okanlawon !! Great Document!
May I ask if it is possible to use oauth-1.0a with CVP call studio 11.6 ? I think I need to import a particular module into CVP call studio script but I am not finding it.
Thanks again.
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: