Security - THM-ATLAS/spring-backend GitHub Wiki

The Backend is secured by Spring Security. This framework is provided by Spring to restrict access to certain features of applications and provides user authentication functionalities. Every request that arrives at the backend first passes through the various stages of Spring Security. Spring Security uses an Auth-Header to check whether a user is authenticated. If this is the case, the request is passed through to the controllers and processed accordingly. If not, the user is redirected to /login, where he can enter his username and password.

AtlasAuthFilter

The AtlasAuthFilter is called when a POST request arrives on /login. It extends the UsernamePasswordAuthenticationFilter class, which is Spring Security's default class for username and password authentication. The method attemptAuthentication is implemented. Which takes an HTTP request and an HTTP response and returns an Authentication. Within this function the JSON in the payload of the request is parsed to an object of the class AuthReq, which contains the given username and password. This class is used exclusively to be able to continue working with the data from the JSON. From the username and password now a UsernamePasswordAuthenticationToken is created, which is passed to the authenticate method of the LDAPAuthenticationManager. This object represents an attempted authentication that still needs to be verified.

LDAPAuthenticationManager

The LDAPAuthenticationManager is responsible for actually performing the authentication. It implements the AuthenticationManager interface, which requires the authenticate method to be implemented. This method takes an authentication (in our case the UsernamePasswordAuthenticationToken) and returns an authentication (In our case an AtlasAuthentication). This method checks username and password, and sets the authenticated field in the authentication to true if everything matches. In our case, the method gets username and password from the UsernamePasswordAuthenticationToken and then first checks if this username is known in THM LDAP. If yes, authentication via the LDAP is attempted. If no, authentication via the database is attempted. If both do not work, an InvalidCredentialsException is thrown. If the authentication was successful, the UserDetails are fetched from the database or LDAP and updated. Then a new AtlasAuthentication is created with the corresponding user and authenticated is set to true.

initLdap()

The initLdap() method initializes a connection to the THM's LDAP server. Returned is a LdapTemplate which is already equipped with the URL and the root directory of the server. With this template users can be authenticated as well as user data can be retrieved from the LDAP for use in the database.

findUserDn()

Logging in via LDAP is only possible with the full Distinguished-Name (DN) of the user. The DN is the full path from the server's root directory to the user's location. Since most users do not know their DN and it cannot be easily derived from the username, the user must be searched for in LDAP. findUserDn() uses the username (uid) of the user and searches starting from root for all objects which are assigned to the object class gifb-person and whose uid matches that of the user. The full DN of the user is returned.

getUserProperties()

The method getUserProperties() searches for the user just like findUserDn() starting from root, but returns not the DN but all attributes which are important for the AtlasUser. These are currently the full name and the email.

Atlas Authentication

The AtlasAuthentication is our implementation of the Spring interface Authentication. This interface provides some methods which are important for user management. The method isAuthenticated returns if a user is already successfully authenticated by the LDAPAuthenticationManager, setAuthenticated is used by the LDAPAuthenticationManager to set auhenticated to true. We also implement the methods getName, which returns the username of the user, getAuthorities, which returns a list of user roles, getCredentials, which, in the case of self-managed users returns the password encrypted by BCrypt and in the case of LDAP users returns null, and getDetails, which we do not use and therefore returns null. We also implement the getPrincipal method, which returns the logged in AtlasUser.

This class is used by Spring Security to manage the session of a user. It contains everything that is important for sessions: the user who is logged in, his roles and whether authentication via LDAP or database has taken place.

UserDetailsService

The UserDetailsService implements the Spring interface UserDetailsService. This provides a method loadUserByUsername, which is used by the LDAPAuthenticationManager to find the AtlasUser for a given username. This is done by looking into the database to see if a user with that username exists. If so, the roles of the user are pulled from the database and filled, and the password is pulled from the database and filled, or set to an empty string. In addition, it goes without saying that we do not store passwords in plain text. All passwords are encrypted with BCrypt, and are only stored or processed this way. We generally do not store LDAP passwords, the corresponding fields in the database are 'null'. This user is then returned.

AtlasUser

The AtlasUser represents a user of the learning platform. This user has the attributes user_id, name, username and email stored in the database. These attributes can be retrieved directly from the database using the UserRepository. In addition, the AtlasUser implements the UserDetails interface. The interface represents a user in Spring Security. This user can be accessed in controllers with the annotation @AuthenticationPrincipal, for example to check user roles. The interface requires some methods to be implemented: getAuthorities returns the user roles, in our case represented by the class Role, getPassword returns the password (encrypted by BCrypt) (here again the remark from above applies) and getUsername returns the user name. the methods isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired and isEnabled currently always return true, because we do not provide corresponding functions yet.

Role

A Role represents a role in ATLAS that is associated with corresponding permissions. The Role class implements the GrantedAuthority interface, which requires the getAuthority method to be implemented, which returns a string, in our case the name of the role. With the help of these roles we check in the controllers if a user is allowed to use certain functions.

SecurityConfig

The SecurityConfig configures properties of the HttpSecurity class. We deactivate CRSF to provide POST, PUT and DELETE. Also the LDAPAuthenticationManager and the AtlasAuthFilter are registered there. Afterwards it is defined that unregistered users only have access to the paths /login, /api/users (for registering), as well as the frontend and the API Doc. All other requests will only work after successful authentication. As a tool for authentication the path /login is set, so when you try to access a secured page you will be automatically redirected to /login, and /login is set as the path where the POST request with username and password is directed to.