Tuesday, October 9, 2018

Adding an Event to the Google Calendar using OAuth

In this post, I will illuminate how to add an event to the Google Calendar using OAuth. If you want to know about how OAuth basically works, you can visit my previous post on Open Authorization (OAuth 2.0), where I explained how it works by protecting the user resources while it enables other applications to access certain protected resources on behalf of the user, given that the user has granted permission for access preceding it.

Registering your Application and Enabling OAuth 2.0 Access in Google API Console

   1. Let's start by registering our application which requests the Google Calendar permissions, by visiting the Google API Console.

   2. You will get a Dashboard similar to the one in the picture below. Click on the Highlighted Dropdown. If you have not made any projects yet, your dropdown button is the one with 'Select a project' on it.



   3. After you click on the dropdown, you will get a modal as the one below. As you can see, this modal shows all the Projects you have currently made, and in the picture below, you could also see the Project: 'Event Creation Application' which I have made initially when developing this application. To register the application, we must create a project first, so click on the 'New Project' button I have highlighted.



   4. After that, you will land on a page which looks like the one below, where you have to enter your Project Name, and then press the 'Create' button.


   5. You will receive the success notification below on your Google Console Dashboard once the project has been successfully created.


   6. Now, having created the project, let's proceed with enabling of OAuth 2.0 API access. For this you need to go to the Google API Console Credentials page. Before going ahead, make sure you have selected the correct project in the project dropdown. Click on 'Create credentials' button, and select 'OAuth client ID' option from the context menu.


   7. You will get a page to fill the Application details which looks not exactly, but somewhat similar to this:


Please fill in all the necessary details. Make sure you give a meaningful Name for the Application as this is what will be displayed in the user consent page, and users may feel uneasy to grant access if it is not a proper name. You must also make sure to give the Redirect URI of your application as this is the endpoint to which the Authorization Server will send responses to.

    8. Also make sure to select Web Application under the Application type.

   9. After you have created the credentials, you will be provided with a Client ID and Client Secret. Please note them down.

How to create an Application that adds Events to Google Calendar

You can visit this GitHub link if you would like to view and try out the sample application I made using Spring Boot to add events to the Google Calendar.

If you are trying this application out, there are some changes you need to make to the code. I have indicated all these changes with the 'CHANGE:' tag below.

This application will only contain one front end page, which is the one below:


   index.html:




CHANGE: In index.html, you may change the client id to your one in the JavaScript method, redirectToGoogleOAuthEndpoint().

   1. You can press the 'Grant Access to Google Calendar' button to grant access to your calendar. You will be redirected to a Login page or Choose an Account page upon clicking like the one below. As you can see, the Application Name shown in the Sign in will be the name you gave when registering the application by creating the Credentials.


   2. After you have granted access, you will be redirected to the first and the only page of the application, while in the background, the Authorization Server will return a response containing the Authorization Code when the user grants access.

As you can see in the code above, once 'Grant Access to Google Calendar' button is pressed, redirectToGoogleOAuthEndpoint() method is called where the required query parameters are set, and the full, final Authorization Endpoint URL to be redirected to is built, finally, redirecting user to the Authorization Endpoint after everything is set.

Authorization Endpoint of Googlehttps://accounts.google.com/o/oauth2/v2/auth

Authorization Request Parameters:
  • client_id            (Required)
  • redirect_uri       (Required)
  • scope                 (Required)
  • access_type       (Recommended)
  • state                   (Recommended)
  • response_type   (Optional)
  • include_granted_scopes, login_hint, prompt     (Optional)
I have used all the required and recommended parameters with the optional response_type parameter set as 'code' which is the value normally sent in the Authorization requests in Authorization Code Grant Type, but you can add any optional ones too if you want to.

Scope for Google Calendar Accesshttps://www.googleapis.com/auth/calendar

State, which is a random string is used to prevent CSRF as I mentioned in my previous post.

   application.properties:


CHANGE: You may change the client_id, and client_secret values to the values you obtained when you created the credentials in Google API Console.

   EventController.java:





   3. As I mentioned above, when user grants access, the Authorization Server will send the response to the Redirect URI which is http://localhost:8081/callback in this case. Once the endpoint that maps that URI is triggered by the Authorization Server response, we can retrieve the value of the parameter 'code' sent in the response which is the Authorization Code, and make a new POST request to the Authorization Server, requesting an Access Token in exchange for the Authorization Code.

Token Endpoint of Googlehttps://www.googleapis.com/oauth2/v4/token

