Different application’s approach: Sugar 7 framework
For whoever is reading this article and is not familiar with Sugar on the most recent version 7.x of the product, it is important to note that the application’s core is now a RESTful based API.
The presentation layer is based on SugarCRM’s framework “Sidecar”, that uses quite a few Open Source libraries (including Bootstrap, jQuery, Handlebar and Backbone.js).
The framework’s MVC layer is cached/stored within the browser at the first application’s load and interacts with the REST API on every subsequent call, creating a more powerful experience as a Single Page Application.
The great concept around the newer application’s framework is that everything can now be achieved interacting with the application via API calls, if it can be done in the application by using the interface (except BWC functionality).
By doing so, the framework provides extreme flexibility and huge integration capabilities, and therefore it allows customers to build any business process around the application.
Local authentication in Sugar 7
In Sugar 7.5.0.1 (current version of Sugar) there are quite a few moving parts in regards to the authentication and session management.
When using the standard application’s interface, the application completes an OAuth token request passing the user’s credentials at login.
From that point onwards the OAuth token is passed through every authenticated HTTP request’s header (it is vital to use SSL to guarantee security).
The OAuth token, the refresh token (used to obtain an additional token when the current one expires) and the download token (used to download files from the API) are stored on the browser’s local storage, easily retrieved and used by Sidecar.
Let’s answer some questions
Now the functionality is pretty straight forward, but let’s answer some questions that will highlight the application’s behaviour.
What happens on the backend at login?
At first, the system invalidates any previously active refresh token for the user (oauth_tokens database table), and then adds a new entry on that database table, containing the refresh token as record id, the download token, the expiry date and quite a few other info.
The system will then create a PHP session (on whatever is the PHP session storage of choice. By default on a vanilla linux PHP install, the file will be on /var/lib/php/sess_<session_id>) containing all the required info to run the application.
What happens when the PHP session expires?
If the browser contains a valid refresh token on its local storage, it will automatically regenerate a new access token, create/update database entry on the relevant table and a new PHP session, without the user even noticing (aside from a HTTP 401 error on the browser’s console). If the refresh token is no longer valid or non-existent, it will redirect the user to the login page.
What happens when the OAuth token expires?
This is basically the same as “What happens when the PHP session expires?”. When the system receives a HTTP 401 error (stating that the access token provided is invalid) the user interface will automatically try to refresh the token using the refresh token stored on the browser’s local storage, and if successful it will complete the action requested, otherwise the application will redirect the user to the login page.
How do I enforce a token revalidation for every user?
If using the standard PHP session storage, and the server is running only Sugar (making sure not to affect any other application running on the server) it is just a matter of deleting any active session file located usually in /var/lib/php/sess_*. This action will invalidate all current PHP sessions for the server. If the system leverages Memcache(d) or Redis as PHP session storage layer, the equivalent action should be performed.
How do I forcefully log out every user from the application?
You would need to remove every entry from the database table “oauth_tokens” and in addition to that, complete the same action as “How do I enforce a token revalidation for every user?”. We would basically be telling the application to expire the current re-validation tokens available to the users and also to invalidate any current access token in use.
If the entries are removed only from the database table (containing refresh tokens), the system will not logout the users immediately. The system will fail to re-generate the next access token as soon as one of the following conditions is applicable:
- the current access token expires
- the 120 seconds maximum session/database cross check elapses (defined on include/SugarOAuth2/SugarOAuth2Storage.php with TOKEN_CHECK_TIME = 120)
Are there any settings that can help tweak the duration of the tokens?
Yes! You can add/modify some parameters within the file config_override.php of the application, that will let you change some parameters:
- You can change the duration of the access token (default 1 hour):
$sugar_config['oauth2']['access_token_lifetime'] = <seconds>;
- You can change the duration of the refresh token (default 2 weeks):
$sugar_config['oauth2']['refresh_token_lifetime'] = <seconds>;
- Optionally you can set the MAXIMUM time that a user can be logged in for (default not set) before triggering a logout:
$sugar_config['oauth2']['max_session_lifetime'] = <seconds>;
Where is the standard PHP session cookie? Is it gone?
No, at least not yet! It is currently generated/used only for functionality in backward compatibility mode (BWC).
As soon as a page in backward compatibility is loaded, it will automatically store the PHP session cookie (if not yet existing) on the browser and then proceed with loading the requested page. The session id on the PHP session cookie has the same value as the OAuth token.
That’s all for today! I hope this post helps you understand more about how authentication works when using the local user management in Sugar.
If you have additional questions please let me know and I will try to find an answer for you.
Enrico, a nice introduction. I’m keen to look at the code to get to know it better. Thanks for the blog.
Thank you for your support Greg!
Enrico,
How does it know that the PHP session has ended? Does it receive a 401 on the API request, and it assumes that the PHPSESSION is expired?
Is there any way I can ask you to shed light on the refresh token? What is it? When is it needed? Why do we need a refresh token?
Hi Michael,
Access tokens, and refresh tokens are standards on the OAuth authorisation framework (https://tools.ietf.org/html/rfc6749#section-1.4 and https://tools.ietf.org/html/rfc6749#section-1.5).
Access tokens are used to access a system, refresh tokens are used to gain a new access token on expiration.
If the PHP session expires or if your access token expires, you would receive a 401 HTTP error code on your browser. The Sugar UI would automatically obtain a new access token (using the refresh token) and re-connect to the last accessed page. If the refresh token (stored within the database) is no longer valid, it would instead redirect you to the login page.
Hope it helps!
Is it possible to force a login of a particular user with a known user who passed in headers to the application by security middleware sitting between user and server?
the headers are never seen by the client side. the problem is getting the UI side to recognize it is logged via the custom authenticator on the backend. on page load to trigger based on the ‘authenticated_user_id’ in the $_SESSION.
Hi Max,
This is a really interesting question and I actually had to solve the problem myself recently for an Enterprise Sugar implementation.
You could setup natively SAML if you do have the option on your environment/infrastructure as that would be the easiest way for you to move forward and supported out of the box.
If you do need to follow a custom solution you have two approaches that you could try to leverage:
I would try with the first approach, and then if it does not allow you to fulfil 100% your requirements move on to the second one.
Hi Enrico,
This might be a stretch, but it has to do with OAuth, and the REST 4_1 framework.
Would you know how I can do the 3 legged dance with SugarCRM if I create a OAuth and enter the consumer client id and client secret in the Admin->Oauth module.
Hi Michael,
This help link might help you with what you are trying to achieve