×
Back to book

Security handling with SpringBot

A guide for developers who want to understand the security of their SpringBot applications so that they can use it in custom code.

One of Codebots' highest priorities is the security of the software which our codebots write, to the point where a diagram was made to focus on that sole purpose. This same level of care and attention was given to developing SpringBot's security strategy.

When it comes to security, we categorise all work into the three A's:

  • Authentication,
  • Authorisation, and
  • Auditing

SpringBot utilises the standard Spring Security framework to cover Authentication and Authorisation, and Hibernate Envers for Auditing purposes. All of which has been implemented on top of our security standard which ensures all third generation bots have the same level of security across the software stack.

This article will explore SpringBot's security strategy, focusing on how to customise the three A's within your application.

We recommend all readers also explore the security strategy for SpringBot, which has been documented in the security documentation section of your Reference Library.

Authentication

In regards to Authentication, there are three main files that are responsible for creating, verifying and destroying authentication tokens. Each file and its purpose has been outlined below.

File Name Purpose
JWTLoginFilter.java Authenticates the user during login using their username and password to create a user token that can be used to authenticate for future requests.
JWTLogoutFilter.java Invalidates the users token so that it can no longer be used for authentication attempts.
JWTAuthenticationFilter.java Attempts to authenticate and return a success or unsuccessful response based upon the provided user token.

All of the files are located at the following relative path: serverside/src/main/java/[ProjectName]/configs/security/filters/[FileName]

Authorisation

SpringBot uses method level security through the use of the @PreAuthorize annotation. This annotation takes the form of @PreAuthorize("hasPermission('[Entity]', 'read')"), and has been applied to service and controller methods throughout SpringBot (although it can be applied almost any bean).

Whenever an annotated method is called, CustomPermissionEvaluator is invoked to check whether the current user has permission to perform the action detailed in the annotation (i.e. read). This file can be found at serverside/src/main/java/[ProjectName]/configs/security/evaluators/CustomPermissionEvaluator.java.

The best way to modify roles and privileges is through the Security Diagram.

More details on how the method-based authorisation works can be found in the
Spring documentation.

Auditing

By default, auditing is enabled and can be used to track the changes of the data within the application. Such changes are logged in two different tables: the EntityAudit and Revisions tables, which have been created and managed by Hibernate Envers.

An entity can be registered for auditing via Envers annotation @Audited, which will inform Envers to create the necessary audit tables and keep track of changes to any instance of that entity automatically. All entities within the application can be found under serverside/src/main/java/[projectName]/entities/*.

The data structures involved in auditing can be viewed in the below:

These entities don't actually need to be made in the Entity Diagram, it was just used to demonstrate the relationship and entities involved. In all applications, these entities are abstracted and not included in the diagram.
Additionally, this diagram represent conceptual relationships not concrete ones.

Revisions and EntityAudit table

Mutations are stored within the Revisions and EntityAudit tables.

The Revisions table records the metadata for a given mutation as a revision. This data includes the timestamp of the mutation, the author, and entity that was changed. The revisions are handled by the Java class CustomRevisionEntity and is located at serverside/src/main/java/[ProjectName]/configs/security/auditing/CustomRevisionEntity.java. You can track additional values by adding to the protected regions in this class.

A full copy of the entity instance is stored in the EntityAudit table for that given entity, along with a reference to the given revision in the revisions table. This allows for the metadata to be stored and associated with the underlying data itself.

The entity audit table follows the naming convention of [EntityName]_entity_audit_log.

Read audits

In addition to auditing the mutations, SpringBot also records read requests and responses. Specifically, SpringBot records the request itself and the data that is part of the response.

Request

The request is stored in a log file that is archived daily. By default, this log file can be found at serverside/logs and is called request-log.log. The archive of the logs (rotated daily) can be found in the serverside/logs/archived directory.

An example of an entry in this log is:

2019-09-19 13:27:48,506 INFO example_app.configs.security.filters.RequestLoggingFilter [ http-nio-8080-exec-10 ] Method: [POST], URI: [/graphql], User: [staff@example.com], Time: [2019-09-19T13:27:48.505+10:00], Payload: [{"operationName":"GetWithQuery","variables":{"pageIndex":0,"pageSize":10,"orderBy":[{"path":"created","descending":true}],"where":[[]]},"query":"query GetWithQuery($pageIndex: Int, $pageSize: Int, $orderBy: [OrderBy!], $where: [[Where!]!]) {\n timesheets: timesheets(pageIndex: $pageIndex, pageSize: $pageSize, orderBy: $orderBy, where: $where) {\n  ...TimesheetProperties\n  staff {\n   id\n   email\n   __typename\n  }\n  __typename\n }\n totalCount: countTimesheets(where: $where)\n}\n\nfragment TimesheetProperties on Timesheet {\n ...TimesheetBaseProperties\n hoursWorked\n description\n __typename\n}\n\nfragment TimesheetBaseProperties on Timesheet {\n id\n created\n modified\n __typename\n}\n"}], Headers: [{host:localhost:8080,connection:keep-alive,content-length:731,sec-fetch-mode:cors,origin:http://localhost:4200,authorization:Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdGFmZkBleGFtcGxlLmNvbSIsImV4cCI6MTU2ODg2NzI1M30.60Oi_pbsYUUTWpvnZBrb7_FmTqvvTAypSToTjAtsaM90udT-KVVo_HMTyDkbjehmWNwtbfRCEofVP8GbQeyCjA,content-type:application/json,accept:application/json, text/plain, */*,user-agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36,dnt:1,sec-fetch-site:same-site,referer:http://localhost:4200/timesheet,accept-encoding:gzip, deflate, br,accept-language:en-GB,en;q=0.9,en-US;q=0.8,en-AU;q=0.7,}]

Response

Each entity in your SpringBot application has an associated entity listener which can be found at
serverside/src/main/java/[ProjectName]/entities/listeners.

Each of these listeners has a method called afterLoad that records all the data fetched in the associated read audit table (only one exists for each entity). The read audit tables follow the naming convention
entity_name_entity_read_audit and stores the created date time, the data, and the user that made the request.