Access Token Request Parameters:
  • code
  • client_id
  • client_secret
  • redirect_uri
  • grant_type
All the parameters mentioned above are required.

grant_typeauthorization_code

Please note that the redirect_uri added here must be the same redirect_uri used in the initial authorization request before.

Another thing to note is that the Content-Type must be application/x-www-form-urlencoded.

After setting the parameters, we can send the POST request, and obtain the JSON response, from which we can retrieve the 'access_token' parameter value sent by the Authorization Server, and save it in a variable for future use when accessing resources.

After receiving the Access Token, user is redirected to index.html as I stated above.

   4. Now you can fill the form, and click the 'Submit' button. Clicking this button will trigger the JavaScript method: addEventToGoogleCalendar() which will take the provided form details, and make an AJAX POST call to the '/addEvent' Endpoint URI of the server which handles the event addition to the Google Calendar. 

   5. When the '/addEvent' endpoint is triggered, a POST request will be made to the Google Calendar API Resource Server to add the event to the Calendar, and the JSON response sent by the server will be read finally when returning the success response to the frontend in JSON format, adding the link of the created Event to it.

It is noticeable that I have only made the Email, Start Date and Time, and End Date and Time fields required in my form as they are the minimal set of values that must be present to add an event to the Google Calendar. 

Email is the calendarId which is the calendar identifier, and without setting this, it is also possible to place 'primary' as the value, and the primary calendar of the logged in access granted user will be used.

Summary, Location, Description, and Attendees are some of the other optional parameters that can be given when making a Calendar Event. The Event ID is also an optional parameter, which if not provided, will be generated by the server for you. In this case, I have made use of some of these optional parameters.

Google Calendar Endpoint
https://www.googleapis.com/calendar/v3/calendars/calendarId/events

Another thing to note is that the Content-Type is application/json. Therefore, all the above mentioned parameters are added to JSON object before making it a string finally, read to be sent.

As we have the Access Token now, when communicating with the Resource Server, we must send it, and this is done by adding it in the Header of the request as "Authorization" being: "Bearer XXX" where XXX is the value of the Access Token.

Please note that the models for Job and Response which maps an Event and a Response to frontend respectively are made as well in the models folder.

   6. Depending on whether the Event Addition to Google Calendar is successful or not, a message will be given to the user. If the event addition is successful, the message below will be displayed, and the user will be able to view the added event in the Google Calendar upon clicking the 'OK' button.

   Success Message:


   Event added to the Google Calendar:


References

Open Authorization (OAuth 2.0)

Open Authorization (OAuth) is an open-standard framework for delegated authorization. OAuth provides the capability for applications to access the protected data or resources of a user of a third-party application, without exposing or having the need to provide login credentials of that application to the party that needs to access the data.

When an application wants to access third-party resources on behalf of the user, instead of requesting the username and password for the third-party application from the user, OAuth framework is used now to obtain an access token which grants access and permission to a predefined set of resources. Using OAuth secures the user resources, as otherwise, login credentials may have to be provided, and providing login credentials to another application gives the application the ability to perform any action as the user. For example, if the application needs to access only the email contacts, but users have to provide the login credentials for the application to access the contacts, the application will have the capability to perform actions like sending emails to people pretending to be the real user, and perform actions for which the user may not have originally intended to give permission.

How OAuth Works

The picture below illustrates how OAuth works using Authorization Code Grant Type (other grant types also have a similar flow with slight differences):


Roles

  • Client - This is the resource requester; the application which requests resources on the user's behalf.
  • Authorization Server - This is the third-party application that issues the access tokens for accessing its resources.
  • Resource Server - This also belongs to the third-party application which contains the resources that needs to be requested. 
  • Resource Owner - This is the user; the owner of the protected resources. 


Protocol Endpoints

Both the Authorization Endpoint and the Token Endpoint are located in the Authorization Server while the Redirection Endpoint (Redirect URI in the diagram above) is located at the Client application.
  • Authorization Endpoint - This is used to get the user's approval/authorization to issue an access token to access the protected resources.
  • Redirection Endpoint - This is the endpoint to which the Authorization Server sends responses to in the client application, after receiving and processing the requests made on the Authorization Endpoint and the Token Endpoint.
  • Token Endpoint - This endpoint issues the access tokens.


