Index: sources/app/src/main/java/parkup/configs/PasswordEncoder.java
===================================================================
--- sources/app/src/main/java/parkup/configs/PasswordEncoder.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/PasswordEncoder.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,14 @@
+package parkup.configs;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+@Configuration
+public class PasswordEncoder {
+    @Bean
+    public BCryptPasswordEncoder bCryptPasswordEncoder(){
+        return new BCryptPasswordEncoder();
+    }
+
+}
Index: sources/app/src/main/java/parkup/configs/RegistrationController.java
===================================================================
--- sources/app/src/main/java/parkup/configs/RegistrationController.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/RegistrationController.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,23 @@
+//package parkup.configs;
+//
+//import org.springframework.web.bind.annotation.*;
+//
+//@RestController
+//public class RegistrationController {
+//
+//    private final RegistrationService registrationService;
+//
+//    public RegistrationController(RegistrationService registrationService) {
+//        this.registrationService = registrationService;
+//    }
+//
+//    @PostMapping(path = "/registration")
+//    public String register(@RequestBody RegistrationRequest request) {
+//        return registrationService.register(request);
+//    }
+//
+//    @GetMapping(path = "/registration/confirm")
+//    public String confirm(@RequestParam("token") String token) {
+//        return registrationService.confirmToken(token);
+//    }
+//}
Index: sources/app/src/main/java/parkup/configs/RegistrationRequest.java
===================================================================
--- sources/app/src/main/java/parkup/configs/RegistrationRequest.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/RegistrationRequest.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,32 @@
+package parkup.configs;
+
+public class RegistrationRequest {
+    private final String firstName;
+    private final String lastName;
+    private final String email;
+    private final String password;
+
+    public RegistrationRequest(String firstName, String lastName, String email, String password) {
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.email = email;
+        this.password = password;
+    }
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+}
Index: sources/app/src/main/java/parkup/configs/RegistrationService.java
===================================================================
--- sources/app/src/main/java/parkup/configs/RegistrationService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/RegistrationService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,147 @@
+package parkup.configs;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import parkup.configs.email.EmailSender;
+import parkup.configs.email.EmailValidator;
+import parkup.configs.token.ConfirmationToken;
+import parkup.configs.token.ConfirmationTokenService;
+import parkup.entities.Administrator;
+import parkup.services.AdministratorService;
+
+import javax.transaction.Transactional;
+import java.time.LocalDateTime;
+
+@Service
+public class RegistrationService {
+    private final AdministratorService administratorService;
+    private final EmailValidator emailValidator;
+    private final ConfirmationTokenService confirmationTokenService;
+    private final EmailSender emailSender;
+
+    @Autowired
+    public RegistrationService(AdministratorService administratorService, EmailValidator emailValidator,
+                               ConfirmationTokenService confirmationTokenService, EmailSender emailSender) {
+        this.administratorService = administratorService;
+        this.emailValidator = emailValidator;
+        this.confirmationTokenService = confirmationTokenService;
+        this.emailSender = emailSender;
+    }
+
+    public String register(RegistrationRequest request) {
+        boolean isValidEmail = emailValidator.
+                test(request.getEmail());
+
+        if (!isValidEmail) {
+            throw new IllegalStateException("email not valid");
+        }
+
+        String token = administratorService.signUpAdministrator(
+                new Administrator(
+                        request.getFirstName(),
+                        request.getLastName(),
+                        request.getEmail(),
+                        request.getPassword()
+                )
+        );
+
+        String link = "http://localhost:8080/administrator/registration/confirm?token=" + token;
+        emailSender.send(
+                request.getEmail(),
+                buildEmail(request.getFirstName(), link));
+
+        return token;
+    }
+
+    @Transactional
+    public String confirmToken(String token) {
+        ConfirmationToken confirmationToken = confirmationTokenService
+                .getToken(token)
+                .orElseThrow(() ->
+                        new IllegalStateException("token not found"));
+
+        if (confirmationToken.getConfirmedAt() != null) {
+            throw new IllegalStateException("email already confirmed");
+        }
+
+        LocalDateTime expiredAt = confirmationToken.getExpiresAt();
+
+        if (expiredAt.isBefore(LocalDateTime.now())) {
+            throw new IllegalStateException("token expired");
+        }
+
+        confirmationTokenService.setConfirmedAt(token);
+
+        administratorService.enableAdministrator(confirmationToken.getAdministrator().getEmail());
+        return "confirmed";
+    }
+
+    private String buildEmail(String name, String link) {
+        return "<div style=\"font-family:Helvetica,Arial,sans-serif;font-size:16px;margin:0;color:#0b0c0c\">\n" +
+                "\n" +
+                "<span style=\"display:none;font-size:1px;color:#fff;max-height:0\"></span>\n" +
+                "\n" +
+                "  <table role=\"presentation\" width=\"100%\" style=\"border-collapse:collapse;min-width:100%;width:100%!important\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
+                "    <tbody><tr>\n" +
+                "      <td width=\"100%\" height=\"53\" bgcolor=\"#0b0c0c\">\n" +
+                "        \n" +
+                "        <table role=\"presentation\" width=\"100%\" style=\"border-collapse:collapse;max-width:580px\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" align=\"center\">\n" +
+                "          <tbody><tr>\n" +
+                "            <td width=\"70\" bgcolor=\"#0b0c0c\" valign=\"middle\">\n" +
+                "                <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-collapse:collapse\">\n" +
+                "                  <tbody><tr>\n" +
+                "                    <td style=\"padding-left:10px\">\n" +
+                "                  \n" +
+                "                    </td>\n" +
+                "                    <td style=\"font-size:28px;line-height:1.315789474;Margin-top:4px;padding-left:10px\">\n" +
+                "                      <span style=\"font-family:Helvetica,Arial,sans-serif;font-weight:700;color:#ffffff;text-decoration:none;vertical-align:top;display:inline-block\">Confirm your email</span>\n" +
+                "                    </td>\n" +
+                "                  </tr>\n" +
+                "                </tbody></table>\n" +
+                "              </a>\n" +
+                "            </td>\n" +
+                "          </tr>\n" +
+                "        </tbody></table>\n" +
+                "        \n" +
+                "      </td>\n" +
+                "    </tr>\n" +
+                "  </tbody></table>\n" +
+                "  <table role=\"presentation\" class=\"m_-6186904992287805515content\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-collapse:collapse;max-width:580px;width:100%!important\" width=\"100%\">\n" +
+                "    <tbody><tr>\n" +
+                "      <td width=\"10\" height=\"10\" valign=\"middle\"></td>\n" +
+                "      <td>\n" +
+                "        \n" +
+                "                <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-collapse:collapse\">\n" +
+                "                  <tbody><tr>\n" +
+                "                    <td bgcolor=\"#1D70B8\" width=\"100%\" height=\"10\"></td>\n" +
+                "                  </tr>\n" +
+                "                </tbody></table>\n" +
+                "        \n" +
+                "      </td>\n" +
+                "      <td width=\"10\" valign=\"middle\" height=\"10\"></td>\n" +
+                "    </tr>\n" +
+                "  </tbody></table>\n" +
+                "\n" +
+                "\n" +
+                "\n" +
+                "  <table role=\"presentation\" class=\"m_-6186904992287805515content\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-collapse:collapse;max-width:580px;width:100%!important\" width=\"100%\">\n" +
+                "    <tbody><tr>\n" +
+                "      <td height=\"30\"><br></td>\n" +
+                "    </tr>\n" +
+                "    <tr>\n" +
+                "      <td width=\"10\" valign=\"middle\"><br></td>\n" +
+                "      <td style=\"font-family:Helvetica,Arial,sans-serif;font-size:19px;line-height:1.315789474;max-width:560px\">\n" +
+                "        \n" +
+                "            <p style=\"Margin:0 0 20px 0;font-size:19px;line-height:25px;color:#0b0c0c\">Hi " + name + ",</p><p style=\"Margin:0 0 20px 0;font-size:19px;line-height:25px;color:#0b0c0c\"> Thank you for registering. Please click on the below link to activate your account: </p><blockquote style=\"Margin:0 0 20px 0;border-left:10px solid #b1b4b6;padding:15px 0 0.1px 15px;font-size:19px;line-height:25px\"><p style=\"Margin:0 0 20px 0;font-size:19px;line-height:25px;color:#0b0c0c\"> <a href=\"" + link + "\">Activate Now</a> </p></blockquote>\n Link will expire in 15 minutes. <p>See you soon</p>" +
+                "        \n" +
+                "      </td>\n" +
+                "      <td width=\"10\" valign=\"middle\"><br></td>\n" +
+                "    </tr>\n" +
+                "    <tr>\n" +
+                "      <td height=\"30\"><br></td>\n" +
+                "    </tr>\n" +
+                "  </tbody></table><div class=\"yj6qo\"></div><div class=\"adL\">\n" +
+                "\n" +
+                "</div></div>";
+    }
+}
Index: sources/app/src/main/java/parkup/configs/WebSecurityConfig.java
===================================================================
--- sources/app/src/main/java/parkup/configs/WebSecurityConfig.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/WebSecurityConfig.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,49 @@
+package parkup.configs;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+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.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import parkup.services.AdministratorService;
+
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+    private final AdministratorService administratorService;
+    private final BCryptPasswordEncoder bCryptPasswordEncoder;
+
+    public WebSecurityConfig(AdministratorService administratorService, BCryptPasswordEncoder bCryptPasswordEncoder) {
+        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
+        this.administratorService = administratorService;
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                .csrf().disable()
+                .authorizeRequests()
+                    .antMatchers("/administrator/registration/**")
+                    .permitAll()
+                .anyRequest()
+                .authenticated().and()
+                .formLogin();
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+        auth.authenticationProvider(daoAuthenticationProvider());
+    }
+
+    @Bean
+    public DaoAuthenticationProvider daoAuthenticationProvider(){
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setPasswordEncoder(bCryptPasswordEncoder);
+        provider.setUserDetailsService(administratorService);
+        return provider;
+    }
+}
Index: sources/app/src/main/java/parkup/configs/email/EmailSender.java
===================================================================
--- sources/app/src/main/java/parkup/configs/email/EmailSender.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/email/EmailSender.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,5 @@
+package parkup.configs.email;
+
+public interface EmailSender {
+    void send(String to, String email);
+}
Index: sources/app/src/main/java/parkup/configs/email/EmailService.java
===================================================================
--- sources/app/src/main/java/parkup/configs/email/EmailService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/email/EmailService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,41 @@
+package parkup.configs.email;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+@Service
+public class EmailService implements EmailSender{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(EmailService.class);
+    private final JavaMailSender mailSender;
+
+    public EmailService(JavaMailSender mailSender) {
+        this.mailSender = mailSender;
+    }
+
+    @Override
+    @Async
+    public void send(String to, String email) {
+        try {
+            MimeMessage mimeMessage = mailSender.createMimeMessage();
+            MimeMessageHelper helper =
+                    new MimeMessageHelper(mimeMessage, "utf-8");
+            helper.setText(email, true);
+            helper.setTo(to);
+            helper.setSubject("Confirm your email");
+            helper.setFrom("parkup@gmail.com");
+            mailSender.send(mimeMessage);
+        } catch (MessagingException e) {
+            LOGGER.error("failed to send email", e);
+            throw new IllegalStateException("failed to send email");
+        }
+    }
+}
+
Index: sources/app/src/main/java/parkup/configs/email/EmailValidator.java
===================================================================
--- sources/app/src/main/java/parkup/configs/email/EmailValidator.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/email/EmailValidator.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,14 @@
+package parkup.configs.email;
+
+import org.springframework.stereotype.Service;
+
+import java.util.function.Predicate;
+
+@Service
+public class EmailValidator implements Predicate<String> {
+    @Override
+    public boolean test(String s) {
+        //todo
+        return true;
+    }
+}
Index: sources/app/src/main/java/parkup/configs/token/ConfirmationToken.java
===================================================================
--- sources/app/src/main/java/parkup/configs/token/ConfirmationToken.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/token/ConfirmationToken.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,105 @@
+package parkup.configs.token;
+
+import parkup.entities.Administrator;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+public class ConfirmationToken {
+
+    @Id
+    @Column(name = "confirmation_token_id")
+    @SequenceGenerator(
+            name="confirmation_token_generator",
+            sequenceName = "confirmation_token_sequence",
+            allocationSize = 1,
+            initialValue = 900
+    )
+    @GeneratedValue(    //za postgres treba sequence da se namesti i ime na generator mi ga davamo kako od gore sto e
+            strategy = GenerationType.SEQUENCE,
+            generator = "confirmation_token_sequence_generator"
+    )
+    private int id;
+
+    @Column(nullable = false)
+    private String token;
+
+    @Column(nullable = false)
+    private LocalDateTime createdAt;
+
+    @Column(nullable = false)
+    private LocalDateTime expiresAt;
+
+    private LocalDateTime confirmedAt;
+
+    @ManyToOne
+    @JoinColumn(nullable = false, name = "administrator_id")
+    //many confirmation tokens to one administrator
+    private Administrator administrator;
+
+    public ConfirmationToken() {}
+
+    public ConfirmationToken(int id, String token, LocalDateTime createdAt, LocalDateTime expiresAt, Administrator administrator) {
+        this.id = id;
+        this.token = token;
+        this.createdAt = createdAt;
+        this.expiresAt = expiresAt;
+        this.administrator = administrator;
+    }
+
+    public ConfirmationToken(String token, LocalDateTime createdAt, LocalDateTime expiresAt, Administrator administrator) {
+        this.token = token;
+        this.createdAt = createdAt;
+        this.expiresAt = expiresAt;
+        this.administrator = administrator;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public LocalDateTime getCreatedAt() {
+        return createdAt;
+    }
+
+    public void setCreatedAt(LocalDateTime createdAt) {
+        this.createdAt = createdAt;
+    }
+
+    public LocalDateTime getExpiresAt() {
+        return expiresAt;
+    }
+
+    public void setExpiresAt(LocalDateTime expiresAt) {
+        this.expiresAt = expiresAt;
+    }
+
+    public LocalDateTime getConfirmedAt() {
+        return confirmedAt;
+    }
+
+    public void setConfirmedAt(LocalDateTime confirmedAt) {
+        this.confirmedAt = confirmedAt;
+    }
+
+    public Administrator getAdministrator() {
+        return administrator;
+    }
+
+    public void setAdministrator(Administrator administrator) {
+        this.administrator = administrator;
+    }
+}
Index: sources/app/src/main/java/parkup/configs/token/ConfirmationTokenRepository.java
===================================================================
--- sources/app/src/main/java/parkup/configs/token/ConfirmationTokenRepository.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/token/ConfirmationTokenRepository.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,23 @@
+package parkup.configs.token;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import javax.transaction.Transactional;
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Repository
+public interface ConfirmationTokenRepository extends JpaRepository<ConfirmationToken,Integer> {
+
+    Optional<ConfirmationToken> findByToken(String token);
+
+    @Transactional
+    @Modifying
+    @Query("UPDATE ConfirmationToken c " +
+            "SET c.confirmedAt = ?2 " +
+            "WHERE c.token = ?1")
+    int updateConfirmedAt(String token, LocalDateTime confirmedAt);
+}
Index: sources/app/src/main/java/parkup/configs/token/ConfirmationTokenService.java
===================================================================
--- sources/app/src/main/java/parkup/configs/token/ConfirmationTokenService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
+++ sources/app/src/main/java/parkup/configs/token/ConfirmationTokenService.java	(revision ce6ad22249e902dea17e6ba473846ccebdd4330c)
@@ -0,0 +1,28 @@
+package parkup.configs.token;
+
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Service
+public class ConfirmationTokenService {
+
+    private final ConfirmationTokenRepository confirmationTokenRepository;
+
+    public ConfirmationTokenService(ConfirmationTokenRepository confirmationTokenRepository) {
+        this.confirmationTokenRepository = confirmationTokenRepository;
+    }
+
+    public void saveConfirmationToken(ConfirmationToken token){
+        confirmationTokenRepository.save(token);
+    }
+
+    public Optional<ConfirmationToken> getToken(String token) {
+        return confirmationTokenRepository.findByToken(token);
+    }
+
+    public int setConfirmedAt(String token) {
+        return confirmationTokenRepository.updateConfirmedAt(token, LocalDateTime.now());
+    }
+}
