Merge pull request 'security' (#9) from security into master
Reviewed-on: http://git.plannaplan.pl/filipizydorczyk/backend/pulls/9
This commit is contained in:
commit
579da3f038
@ -1,5 +1,7 @@
|
||||
package com.plannaplan.entities;
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
@ -14,11 +16,35 @@ public class User {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String surname;
|
||||
private String email;
|
||||
private UserRoles role;
|
||||
private String token;
|
||||
private Date tokenCreatedDate;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Date getTokenCreatedDate() {
|
||||
return tokenCreatedDate;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.tokenCreatedDate = new Date(System.currentTimeMillis());
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.plannaplan.exceptions;
|
||||
|
||||
public class UserNotFoundException extends Exception {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UserNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -3,9 +3,15 @@ package com.plannaplan.repositories;
|
||||
import com.plannaplan.entities.User;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
@Query("FROM User WHERE email = ?1")
|
||||
User getByAuthority(@Param("authority") String authority);
|
||||
|
||||
@Query("FROM User WHERE token = ?1")
|
||||
User getByToken(@Param("token") String token);
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package com.plannaplan.services;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.plannaplan.abstracts.EventWatcher;
|
||||
import com.plannaplan.entities.User;
|
||||
import com.plannaplan.exceptions.UserNotFoundException;
|
||||
import com.plannaplan.repositories.UserRepository;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -15,4 +19,27 @@ public class UserService extends EventWatcher {
|
||||
super();
|
||||
}
|
||||
|
||||
public String login(String authority) throws UserNotFoundException {
|
||||
User user = this.repo.getByAuthority(authority.replace("\n", "").trim());
|
||||
if (user == null) {
|
||||
throw new UserNotFoundException("Can not find user with given authority");
|
||||
}
|
||||
String token = UUID.randomUUID().toString();
|
||||
user.setToken(token);
|
||||
this.repo.save(user);
|
||||
return token;
|
||||
}
|
||||
|
||||
public void save(User user) {
|
||||
this.repo.save(user);
|
||||
}
|
||||
|
||||
public User getUserByEmail(String email) {
|
||||
return this.repo.getByAuthority(email.replace("\n", "").trim());
|
||||
}
|
||||
|
||||
public User getByToken(String token) {
|
||||
return this.repo.getByToken(token);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package com.plannaplan.types;
|
||||
|
||||
public enum UserRoles {
|
||||
STUDENT, DEANERY, ADMIN
|
||||
STUDENT, DEANERY, ADMIN, TEST_USER
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.plannaplan.services;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.plannaplan.entities.User;
|
||||
import com.plannaplan.exceptions.UserNotFoundException;
|
||||
import com.plannaplan.types.UserRoles;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@ContextConfiguration
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
public class UserServiceTest {
|
||||
public static String TEST_USER_MAIL = "noteexisitingmail@notexistingdomain.com";
|
||||
public static String TEST_USER_NAME = "Tom";
|
||||
public static String TEST_USER_SUERNAME = "Kovalsky";
|
||||
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
@Before
|
||||
public void initialize() {
|
||||
User testUser = new User();
|
||||
testUser.setEmail(TEST_USER_MAIL);
|
||||
testUser.setName(TEST_USER_NAME);
|
||||
testUser.setSurname(TEST_USER_SUERNAME);
|
||||
testUser.setRole(UserRoles.TEST_USER);
|
||||
this.userService.save(testUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnToken() {
|
||||
try {
|
||||
String token = this.userService.login(TEST_USER_MAIL);
|
||||
System.out.println("Returned token: " + token);
|
||||
assertTrue(token != null);
|
||||
assertTrue(this.userService.getUserByEmail(TEST_USER_MAIL).getToken() != null);
|
||||
} catch (UserNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowException() {
|
||||
try {
|
||||
this.userService.login("thiseamilisnotindatabase@gmail.com");
|
||||
assertTrue(false);
|
||||
} catch (UserNotFoundException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
37
docs/api.md
37
docs/api.md
@ -1,11 +1,12 @@
|
||||
# Dokumetacja API
|
||||
|
||||
| Api | Zadania endpointa |
|
||||
| ---------------------------------------------- | ---------------------------------------------------------- |
|
||||
| [/config](#config) | Załadowanie konfiguracji startowej do aplikacji PlanNaPlan |
|
||||
| [/getCoursesWithGroups](#getcourseswithgroups) | Zwrócenie wszytskich kursów razem z grupami |
|
||||
| [/getCourseGroups](#getcoursegroups) | Zwrócenie grup dla danego kursu |
|
||||
| [/getCourses](#getcourses) | Zwrócenie wszystkich kursów |
|
||||
| Api | Zadania endpointa |
|
||||
| ------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| [/api/v1/configurator/config](#config) | Załadowanie konfiguracji startowej do aplikacji PlanNaPlan |
|
||||
| [/api/v1/courses/getCoursesWithGroups](#getcourseswithgroups) | Zwrócenie wszytskich kursów razem z grupami |
|
||||
| [/api/v1/groups/getCourseGroups](#getcoursegroups) | Zwrócenie grup dla danego kursu |
|
||||
| [/api/v1/courses/getCourses](#getcourses) | Zwrócenie wszystkich kursów |
|
||||
| [/token](#token) | Wymienia ticket z CAS-a na token ktorym beda autoryzowane chronione requesty |
|
||||
|
||||
## config
|
||||
|
||||
@ -30,7 +31,7 @@ Endpoint konfigurujacy caly system i importujacy dane do bazy.
|
||||
Source code: [link](../restservice/src/main/java/com/plannaplan/controllers/getCoursesWithGroups.java)
|
||||
|
||||
```
|
||||
GET /getCoursesWithGroups
|
||||
GET /api/v1/courses/getCoursesWithGroups
|
||||
```
|
||||
|
||||
#### Opis
|
||||
@ -42,7 +43,7 @@ Zwraca wszystkie dostepne kursy wraz z listą grup.
|
||||
Source code: [link](../restservice/src/main/java/com/plannaplan/controllers/GroupController.java)
|
||||
|
||||
```
|
||||
GET /getCourseGroups
|
||||
GET /api/v1/groups/getCourseGroups
|
||||
```
|
||||
|
||||
#### Opis
|
||||
@ -61,9 +62,27 @@ Zwraca wszytskie grupy dla danego kursu.
|
||||
Source code: [link](../restservice/src/main/java/com/plannaplan/controllers/CoursesController.java)
|
||||
|
||||
```
|
||||
GET /getCourses
|
||||
GET /api/v1/courses/getCourses
|
||||
```
|
||||
|
||||
#### Opis
|
||||
|
||||
Zwraca wszystkie dostepne kursy.
|
||||
|
||||
## token
|
||||
|
||||
Source code: [link](../restservice/src/main/java/com/plannaplan/controllers/TokenController.java)
|
||||
|
||||
```
|
||||
GET /token?ticket=ST-668405-W0gfvSVDRBdMUWLweKzv-cas.amu.edu.pl
|
||||
```
|
||||
|
||||
#### Opis
|
||||
|
||||
Po odpytaniu tego endpointa z podanym ticketem system zrobi nma nim validate i dostanie uzytkownika dla ktorego zostal on wygenerowany. System utworzy dla niego access token i go zwroci w odpowiedzi
|
||||
|
||||
#### Parametry
|
||||
|
||||
| Type | Name | Consumes | Opis | Type |
|
||||
| ----------- | ------------------------- | -------- | --------------------------------------- | ------ |
|
||||
| Query Param | **ticket** </br> required | - | ticket uzyskany z logowania poprzez CAS | string |
|
||||
|
@ -31,11 +31,23 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<version>2.3.3.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
@ -48,6 +60,12 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<artifactId>buisnesslogic</artifactId>
|
||||
<groupId>com.plannaplan</groupId>
|
||||
|
@ -1,15 +1,38 @@
|
||||
package com.plannaplan;
|
||||
|
||||
import com.plannaplan.entities.User;
|
||||
import com.plannaplan.services.UserService;
|
||||
import com.plannaplan.types.UserRoles;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
@SpringBootApplication
|
||||
public class App {
|
||||
|
||||
public final static String API_VERSION = "v1";
|
||||
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Logo logo = new Logo("beta");
|
||||
System.out.println(logo.getLogo());
|
||||
System.out.println("|=============================================================================================|");
|
||||
System.out.println(
|
||||
"|=============================================================================================|");
|
||||
SpringApplication.run(App.class, args);
|
||||
}
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void importData() {
|
||||
User testUser = new User();
|
||||
testUser.setEmail("filizy@st.amu.edu.pl");
|
||||
testUser.setName("Filip");
|
||||
testUser.setSurname("Izydorczyk");
|
||||
testUser.setRole(UserRoles.STUDENT);
|
||||
this.userService.save(testUser);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.plannaplan.App;
|
||||
import com.plannaplan.Controller;
|
||||
import com.plannaplan.models.ConfigData;
|
||||
|
||||
@ -12,11 +13,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/api/" + App.API_VERSION + "/configurator")
|
||||
public class ConfigController {
|
||||
|
||||
@Autowired
|
||||
|
@ -5,6 +5,7 @@ import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import com.plannaplan.App;
|
||||
import com.plannaplan.entities.Course;
|
||||
import com.plannaplan.entities.Groups;
|
||||
import com.plannaplan.services.CourseService;
|
||||
@ -15,38 +16,40 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/api/" + App.API_VERSION + "/courses")
|
||||
public class CoursesController {
|
||||
@Autowired
|
||||
private CourseService courseService;
|
||||
|
||||
@GetMapping("/getCourses")
|
||||
public ResponseEntity<List<Dictionary<String,Object>>> getMethodName() {
|
||||
public ResponseEntity<List<Dictionary<String, Object>>> getMethodName() {
|
||||
List<Course> courses = this.courseService.getAllCourses();
|
||||
List<Dictionary<String,Object>> response = new ArrayList<>();
|
||||
for(Course c : courses){
|
||||
List<Dictionary<String, Object>> response = new ArrayList<>();
|
||||
for (Course c : courses) {
|
||||
Dictionary<String, Object> element = new Hashtable<>();
|
||||
element.put("id", c.getId());
|
||||
element.put("name",c.getName());
|
||||
element.put("name", c.getName());
|
||||
response.add(element);
|
||||
}
|
||||
|
||||
|
||||
return new ResponseEntity<>(response, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getCoursesWithGroups")
|
||||
public ResponseEntity<List<Dictionary<String,Object>>> getCoursesWithGroups() {
|
||||
public ResponseEntity<List<Dictionary<String, Object>>> getCoursesWithGroups() {
|
||||
List<Course> courses = this.courseService.getAllCourses();
|
||||
List<Dictionary<String,Object>> response = new ArrayList<>();
|
||||
for(Course c : courses){
|
||||
List<Dictionary<String, Object>> response = new ArrayList<>();
|
||||
for (Course c : courses) {
|
||||
Dictionary<String, Object> element = new Hashtable<>();
|
||||
element.put("id", c.getId());
|
||||
element.put("name",c.getName());
|
||||
List<Dictionary<String,Object>> groups = new ArrayList<>();
|
||||
for(Groups g : c.getGroups()){
|
||||
Dictionary<String,Object> group = new Hashtable<>();
|
||||
element.put("name", c.getName());
|
||||
List<Dictionary<String, Object>> groups = new ArrayList<>();
|
||||
for (Groups g : c.getGroups()) {
|
||||
Dictionary<String, Object> group = new Hashtable<>();
|
||||
group.put("id", g.getId());
|
||||
group.put("day", g.getDay().label);
|
||||
group.put("time", g.getTimeString());
|
||||
@ -55,11 +58,11 @@ public class CoursesController {
|
||||
group.put("type", g.getType());
|
||||
groups.add(group);
|
||||
}
|
||||
|
||||
|
||||
element.put("groups", groups);
|
||||
response.add(element);
|
||||
}
|
||||
|
||||
|
||||
return new ResponseEntity<>(response, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import com.plannaplan.App;
|
||||
import com.plannaplan.entities.Groups;
|
||||
import com.plannaplan.services.GroupService;
|
||||
|
||||
@ -13,21 +14,23 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/api/" + App.API_VERSION + "/groups")
|
||||
public class GroupController {
|
||||
@Autowired
|
||||
private GroupService groupService;
|
||||
|
||||
@GetMapping("/getCourseGroups")
|
||||
public ResponseEntity<List<Dictionary<String, Object>>> getCourses(@RequestParam("id") Long id, @RequestParam(name="capacity", defaultValue="true") Boolean capacity){
|
||||
public ResponseEntity<List<Dictionary<String, Object>>> getCourses(@RequestParam("id") Long id,
|
||||
@RequestParam(name = "capacity", defaultValue = "true") Boolean capacity) {
|
||||
List<Groups> groups = this.groupService.getGroupsByCourse(id);
|
||||
List<Dictionary<String, Object>> response = new ArrayList<>();
|
||||
|
||||
|
||||
for (Groups g : groups) {
|
||||
Dictionary<String, Object> group = new Hashtable<>();
|
||||
group.put("id", g.getId());
|
||||
@ -37,7 +40,7 @@ public class GroupController {
|
||||
group.put("room", g.getRoom());
|
||||
if (capacity) {
|
||||
group.put("capacity", g.getCapacity());
|
||||
}
|
||||
}
|
||||
group.put("type", g.getType());
|
||||
|
||||
response.add(group);
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.plannaplan.controllers;
|
||||
|
||||
import com.plannaplan.exceptions.UserNotFoundException;
|
||||
import com.plannaplan.security.CasValidationExcepiton;
|
||||
import com.plannaplan.security.CasValidator;
|
||||
import com.plannaplan.services.UserService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
public class TokenController {
|
||||
|
||||
public static String SERVICE_URL = "http://localhost:3000";
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/token")
|
||||
public ResponseEntity<String> getToken(@RequestParam("ticket") final String ticket) {
|
||||
CasValidator validator = new CasValidator(SERVICE_URL, ticket);
|
||||
|
||||
try {
|
||||
String authority = validator.validate();
|
||||
String token = this.userService.login(authority);
|
||||
return new ResponseEntity<>(token, HttpStatus.OK);
|
||||
} catch (CasValidationExcepiton e) {
|
||||
return new ResponseEntity<>("Wrong ticket", HttpStatus.UNAUTHORIZED);
|
||||
} catch (UserNotFoundException e) {
|
||||
return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
|
||||
|
||||
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
AuthenticationFilter(final RequestMatcher requiresAuth) {
|
||||
super(requiresAuth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException, ServletException {
|
||||
|
||||
String token = request.getHeader(AUTHORIZATION);
|
||||
if (token == null) {
|
||||
token = "";
|
||||
} else {
|
||||
token = StringUtils.removeStart(token, "Bearer").trim();
|
||||
}
|
||||
Authentication requestAuthentication = new UsernamePasswordAuthenticationToken(token, token);
|
||||
return getAuthenticationManager().authenticate(requestAuthentication);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final FilterChain chain, final Authentication authResult) throws IOException, ServletException {
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.plannaplan.entities.User;
|
||||
import com.plannaplan.services.UserService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
String token = authentication.getCredentials().toString();
|
||||
|
||||
User user = this.userService.getByToken(token);
|
||||
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException("Cannot find user with authentication token=" + token);
|
||||
}
|
||||
|
||||
UserDetails response = new UserDetails() {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return user.getName() + " " + user.getSurname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
public class CasValidationExcepiton extends RuntimeException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CasValidationExcepiton(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
public class CasValidator {
|
||||
private static String CAS_URL = "https://cas.amu.edu.pl/cas";
|
||||
private final CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
private String service;
|
||||
private String ticket;
|
||||
|
||||
public CasValidator(String service, String ticket) {
|
||||
this.service = service;
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
public String validate() throws Exception, CasValidationExcepiton{
|
||||
HttpGet request = new HttpGet(CasValidator.CAS_URL + "/validate?service="
|
||||
+ URLEncoder.encode(this.service, "UTF-8") + "&ticket=" + URLEncoder.encode(this.ticket, "UTF-8"));
|
||||
try (CloseableHttpResponse response = httpClient.execute(request)) {
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
String result = null;
|
||||
if (entity != null) {
|
||||
// return it as a String
|
||||
result = EntityUtils.toString(entity);
|
||||
if(result.replace("\n", "").trim().equals("no")){
|
||||
throw new CasValidationExcepiton("Validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
String res = result.substring(result.indexOf('\n') + 1);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(new AntPathRequestMatcher("/api/**"));
|
||||
|
||||
AuthenticationProvider provider;
|
||||
|
||||
public WebSecurityConfig(final AuthenticationProvider authenticationProvider) {
|
||||
super();
|
||||
this.provider = authenticationProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) {
|
||||
auth.authenticationProvider(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final WebSecurity webSecurity) {
|
||||
webSecurity.ignoring().antMatchers("/token**").antMatchers("/api/v1/courses/getCourses")
|
||||
.antMatchers("/api/v1/groups/getCourseGroups").antMatchers("/api/v1/courses/getCoursesWithGroups");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable().formLogin().disable().httpBasic().disable().logout().disable().sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().exceptionHandling().and()
|
||||
.authenticationProvider(provider)
|
||||
.addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class).authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
|
||||
}
|
||||
|
||||
AuthenticationFilter authenticationFilter() throws Exception {
|
||||
final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
|
||||
filter.setAuthenticationManager(authenticationManager());
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationEntryPoint forbiddenEntryPoint() {
|
||||
return new HttpStatusEntryPoint(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.plannaplan.security;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CasValidatorTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void shouldValidateTicket() {
|
||||
//you need to privide fresh ticket to make this test pass that's why it is marked as ignored
|
||||
CasValidator validator = new CasValidator("http://localhost:3000",
|
||||
"ST-572267-cbgKrcJLd0tdCubeLqdW-cas.amu.edu.pl");
|
||||
try {
|
||||
System.out.println(validator.validate());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotValidateTicket() {
|
||||
//you need to privide fresh ticket to make this test pass that's why it is marked as ignored
|
||||
CasValidator validator = new CasValidator("http://localhost:3000",
|
||||
"notticket");
|
||||
try {
|
||||
assertTrue(validator.validate().trim().equals(""));
|
||||
}
|
||||
catch (CasValidationExcepiton e){
|
||||
assertTrue(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user