The following are some of the important points that must be noted regarding OAuth:
  • Both the Authorization Code and the Access Token have a validity period which means that it will expire after a certain time period decided by the Authorization Server.
  • Authorization Code can be seen in the browser request, but others like the Access Token cannot be seen as the communication which takes place after user access consent is server-to-server communication.
  • The Client application must be registered with the third-party application which contains the resources, so that it can identify the client who requests the resources. Upon registering the application, you will receive the Client Id (Consumer Key/Client Key/App Id) which is the username of the application, and the Client Secret (Consumer Secret/App Secret) which is the password of the application requesting the information. 
  • Client Id of the registered application must be sent to the Authorization Server when requesting both Authorization and Access Token.
  • Scope refers to the permissions that needs to be requested.
  • Multiple permissions can be requested at the same time using Scope.
  • State is a random string which is used to prevent CSRF, and is therefore recommended. It is sent to the Authorization Server, and the server sends it back to the client in response. 
  • Resource Server defines which resources can be accessed and using which scopes.
  • Client Secret must be sent to the Authorization Server when requesting an Access Token as the server has to validate the requester. The initial request does not need to have the Client Secret sent to the server.
  • The user has to give the consent only once.


Grant Types

There are several ways in which Access Tokens can be obtained, and these mechanisms are called Grant Types.
  1. Authorization Code Grant Type - This is used to develop Server-side Web Applications.
  2. Implicit Grant Type - This is used in implementing Client-side Applications like Single-page JavaScript applications. It has no Token Endpoint as initial response itself returns a Token.
  3. Resource Owner Password Credentials - This is used in Trusted Apps like Facebook Mobile App where username and password is requested, and is possible to provide the login credentials without any worries. It has only the Token Endpoint, and does not have an Authorization Endpoint.
  4. Client Credentials - This is used in Server-to-server communication, and it has no user involved. There are times when although no user is involved, information must be exposed securely to outsiders or other applications. For instance, this can be used when retrieving data like Weather data or Traffic data from an API. It has only the Token Endpoint, and does not have an Authorization Endpoint.


Some Use Cases

  • Logging on to websites using other social websites like Facebook, LinkedIn, Twitter, etc. 
  • Automating the uploading of some files to Google Drive.
  • Retrieve data from Facebook and display it or carry out some processing. For example, this is done by the fun applications that access information and predicts things like "What your profile picture reveals about you?" or "When will you die?"
  • Accessing Gmail contacts.
  • Access Photos stored on another site.
  • Updating Gaming Scores and storing them on another site.


One of the advantages of using Social Websites to login to other websites is that you do not need to create multiple accounts, but at the same time, one of the disadvantages is that it can become a single point of failure because if the credentials to the social website are leaked, then others can have access to all the other websites you logged into using the social login.

While OAuth protects the users' resources, one of the disadvantages of OAuth is that whoever bearing the Access Token can access the data, which means if an attacker gets or steals this Access Token, they can get the permission-given data until the Access Token expires. 

Thursday, October 4, 2018

Double Submit Cookies Pattern

As I mentioned in my previous posts, Double Submit Cookies Pattern is another mechanism of preventing CSRF attacks.

Similar to the Synchronized Token Pattern, a random string token is generated whenever a user logs in and a session starts in Double Submit Cookies as well. One of the main differences is that the server only generates the token, and does not store it in the database in Double Submit Cookies Pattern, whereas the token is stored in the database in Synchronized Token Pattern.

What happens here is after generating the CSRF token, the server sets a cookie which contains the CSRF token in the client's browser. 

If we take the same example as in the Synchronized Token Pattern, where an admin fills a form to create a user account, in a similar fashion, in Double Submit Cookies Pattern too, a hidden field which contains the CSRF token must be embedded in the form. The CSRF token value to be embedded is not retrieved from the server side through an AJAX call like in Synchronized Token Pattern. In Double Submit Cookies Pattern, we retrieve the CSRF token value from the CSRF cookie stored in the browser using Javascript.

To read cookies through Javascript, the domain should match with the current domain which means only the cookies of the current domain will be visible. CSRF cookie cannot be protected by httpOnly flag that is used to prevent any client side Javascripts from reading and accessing this cookie because the requirement of the problem needs the reading of the CSRF token using Javascript.

When the request is sent to the server, either the body will contain the CSRF token embedded in the form or the header, and since the browser selects and sends all the cookies that fall under the current domain and path to the server along with all the requests to maintain the session, the server can easily validate whether the current session is valid or not by reading the received CSRF token cookie value and comparing it against the received CSRF form-embedded token value.

Therefore, this makes it impossible for attackers to obtain and access the cookies for another domain, and attackers' request body/header will not have this token.

