diff --git a/pom.xml b/pom.xml index 38c19e5..f11fb7d 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,18 @@ org.springframework.boot spring-boot-starter-data-jpa - + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.ldap + spring-ldap-core + + + org.springframework.security + spring-security-ldap + org.springframework.boot spring-boot-starter-validation diff --git a/src/main/java/com/primefactorsolutions/config/SecurityConfig.java b/src/main/java/com/primefactorsolutions/config/SecurityConfig.java new file mode 100644 index 0000000..a154390 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/config/SecurityConfig.java @@ -0,0 +1,38 @@ +package com.primefactorsolutions.config; + +import com.primefactorsolutions.views.LoginView; +import com.vaadin.flow.spring.security.VaadinWebSecurity; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.ldap.LdapBindAuthenticationManagerFactory; +import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +@EnableWebSecurity +@Configuration +public class SecurityConfig extends VaadinWebSecurity { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(auth -> + auth.requestMatchers( + AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/images/*.png")).permitAll()); + super.configure(http); + setLoginView(http, LoginView.class); + } + + @Bean + public AuthenticationManager authenticationManager() { + DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ldap.primefactorsolutions.com:389/dc=primefactorsolutions,dc=com"); + contextSource.setCacheEnvironmentProperties(false); + LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource); + factory.setUserDnPatterns("uid={0},ou=users"); + + return factory.createAuthenticationManager(); + } +} + diff --git a/src/main/java/com/primefactorsolutions/service/QuestionService.java b/src/main/java/com/primefactorsolutions/service/QuestionService.java index e2e6006..3b09775 100644 --- a/src/main/java/com/primefactorsolutions/service/QuestionService.java +++ b/src/main/java/com/primefactorsolutions/service/QuestionService.java @@ -6,13 +6,22 @@ import lombok.Data; import org.springframework.stereotype.Service; import java.util.List; +import java.util.UUID; @Service @Data public class QuestionService { private final QuestionRepository questionRepository; + public Question getQuestion(UUID id) { + return questionRepository.findById(id).get(); + } + public List getQuestions() { return questionRepository.findAll(); } + + public void createOrUpdate(Question question) { + questionRepository.save(question); + } } diff --git a/src/main/java/com/primefactorsolutions/views/AssessmentView.java b/src/main/java/com/primefactorsolutions/views/AssessmentView.java index cddcfa3..1b17dcd 100644 --- a/src/main/java/com/primefactorsolutions/views/AssessmentView.java +++ b/src/main/java/com/primefactorsolutions/views/AssessmentView.java @@ -15,6 +15,7 @@ import com.vaadin.flow.router.HasUrlParameter; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.fields.SubListSelector; @@ -24,6 +25,7 @@ import java.util.List; import java.util.UUID; @SpringComponent +@PermitAll @Scope("prototype") @PageTitle("Assessments") @Route(value = "/assessments", layout = MainLayout.class) diff --git a/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java b/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java index 0a146a7..8455b84 100644 --- a/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java +++ b/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java @@ -14,6 +14,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.addon.stefan.clipboard.ClientsideClipboard; import org.vaadin.firitin.components.grid.VGrid; @@ -24,6 +25,7 @@ import java.util.stream.Stream; @Scope("prototype") @PageTitle("Assessments") @Route(value = "/assessments", layout = MainLayout.class) +@PermitAll public class AssessmentsListView extends Main { public AssessmentsListView(final AssessmentService assessmentService) { diff --git a/src/main/java/com/primefactorsolutions/views/EvaluationCompletedView.java b/src/main/java/com/primefactorsolutions/views/EvaluationCompletedView.java deleted file mode 100644 index 5e4ee89..0000000 --- a/src/main/java/com/primefactorsolutions/views/EvaluationCompletedView.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.primefactorsolutions.views; - -import com.vaadin.flow.component.Text; -import com.vaadin.flow.component.html.Main; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; - -@PageTitle("Assessment") -@Route(value = "/evaluation/completed", layout = MainLayout.class) -public class EvaluationCompletedView extends Main { - public EvaluationCompletedView() { - add(new Text("La evaluacion ha sido completada. Nos contactaremos con usted.")); - } -} diff --git a/src/main/java/com/primefactorsolutions/views/EvaluationView.java b/src/main/java/com/primefactorsolutions/views/EvaluationView.java index 90b57e8..ee9e516 100644 --- a/src/main/java/com/primefactorsolutions/views/EvaluationView.java +++ b/src/main/java/com/primefactorsolutions/views/EvaluationView.java @@ -25,6 +25,7 @@ import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.*; +import com.vaadin.flow.server.auth.AnonymousAllowed; import com.vaadin.flow.spring.annotation.SpringComponent; import com.vaadin.flow.theme.lumo.LumoUtility.Background; import com.vaadin.flow.theme.lumo.LumoUtility.BoxSizing; @@ -53,6 +54,7 @@ import java.util.stream.Collectors; @SpringComponent @Scope("prototype") @Route(value = "/evaluation", layout = MainLayout.class) +@AnonymousAllowed public class EvaluationView extends Main implements HasUrlParameter { final CompilerService compilerService; diff --git a/src/main/java/com/primefactorsolutions/views/LoginView.java b/src/main/java/com/primefactorsolutions/views/LoginView.java new file mode 100644 index 0000000..00942bb --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/LoginView.java @@ -0,0 +1,41 @@ +package com.primefactorsolutions.views; + +import com.vaadin.flow.component.html.H1; +import com.vaadin.flow.component.login.LoginForm; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.server.auth.AnonymousAllowed; + +@Route("login") +@PageTitle("PFS Recruiting") +@AnonymousAllowed +public class LoginView extends VerticalLayout implements BeforeEnterObserver { + + private final LoginForm login = new LoginForm(); + + public LoginView() { + addClassName("login-view"); + setSizeFull(); + setAlignItems(Alignment.CENTER); + setJustifyContentMode(JustifyContentMode.CENTER); + + login.setAction("login"); + + add(new H1("PFS Recruiting")); + add(login); + } + + @Override + public void beforeEnter(final BeforeEnterEvent beforeEnterEvent) { + // inform the user about an authentication error + if (beforeEnterEvent.getLocation() + .getQueryParameters() + .getParameters() + .containsKey("error")) { + login.setError(true); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/views/MainView.java b/src/main/java/com/primefactorsolutions/views/MainView.java index 0ca481c..2d219d7 100644 --- a/src/main/java/com/primefactorsolutions/views/MainView.java +++ b/src/main/java/com/primefactorsolutions/views/MainView.java @@ -4,9 +4,11 @@ import com.vaadin.flow.component.Text; import com.vaadin.flow.component.html.Main; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; @PageTitle("Assessment") @Route(value = "", layout = MainLayout.class) +@PermitAll public class MainView extends Main { public MainView() { add(new Text("welcome")); diff --git a/src/main/java/com/primefactorsolutions/views/QuestionView.java b/src/main/java/com/primefactorsolutions/views/QuestionView.java new file mode 100644 index 0000000..31aab82 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/QuestionView.java @@ -0,0 +1,63 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.Question; +import com.primefactorsolutions.service.QuestionService; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.textfield.TextArea; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.router.BeforeEvent; +import com.vaadin.flow.router.HasUrlParameter; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.annotation.Scope; +import org.vaadin.firitin.form.BeanValidationForm; + +import java.util.List; +import java.util.UUID; + +@SpringComponent +@Scope("prototype") +@PageTitle("Assessments") +@Route(value = "/questions", layout = MainLayout.class) +@PermitAll +public class QuestionView extends BeanValidationForm implements HasUrlParameter { + private final QuestionService questionService; + + private TextField title = null; + private TextArea description = null; + private TextArea content = null; + + public QuestionView(final QuestionService questionService) { + super(Question.class); + this.questionService = questionService; + title = new TextField(); + title.setLabel("Title"); + + description = new TextArea(); + description.setLabel("Description"); + + content = new TextArea(); + content.setLabel("Content"); + + setSavedHandler((SavedHandler) questionService::createOrUpdate); + } + + + @Override + public void setParameter(final BeforeEvent beforeEvent, final String s) { + if (StringUtils.isNotBlank(s) && !"new".equals(s)) { + var user = questionService.getQuestion(UUID.fromString(s)); + setEntityWithEnabledSave(user); + } else { + setEntityWithEnabledSave(new Question()); + } + } + + @Override + protected List getFormComponents() { + return List.of(title, description, content); + } +} diff --git a/src/main/java/com/primefactorsolutions/views/QuestionsListView.java b/src/main/java/com/primefactorsolutions/views/QuestionsListView.java new file mode 100644 index 0000000..4f4775a --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/QuestionsListView.java @@ -0,0 +1,71 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.AppUser; +import com.primefactorsolutions.model.Question; +import com.primefactorsolutions.service.QuestionService; +import com.primefactorsolutions.service.UserService; +import com.vaadin.flow.component.html.Main; +import com.vaadin.flow.data.provider.DataProvider; +import com.vaadin.flow.data.provider.DataProviderListener; +import com.vaadin.flow.data.provider.Query; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.shared.Registration; +import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; +import org.springframework.context.annotation.Scope; +import org.vaadin.firitin.components.grid.VGrid; + +import java.util.stream.Stream; + +@SpringComponent +@Scope("prototype") +@PageTitle("Questions") +@Route(value = "/questions", layout = MainLayout.class) +@PermitAll +public class QuestionsListView extends Main { + final QuestionService questionService; + + public QuestionsListView(final QuestionService questionService) { + this.questionService = questionService; + final VGrid grid = new VGrid<>(Question.class); + grid.setColumns("id", "title"); + + grid.setDataProvider(new DataProvider<>() { + @Override + public boolean isInMemory() { + return false; + } + + @Override + public int size(Query query) { + return questionService.getQuestions().size(); + } + + @Override + public Stream fetch(Query query) { + int limit = query.getLimit(); + int pagerSize = query.getPageSize(); + int page = query.getPage(); + return questionService.getQuestions().stream(); + } + + @Override + public void refreshItem(Question question) { + + } + + @Override + public void refreshAll() { + + } + + @Override + public Registration addDataProviderListener(DataProviderListener dataProviderListener) { + return null; + } + }); + + add(grid); + } +} diff --git a/src/main/java/com/primefactorsolutions/views/UserView.java b/src/main/java/com/primefactorsolutions/views/UserView.java index 8d9afef..4f2c3ee 100644 --- a/src/main/java/com/primefactorsolutions/views/UserView.java +++ b/src/main/java/com/primefactorsolutions/views/UserView.java @@ -9,6 +9,7 @@ import com.vaadin.flow.router.HasUrlParameter; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.form.BeanValidationForm; @@ -20,6 +21,7 @@ import java.util.UUID; @Scope("prototype") @PageTitle("Assessments") @Route(value = "/users", layout = MainLayout.class) +@PermitAll public class UserView extends BeanValidationForm implements HasUrlParameter { private final UserService userService; diff --git a/src/main/java/com/primefactorsolutions/views/UsersListView.java b/src/main/java/com/primefactorsolutions/views/UsersListView.java index 561f30d..f102344 100644 --- a/src/main/java/com/primefactorsolutions/views/UsersListView.java +++ b/src/main/java/com/primefactorsolutions/views/UsersListView.java @@ -10,6 +10,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.components.grid.VGrid; @@ -20,6 +21,7 @@ import java.util.stream.Stream; @Scope("prototype") @PageTitle("Users") @Route(value = "/users", layout = MainLayout.class) +@PermitAll public class UsersListView extends Main { final UserService userService;