The diagram below illustrates the flow of the Double Submit Cookies Pattern process mentioned above:



We do not protect GET requests against CSRF attacks, as we expect client to send the CSRF token, and the token cannot be sent in the query parameters of a GET request as it exposes the token.

You can visit this GitHub link to view the sample implementation of Double Submit Cookies Pattern to prevent CSRF. I have hard-coded the username and password for demonstration purpose.

Username and Password both: ssd

As in the diagram above:


   1. User logs in to the system using index.html. The form action points to login.php, and the form details will be submitted to it when the user clicks the Login button.

   Login Page:

   index.html:







   
   
   2. If the user has provided the correct login credentials, the user is redirected to add_user.html.

   login.php:
























As in Synchronized Token Pattern, for each login, a new session is made for the user, and it is ensured that a new PHP Session Id is generated for each login after invalidating the already existing session.


Similar to the approach taken in Synchronized Token Pattern, the CSRF Token, being a randomly generated string, in this case, has been produced by hashing and Base64 encoding the random integer created while taking the current timestamp into account, through the line:
$csrfToken = base64_encode(hash("sha256", uniqid(mt_rand(1000, 9999)
.microtime(), true), true));

Afterwards, setcookie() function in PHP has been used to create and store a cookie which contains the generated CSRF Token value in the user's browser, through the line:
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/");
Cookies normally contain the five key-value pairs: Cookie Name, Cookie Value, Domain, Path, and Expiry Date. As it can be seen the Name of the Cookie is set to be "CSRF_TOKEN", Value is the generated CSRF Token value, and Path is "/" (root) which means all the paths of the particular domain to which the cookie belongs. The Cookie is set to expire after 30 days. The domain is not mandatory to be added to the setcookie() function along with the other required and appropriately added details as the browser automatically sets it as the current domain as it is the domain setting the cookie in the browser at that point of time.  

   3. The CSRF Token for the session is retrieved from the CSRF_TOKEN cookie stored in the user's browser using JavaScript, and when the user fills the form and clicks the Insert button, the form details are submitted to the pointed validate_token.php.

   Add User Page:

   add_user.html:


























When the form has completely loaded as checked by the document.readyState if statement, the CSRF token value is retrieved from the cookie stored in the user's browser by calling getCSRFToken() method, passing the Cookie Name as a parameter, and after retrieving the CSRF token value, a new hidden input field is added to the form, and this input field contains the retrieved CSRF token which is to be passed to the server-side in the attempt in enabling the server to recognize whether the request is legitimate or not.

getCSRFToken() method works by accessing cookies of the current domain using document.cookie, decoding the retrieved value which contains all the cookies for the current domain, and splitting by the delimiter ";" to separate key-value pair cookies of the retrieved cookie set. Then, in a loop, each key-value pair is accessed and the white spaces in the beginning are removed, if found, and afterwards, if it is possible to find the correct key-value pair which contains the string: "CSRF_TOKEN=" and the CSRF Token value, the CSRF Token value which is the value in the key-value pair is extracted and returned. 

   4. When the form details are submitted to validate_token.php on Insert button click, the CSRF Token values will be compared and validated, and a message will be returned based on the outcome of the comparison.

   validate_token.php:































validate_token.php checks whether the request is POST and checks to see whether the PHPSESSID which is the PHP Session Id has been set. Additionally, it checks to see whether a value has been set as the 'csrf_token' in the request body and also in the CSRF_TOKEN cookie, and if it has been set, the CSRF Token value stored in the received CSRF Token Cookie is compared with the value sent in the POST request body to see whether the values are equal and the request is legitimate. Either a successful message as in the picture included below, or an error message will be displayed in the client-side based on the equality comparison outcome.

This way we do not need to store a whole set of CSRF Tokens mapped against each user's each session in the database.

Wednesday, October 3, 2018

Synchronized Token Pattern

Synchronized Token Pattern is one mechanism to prevent or handle the security attack: Cross-Site Request Forgery (CSRF). My previous post on CSRF will give you an idea about what CSRF is.

Each time a user logs in, a new session is created for the user if the site allows multiple logins like Facebook, allowing users to log in from many browsers and devices. In Synchronized Token Pattern, a random string token is generated in the server side whenever a user logs in and a new session is created. This token is stored in the database mapped to each session of the user. The server then exposes a URL which can be accessed by the user to get the generated CSRF token.

Lets assume that the user is an Administrator making a user account for another user of the system. The admin will fill the form providing the relevant details of the user and submit it. The server will receive all the form details through the request made to the backend. 

After obtaining the token, the user can embed the token in a hidden field in the form and send the token in the request along with the user details to the server when posting data. This way, the server can identify whether the request is valid as only a valid request will contain the Session Id, Username, and CSRF token that matches the values stored in the database.

The user must make an AJAX call to obtain this CSRF token. The attacker will not be able to obtain this token, as whenever a browser makes an AJAX call, it validates the current domain against the request domain. If the call is made to www.abc.com, this domain should match in the browser and the server call. The browser will only send the request if the domain matches. By default, making Cross-domain AJAX calls is not possible as it is blocked. It can be enabled if needed, but for these security reasons we do not enable it normally.

As attacker will not be able to obtain the CSRF token using an AJAX call as domains will not match, CSRF will not be possible as attacker's form will not contain the CSRF token, making the request invalid even if all the other details match.

The diagram below illustrates the flow of the Synchronized Token Pattern process mentioned above:



You can visit this GitHub link to view the sample implementation of Synchronized Token Pattern to prevent CSRF. In this example, instead of using a real database, the CSRF token generated for each session is mapped to a PHP key-value associative array in the Server-side, and is used in validating the requests. I have also hard-coded the username and password for demonstration purpose.

Username and Password both: ssd

As in the diagram above:


   1. User logs in to the system using index.html. The form action points to login.php, and the form details will be submitted to it when the user clicks the Login button.

   Login Page:

   index.html:






 

   2. If the user has provided the correct login credentials, the user is redirected to add_user.html.

   login.php:




For each login, a new session is made for the user as mentioned earlier, and it is ensured that a new PHP Session Id is generated for each login after invalidating the already existing session.

A CSRF Token is also generated for each user login session, and for demonstration purpose, as mentioned previously, it is stored in a PHP associative array, mapped against the Session Id through the line:
$csrfTokenArray[session_id()] = $csrfToken;

The CSRF Token, being a randomly generated string, in this case, has been produced by hashing and Base64 encoding the random integer created while taking the current timestamp into account, through the line:
$csrfToken = base64_encode(hash("sha256", uniqid(mt_rand(1000, 9999)
.microtime(), true), true));

The array that stores CSRF tokens mapped against the Session is added to the Session through the line mentioned below, so that it is accessible from other server-side files throughout the Session:
$_SESSION['csrfTokenArray'] = $csrfTokenArray;



   3. The CSRF Token for the session is retrieved using an AJAX call, and when the user fills the form and clicks the Insert button, the form details are submitted to the pointed validate_token.php.

   Add User Page:

   add_user.html:




























When the form body is loading the JavaScript function getCSRFToken() is called, and this function makes the above mentioned AJAX POST call to the server-side token_dispatcher.php to retrieve the CSRF Token generated for the current user's current session. The JSON response returned from the server-side is taken, and when the form has completely loaded as checked by the document.readyState if statement, a new hidden input field is added to the form, and this input field contains the retrieved CSRF token which is to be passed to the server-side in the attempt in enabling the server to recognize whether the request is legitimate or not.

   4. When the client-side makes the AJAX call to the server-side, if there is a Session, the CSRF Token for that particular Session is returned to the client-side in JSON format.

   token_dispatcher.php:


token_dispatcher.php checks whether the request is POST and checks to see whether the PHPSESSID which is the PHP Session Id has been set, and if these conditions are met, it retrieves the associative array stored in the Session and returns the CSRF Token for that particular Session identified by the Session Id, along with the 200 message status and a message in the JSON format.

   5. When the form details are submitted to validate_token.php on Insert button click, the CSRF Token values will be compared and validated, and a message will be returned based on the outcome of the comparison.

   validate_token.php:


It performs the same checks previously carried out in token_dispatcher.php, but this time, additionally, the check to see whether a value has been set as the 'csrf_token' is enabled, and if it has been set, the CSRF Token value stored in the array for that particular Session is compared with the value sent in the POST request to see whether the values are equal and the request is legitimate. Either a successful message as in the picture included below, or an error message will be displayed in the client-side based on the equality comparison outcome.


One of the major drawbacks of the Synchronized Token Pattern is that it requires a lot of database space to store all the CSRF tokens generated per each user's each session. Double Submit Cookies Pattern is a better alternative to prevent CSRF while overcoming this storage issue, and I will discuss about Double Submit Cookies Pattern in my next post.