/src/test/javascript/coverage/
/src/test/javascript/PhantomJS*/
+/src/main/resources/.h2.server.properties
+
######################
# Node
######################
<dockerfile-maven-plugin.version>1.3.4</dockerfile-maven-plugin.version>
<jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
<scala-maven-plugin.version>3.2.2</scala-maven-plugin.version>
- <sonar-maven-plugin.version>3.2</sonar-maven-plugin.version>
+ <sonar-maven-plugin.version>3.4.0.905</sonar-maven-plugin.version>
<!-- Sonar properties -->
<sonar.exclusions>src/main/webapp/content/**/*.*, src/main/webapp/i18n/*.js, target/www/**/*.*</sonar.exclusions>
<apache.commons-codec.version>1.11</apache.commons-codec.version>
<springfox-swagger-ui.version>2.8.0</springfox-swagger-ui.version>
+ <jackson-dataformats-binary.version>2.9.4</jackson-dataformats-binary.version>
</properties>
<version>${apache.commons-codec.version}</version>
</dependency>
+ <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformats-binary -->
+ <dependency>
+ <groupId>com.fasterxml.jackson.dataformat</groupId>
+ <artifactId>jackson-dataformats-binary</artifactId>
+ <version>${jackson-dataformats-binary.version}</version>
+ <type>pom</type>
+ </dependency>
+
</dependencies>
<build>
"run with both the 'dev' and 'cloud' profiles at the same time.");
}
managementDocket.enable(false);
- apiDocket.select().paths(PathSelectors.regex("/api/device-service.*")).build();
+ apiDocket.select().paths(PathSelectors.regex("/api/device-service.*|/dashboard.*")).build();
}
/**
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.web.filter.CorsFilter;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
@Configuration
@Import(SecurityProblemSupport.class)
@EnableWebSecurity
private final SecurityProblemSupport problemSupport;
- public MicroserviceSecurityConfiguration(TokenProvider tokenProvider, SecurityProblemSupport problemSupport) {
+ private final AuthenticationManagerBuilder authenticationManagerBuilder;
+
+ private final UserDetailsService userDetailsService;
+
+ private final CorsFilter corsFilter;
+
+ public MicroserviceSecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService,TokenProvider tokenProvider,CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
+ this.authenticationManagerBuilder = authenticationManagerBuilder;
+ this.userDetailsService = userDetailsService;
this.tokenProvider = tokenProvider;
+ this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
+ @PostConstruct
+ public void init() {
+ try {
+ authenticationManagerBuilder
+ .userDetailsService(userDetailsService)
+ .passwordEncoder(passwordEncoder());
+ } catch (Exception e) {
+ throw new BeanInitializationException("Security configuration failed", e);
+ }
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
- //.antMatchers("/api/**").authenticated()
+ .antMatchers("/dashboard/auth/login").permitAll()
+ .antMatchers("/dashboard/auth/register").permitAll()
+ .antMatchers("/dashboard/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/swagger-resources/configuration/ui").permitAll()
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.domain;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Column;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+
+/**
+ * An authority (a security role) used by Spring Security.
+ */
+@Entity
+@Table(name = "jhi_authority")
+
+public class Authority implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @NotNull
+ @Size(max = 50)
+ @Id
+ @Column(length = 50)
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Authority authority = (Authority) o;
+
+ return !(name != null ? !name.equals(authority.name) : authority.name != null);
+ }
+
+ @Override
+ public int hashCode() {
+ return name != null ? name.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ return "Authority{" +
+ "name='" + name + '\'' +
+ "}";
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.samsung.samserver.config.Constants;
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.validator.constraints.Email;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+import java.time.Instant;
+
+/**
+ * A user.
+ */
+@Entity
+@Table(name = "jhi_user")
+
+public class User extends AbstractAuditingEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
+ @SequenceGenerator(name = "sequenceGenerator")
+ private Long id;
+
+ @NotNull
+ @Pattern(regexp = Constants.LOGIN_REGEX)
+ @Size(min = 1, max = 50)
+ @Column(length = 50, unique = true, nullable = false)
+ private String login;
+
+ @JsonIgnore
+ @NotNull
+ @Size(min = 60, max = 60)
+ @Column(name = "password_hash", length = 60)
+ private String password;
+
+ @Size(max = 50)
+ @Column(name = "first_name", length = 50)
+ private String firstName;
+
+ @Size(max = 50)
+ @Column(name = "last_name", length = 50)
+ private String lastName;
+
+ @Email
+ @Size(min = 5, max = 100)
+ @Column(length = 100, unique = true)
+ private String email;
+
+ @NotNull
+ @Column(nullable = false)
+ private boolean activated = false;
+
+ @Size(min = 2, max = 6)
+ @Column(name = "lang_key", length = 6)
+ private String langKey;
+
+ @Size(max = 256)
+ @Column(name = "image_url", length = 256)
+ private String imageUrl;
+
+ @Size(max = 20)
+ @Column(name = "activation_key", length = 20)
+ @JsonIgnore
+ private String activationKey;
+
+ @Size(max = 20)
+ @Column(name = "reset_key", length = 20)
+ @JsonIgnore
+ private String resetKey;
+
+ @Column(name = "reset_date")
+ private Instant resetDate = null;
+
+ @JsonIgnore
+ @ManyToMany
+ @JoinTable(
+ name = "jhi_user_authority",
+ joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
+ inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")})
+
+ @BatchSize(size = 20)
+ private Set<Authority> authorities = new HashSet<>();
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ // Lowercase the login before saving it in database
+ public void setLogin(String login) {
+ this.login = StringUtils.lowerCase(login, Locale.ENGLISH);
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public void setImageUrl(String imageUrl) {
+ this.imageUrl = imageUrl;
+ }
+
+ public boolean getActivated() {
+ return activated;
+ }
+
+ public void setActivated(boolean activated) {
+ this.activated = activated;
+ }
+
+ public String getActivationKey() {
+ return activationKey;
+ }
+
+ public void setActivationKey(String activationKey) {
+ this.activationKey = activationKey;
+ }
+
+ public String getResetKey() {
+ return resetKey;
+ }
+
+ public void setResetKey(String resetKey) {
+ this.resetKey = resetKey;
+ }
+
+ public Instant getResetDate() {
+ return resetDate;
+ }
+
+ public void setResetDate(Instant resetDate) {
+ this.resetDate = resetDate;
+ }
+
+ public String getLangKey() {
+ return langKey;
+ }
+
+ public void setLangKey(String langKey) {
+ this.langKey = langKey;
+ }
+
+ public Set<Authority> getAuthorities() {
+ return authorities;
+ }
+
+ public void setAuthorities(Set<Authority> authorities) {
+ this.authorities = authorities;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ User user = (User) o;
+ return !(user.getId() == null || getId() == null) && Objects.equals(getId(), user.getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getId());
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "login='" + login + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ ", email='" + email + '\'' +
+ ", imageUrl='" + imageUrl + '\'' +
+ ", activated='" + activated + '\'' +
+ ", langKey='" + langKey + '\'' +
+ ", activationKey='" + activationKey + '\'' +
+ "}";
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.repository;
+
+
+import com.samsung.samserver.domain.Authority;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * Spring Data JPA repository for the Authority entity.
+ */
+public interface AuthorityRepository extends JpaRepository<Authority, String> {
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.repository;
+
+import com.samsung.samserver.domain.User;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.EntityGraph;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import java.util.List;
+import java.util.Optional;
+import java.time.Instant;
+
+/**
+ * Spring Data JPA repository for the User entity.
+ */
+@Repository
+public interface UserRepository extends JpaRepository<User, Long> {
+
+ Optional<User> findOneByActivationKey(String activationKey);
+
+ List<User> findAllByActivatedIsFalseAndCreatedDateBefore(Instant dateTime);
+
+ Optional<User> findOneByResetKey(String resetKey);
+
+ Optional<User> findOneByEmailIgnoreCase(String email);
+
+ Optional<User> findOneByLogin(String login);
+
+ @EntityGraph(attributePaths = "authorities")
+ Optional<User> findOneWithAuthoritiesById(Long id);
+
+ @EntityGraph(attributePaths = "authorities")
+ Optional<User> findOneWithAuthoritiesByLogin(String login);
+
+ @EntityGraph(attributePaths = "authorities")
+ Optional<User> findOneWithAuthoritiesByEmail(String email);
+
+ Page<User> findAllByLoginNot(Pageable pageable, String login);
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.security;
+
+
+import com.samsung.samserver.domain.User;
+import com.samsung.samserver.repository.UserRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Authenticate a user from the database.
+ */
+@Component("userDetailsService")
+public class DomainUserDetailsService implements UserDetailsService {
+
+ private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
+
+ private final UserRepository userRepository;
+
+ public DomainUserDetailsService(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ @Transactional
+ public UserDetails loadUserByUsername(final String login) {
+ log.debug("Authenticating {}", login);
+ String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
+ Optional<User> userByEmailFromDatabase = userRepository.findOneWithAuthoritiesByEmail(lowercaseLogin);
+ return userByEmailFromDatabase.map(user -> createSpringSecurityUser(lowercaseLogin, user)).orElseGet(() -> {
+ Optional<User> userByLoginFromDatabase = userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin);
+ return userByLoginFromDatabase.map(user -> createSpringSecurityUser(lowercaseLogin, user))
+ .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " +
+ "database"));
+ });
+ }
+
+ private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
+ if (!user.getActivated()) {
+ throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
+ }
+ List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
+ .map(authority -> new SimpleGrantedAuthority(authority.getName()))
+ .collect(Collectors.toList());
+ return new org.springframework.security.core.userdetails.User(user.getLogin(),
+ user.getPassword(),
+ grantedAuthorities);
+ }
+
+
+ /**
+ * This exception is thrown in case of a not activated user trying to authenticate.
+ */
+ public static class UserNotActivatedException extends AuthenticationException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UserNotActivatedException(String message) {
+ super(message);
+ }
+
+ public UserNotActivatedException(String message, Throwable t) {
+ super(message, t);
+ }
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.service.dto;
+
+
+
+import com.samsung.samserver.config.Constants;
+import com.samsung.samserver.domain.Authority;
+import com.samsung.samserver.domain.User;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotBlank;
+
+import javax.validation.constraints.*;
+import java.time.Instant;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * A DTO representing a user, with his authorities.
+ */
+public class UserDTO {
+
+ private Long id;
+
+ @NotBlank
+ @Pattern(regexp = Constants.LOGIN_REGEX)
+ @Size(min = 1, max = 50)
+ private String login;
+
+ @Size(max = 50)
+ private String firstName;
+
+ @Size(max = 50)
+ private String lastName;
+
+ @Email
+ @Size(min = 5, max = 100)
+ private String email;
+
+ @Size(max = 256)
+ private String imageUrl;
+
+ private boolean activated = false;
+
+ @Size(min = 2, max = 6)
+ private String langKey;
+
+ private String createdBy;
+
+ private Instant createdDate;
+
+ private String lastModifiedBy;
+
+ private Instant lastModifiedDate;
+
+ private Set<String> authorities;
+
+ public UserDTO() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public UserDTO(User user) {
+ this.id = user.getId();
+ this.login = user.getLogin();
+ this.firstName = user.getFirstName();
+ this.lastName = user.getLastName();
+ this.email = user.getEmail();
+ this.activated = user.getActivated();
+ this.imageUrl = user.getImageUrl();
+ this.langKey = user.getLangKey();
+ this.authorities = user.getAuthorities().stream()
+ .map(Authority::getName)
+ .collect(Collectors.toSet());
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public void setImageUrl(String imageUrl) {
+ this.imageUrl = imageUrl;
+ }
+
+ public boolean isActivated() {
+ return activated;
+ }
+
+ public void setActivated(boolean activated) {
+ this.activated = activated;
+ }
+
+ public String getLangKey() {
+ return langKey;
+ }
+
+ public void setLangKey(String langKey) {
+ this.langKey = langKey;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public Instant getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(Instant createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public String getLastModifiedBy() {
+ return lastModifiedBy;
+ }
+
+ public void setLastModifiedBy(String lastModifiedBy) {
+ this.lastModifiedBy = lastModifiedBy;
+ }
+
+ public Instant getLastModifiedDate() {
+ return lastModifiedDate;
+ }
+
+ public void setLastModifiedDate(Instant lastModifiedDate) {
+ this.lastModifiedDate = lastModifiedDate;
+ }
+
+ public Set<String> getAuthorities() {
+ return authorities;
+ }
+
+ public void setAuthorities(Set<String> authorities) {
+ this.authorities = authorities;
+ }
+
+ @Override
+ public String toString() {
+ return "UserDTO{" +
+ "login='" + login + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ ", email='" + email + '\'' +
+ ", imageUrl='" + imageUrl + '\'' +
+ ", activated=" + activated +
+ ", langKey='" + langKey + '\'' +
+ ", createdBy=" + createdBy +
+ ", createdDate=" + createdDate +
+ ", lastModifiedBy='" + lastModifiedBy + '\'' +
+ ", lastModifiedDate=" + lastModifiedDate +
+ ", authorities=" + authorities +
+ "}";
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.service.dto;
+
+import com.samsung.samserver.domain.Authority;
+import com.samsung.samserver.domain.User;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Mapper for the entity User and its DTO called UserDTO.
+ *
+ * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct
+ * support is still in beta, and requires a manual step with an IDE.
+ */
+@Service
+public class UserMapper {
+
+ public UserDTO userToUserDTO(User user) {
+ return new UserDTO(user);
+ }
+
+ public List<UserDTO> usersToUserDTOs(List<User> users) {
+ return users.stream()
+ .filter(Objects::nonNull)
+ .map(this::userToUserDTO)
+ .collect(Collectors.toList());
+ }
+
+ public User userDTOToUser(UserDTO userDTO) {
+ if (userDTO == null) {
+ return null;
+ } else {
+ User user = new User();
+ user.setId(userDTO.getId());
+ user.setLogin(userDTO.getLogin());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ user.setEmail(userDTO.getEmail());
+ user.setImageUrl(userDTO.getImageUrl());
+ user.setActivated(userDTO.isActivated());
+ user.setLangKey(userDTO.getLangKey());
+ Set<Authority> authorities = this.authoritiesFromStrings(userDTO.getAuthorities());
+ if (authorities != null) {
+ user.setAuthorities(authorities);
+ }
+ return user;
+ }
+ }
+
+ public List<User> userDTOsToUsers(List<UserDTO> userDTOs) {
+ return userDTOs.stream()
+ .filter(Objects::nonNull)
+ .map(this::userDTOToUser)
+ .collect(Collectors.toList());
+ }
+
+ public User userFromId(Long id) {
+ if (id == null) {
+ return null;
+ }
+ User user = new User();
+ user.setId(id);
+ return user;
+ }
+
+ public Set<Authority> authoritiesFromStrings(Set<String> strings) {
+ return strings.stream().map(string -> {
+ Authority auth = new Authority();
+ auth.setName(string);
+ return auth;
+ }).collect(Collectors.toSet());
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.service.impl;
+
+import com.samsung.samserver.domain.User;
+import io.github.jhipster.config.JHipsterProperties;
+
+import org.apache.commons.lang3.CharEncoding;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.MessageSource;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.thymeleaf.context.Context;
+import org.thymeleaf.spring4.SpringTemplateEngine;
+
+import javax.mail.internet.MimeMessage;
+import java.util.Locale;
+
+/**
+ * Service for sending emails.
+ * <p>
+ * We use the @Async annotation to send emails asynchronously.
+ */
+@Service
+public class MailService {
+
+ private final Logger log = LoggerFactory.getLogger(MailService.class);
+
+ private static final String USER = "user";
+
+ private static final String BASE_URL = "baseUrl";
+
+ private final JHipsterProperties jHipsterProperties;
+
+ private final JavaMailSender javaMailSender;
+
+ private final MessageSource messageSource;
+
+ private final SpringTemplateEngine templateEngine;
+
+ public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender,
+ MessageSource messageSource, SpringTemplateEngine templateEngine) {
+
+ this.jHipsterProperties = jHipsterProperties;
+ this.javaMailSender = javaMailSender;
+ this.messageSource = messageSource;
+ this.templateEngine = templateEngine;
+ }
+
+ @Async
+ public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
+ log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
+ isMultipart, isHtml, to, subject, content);
+
+ // Prepare message using a Spring helper
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ try {
+ MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8);
+ message.setTo(to);
+ message.setFrom(jHipsterProperties.getMail().getFrom());
+ message.setSubject(subject);
+ message.setText(content, isHtml);
+ javaMailSender.send(mimeMessage);
+ log.debug("Sent email to User '{}'", to);
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.warn("Email could not be sent to user '{}'", to, e);
+ } else {
+ log.warn("Email could not be sent to user '{}': {}", to, e.getMessage());
+ }
+ }
+ }
+
+ @Async
+ public void sendEmailFromTemplate(User user, String templateName, String titleKey) {
+ Locale locale = Locale.forLanguageTag(user.getLangKey());
+ Context context = new Context(locale);
+ context.setVariable(USER, user);
+ context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
+ String content = templateEngine.process(templateName, context);
+ String subject = messageSource.getMessage(titleKey, null, locale);
+ sendEmail(user.getEmail(), subject, content, false, true);
+
+ }
+
+ @Async
+ public void sendActivationEmail(User user) {
+ log.debug("Sending activation email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "activationEmail", "email.activation.title");
+ }
+
+ @Async
+ public void sendCreationEmail(User user) {
+ log.debug("Sending creation email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "creationEmail", "email.activation.title");
+ }
+
+ @Async
+ public void sendPasswordResetMail(User user) {
+ log.debug("Sending password reset email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "passwordResetEmail", "email.reset.title");
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.service.impl;
+
+
+import com.samsung.samserver.service.dto.UserDTO;
+
+import com.samsung.samserver.config.Constants;
+import com.samsung.samserver.domain.*;
+import com.samsung.samserver.repository.AuthorityRepository;
+import com.samsung.samserver.repository.UserRepository;
+import com.samsung.samserver.security.AuthoritiesConstants;
+import com.samsung.samserver.security.SecurityUtils;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Service class for managing users.
+ */
+@Service
+@Transactional
+public class UserService {
+
+ private final Logger log = LoggerFactory.getLogger(UserService.class);
+
+ private final UserRepository userRepository;
+
+ private final PasswordEncoder passwordEncoder;
+
+ private final AuthorityRepository authorityRepository;
+
+ public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository) {
+ this.userRepository = userRepository;
+ this.passwordEncoder = passwordEncoder;
+ this.authorityRepository = authorityRepository;
+ }
+
+ public Optional<User> activateRegistration(String key) {
+ log.debug("Activating user for activation key {}", key);
+ return userRepository.findOneByActivationKey(key)
+ .map(user -> {
+ // activate given user for the registration key.
+ user.setActivated(true);
+ user.setActivationKey(null);
+ log.debug("Activated user: {}", user);
+ return user;
+ });
+ }
+
+ public Optional<User> completePasswordReset(String newPassword, String key) {
+ log.debug("Reset user password for reset key {}", key);
+
+ return userRepository.findOneByResetKey(key)
+ .filter(user -> user.getResetDate().isAfter(Instant.now().minusSeconds(86400)))
+ .map(user -> {
+ user.setPassword(passwordEncoder.encode(newPassword));
+ user.setResetKey(null);
+ user.setResetDate(null);
+ return user;
+ });
+ }
+
+ public Optional<User> requestPasswordReset(String mail) {
+ return userRepository.findOneByEmailIgnoreCase(mail)
+ .filter(User::getActivated)
+ .map(user -> {
+ user.setResetKey(RandomUtil.generateResetKey());
+ user.setResetDate(Instant.now());
+ return user;
+ });
+ }
+
+ public User registerUser(UserDTO userDTO, String password) {
+
+ User newUser = new User();
+ Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER);
+ Set<Authority> authorities = new HashSet<>();
+ String encryptedPassword = passwordEncoder.encode(password);
+ newUser.setLogin(userDTO.getLogin());
+ // new user gets initially a generated password
+ newUser.setPassword(encryptedPassword);
+ newUser.setFirstName(userDTO.getFirstName());
+ newUser.setLastName(userDTO.getLastName());
+ newUser.setEmail(userDTO.getEmail());
+ newUser.setImageUrl(userDTO.getImageUrl());
+ newUser.setLangKey(userDTO.getLangKey());
+ // new user is not active
+ newUser.setActivated(false);
+ // new user gets registration key
+ newUser.setActivationKey(RandomUtil.generateActivationKey());
+ authorities.add(authority);
+ newUser.setAuthorities(authorities);
+ userRepository.save(newUser);
+ log.debug("Created Information for User: {}", newUser);
+ return newUser;
+ }
+
+ public User createUser(UserDTO userDTO) {
+ User user = new User();
+ user.setLogin(userDTO.getLogin());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ user.setEmail(userDTO.getEmail());
+ user.setImageUrl(userDTO.getImageUrl());
+ if (userDTO.getLangKey() == null) {
+ user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language
+ } else {
+ user.setLangKey(userDTO.getLangKey());
+ }
+ if (userDTO.getAuthorities() != null) {
+ Set<Authority> authorities = userDTO.getAuthorities().stream()
+ .map(authorityRepository::findOne)
+ .collect(Collectors.toSet());
+ user.setAuthorities(authorities);
+ }
+ String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
+ user.setPassword(encryptedPassword);
+ user.setResetKey(RandomUtil.generateResetKey());
+ user.setResetDate(Instant.now());
+ user.setActivated(true);
+ userRepository.save(user);
+ log.debug("Created Information for User: {}", user);
+ return user;
+ }
+
+ /**
+ * Update basic information (first name, last name, email, language) for the current user.
+ *
+ * @param firstName first name of user
+ * @param lastName last name of user
+ * @param email email id of user
+ * @param langKey language key
+ * @param imageUrl image URL of user
+ */
+ public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) {
+ SecurityUtils.getCurrentUserLogin()
+ .flatMap(userRepository::findOneByLogin)
+ .ifPresent(user -> {
+ user.setFirstName(firstName);
+ user.setLastName(lastName);
+ user.setEmail(email);
+ user.setLangKey(langKey);
+ user.setImageUrl(imageUrl);
+ log.debug("Changed Information for User: {}", user);
+ });
+ }
+
+ /**
+ * Update all information for a specific user, and return the modified user.
+ *
+ * @param userDTO user to update
+ * @return updated user
+ */
+ public Optional<UserDTO> updateUser(UserDTO userDTO) {
+ return Optional.of(userRepository
+ .findOne(userDTO.getId()))
+ .map(user -> {
+ user.setLogin(userDTO.getLogin());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ user.setEmail(userDTO.getEmail());
+ user.setImageUrl(userDTO.getImageUrl());
+ user.setActivated(userDTO.isActivated());
+ user.setLangKey(userDTO.getLangKey());
+ Set<Authority> managedAuthorities = user.getAuthorities();
+ managedAuthorities.clear();
+ userDTO.getAuthorities().stream()
+ .map(authorityRepository::findOne)
+ .forEach(managedAuthorities::add);
+ log.debug("Changed Information for User: {}", user);
+ return user;
+ })
+ .map(UserDTO::new);
+ }
+
+ public void deleteUser(String login) {
+ userRepository.findOneByLogin(login).ifPresent(user -> {
+ userRepository.delete(user);
+ log.debug("Deleted User: {}", user);
+ });
+ }
+
+ public void changePassword(String password) {
+ SecurityUtils.getCurrentUserLogin()
+ .flatMap(userRepository::findOneByLogin)
+ .ifPresent(user -> {
+ String encryptedPassword = passwordEncoder.encode(password);
+ user.setPassword(encryptedPassword);
+ log.debug("Changed password for User: {}", user);
+ });
+ }
+
+ @Transactional(readOnly = true)
+ public Page<UserDTO> getAllManagedUsers(Pageable pageable) {
+ return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new);
+ }
+
+ @Transactional(readOnly = true)
+ public Optional<User> getUserWithAuthoritiesByLogin(String login) {
+ return userRepository.findOneWithAuthoritiesByLogin(login);
+ }
+
+ @Transactional(readOnly = true)
+ public Optional<User> getUserWithAuthorities(Long id) {
+ return userRepository.findOneWithAuthoritiesById(id);
+ }
+
+ @Transactional(readOnly = true)
+ public Optional<User> getUserWithAuthorities() {
+ return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin);
+ }
+
+ /**
+ * Not activated users should be automatically deleted after 3 days.
+ * <p>
+ * This is scheduled to get fired everyday, at 01:00 (am).
+ */
+ @Scheduled(cron = "0 0 1 * * ?")
+ public void removeNotActivatedUsers() {
+ List<User> users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS));
+ for (User user : users) {
+ log.debug("Deleting not activated user {}", user.getLogin());
+ userRepository.delete(user);
+ }
+ }
+
+ /**
+ * @return a list of all the authorities
+ */
+ public List<String> getAuthorities() {
+ return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList());
+ }
+
+ /**
+ * Utility class for generating random Strings.
+ */
+ public static final class RandomUtil {
+
+ private static final int DEF_COUNT = 20;
+
+ private RandomUtil() {
+ }
+
+ /**
+ * Generate a password.
+ *
+ * @return the generated password
+ */
+ public static String generatePassword() {
+ return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
+ }
+
+ /**
+ * Generate an activation key.
+ *
+ * @return the generated activation key
+ */
+ public static String generateActivationKey() {
+ return RandomStringUtils.randomNumeric(DEF_COUNT);
+ }
+
+ /**
+ * Generate a reset key.
+ *
+ * @return the generated reset key
+ */
+ public static String generateResetKey() {
+ return RandomStringUtils.randomNumeric(DEF_COUNT);
+ }
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.web.rest;
+
+import com.codahale.metrics.annotation.Timed;
+import com.samsung.samserver.config.Constants;
+import com.samsung.samserver.domain.User;
+import com.samsung.samserver.repository.UserRepository;
+import com.samsung.samserver.security.AuthoritiesConstants;
+import com.samsung.samserver.service.impl.MailService;
+import com.samsung.samserver.service.impl.UserService;
+import com.samsung.samserver.service.dto.UserDTO;
+import com.samsung.samserver.web.rest.errors.BadRequestAlertException;
+import com.samsung.samserver.web.rest.errors.UserServiceError;
+import com.samsung.samserver.web.rest.util.HeaderUtil;
+import com.samsung.samserver.web.rest.util.PaginationUtil;
+import io.github.jhipster.web.util.ResponseUtil;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+/**
+ * REST controller for managing users.
+ * <p>
+ * This class accesses the User entity, and needs to fetch its collection of authorities.
+ * <p>
+ * For a normal use-case, it would be better to have an eager relationship between User and Authority,
+ * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join
+ * which would be good for performance.
+ * <p>
+ * We use a View Model and a DTO for 3 reasons:
+ * <ul>
+ * <li>We want to keep a lazy association between the user and the authorities, because people will
+ * quite often do relationships with the user, and we don't want them to get the authorities all
+ * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users'
+ * application because of this use-case.</li>
+ * <li> Not having an outer join causes n+1 requests to the database. This is not a real issue as
+ * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests,
+ * but then all authorities come from the cache, so in fact it's much better than doing an outer join
+ * (which will get lots of data from the database, for each HTTP call).</li>
+ * <li> As this manages users, for security reasons, we'd rather have a DTO layer.</li>
+ * </ul>
+ * <p>
+ * Another option would be to have a specific JPA entity graph to handle this case.
+ */
+@RestController
+@RequestMapping("/api")
+public class UserResource {
+
+ private final Logger log = LoggerFactory.getLogger(UserResource.class);
+
+ private final UserRepository userRepository;
+
+ private final UserService userService;
+
+ private final MailService mailService;
+
+ public UserResource(UserRepository userRepository, UserService userService, MailService mailService) {
+
+ this.userRepository = userRepository;
+ this.userService = userService;
+ this.mailService = mailService;
+ }
+
+ /**
+ * POST /users : Creates a new user.
+ * <p>
+ * Creates a new user if the login and email are not already used, and sends an
+ * mail with an activation link.
+ * The user needs to be activated on creation.
+ *
+ * @param userDTO the user to create
+ * @return the ResponseEntity with status 201 (Created) and with body the new user, or with status 400 (Bad Request) if the login or email is already in use
+ * @throws URISyntaxException if the Location URI syntax is incorrect
+ * @throws BadRequestAlertException 400 (Bad Request) if the login or email is already in use
+ */
+ @PostMapping("/users")
+ @Timed
+ @Secured(AuthoritiesConstants.ADMIN)
+ public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO userDTO) throws URISyntaxException {
+ log.debug("REST request to save User : {}", userDTO);
+
+ if (userDTO.getId() != null) {
+ throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists");
+ // Lowercase the user login before comparing with database
+ } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) {
+ throw new UserServiceError.LoginAlreadyUsedException();
+ } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) {
+ throw new UserServiceError.EmailAlreadyUsedException();
+ } else {
+ User newUser = userService.createUser(userDTO);
+ mailService.sendCreationEmail(newUser);
+ return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin()))
+ .headers(HeaderUtil.createAlert( "A user is created with identifier " + newUser.getLogin(), newUser.getLogin()))
+ .body(newUser);
+ }
+ }
+
+ /**
+ * PUT /users : Updates an existing User.
+ *
+ * @param userDTO the user to update
+ * @return the ResponseEntity with status 200 (OK) and with body the updated user
+ * @throws UserServiceError.EmailAlreadyUsedException 400 (Bad Request) if the email is already in use
+ * @throws UserServiceError.LoginAlreadyUsedException 400 (Bad Request) if the login is already in use
+ */
+ @PutMapping("/users")
+ @Timed
+ @Secured(AuthoritiesConstants.ADMIN)
+ public ResponseEntity<UserDTO> updateUser(@Valid @RequestBody UserDTO userDTO) {
+ log.debug("REST request to update User : {}", userDTO);
+ Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
+ if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
+ throw new UserServiceError.EmailAlreadyUsedException();
+ }
+ existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase());
+ if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
+ throw new UserServiceError.LoginAlreadyUsedException();
+ }
+ Optional<UserDTO> updatedUser = userService.updateUser(userDTO);
+
+ return ResponseUtil.wrapOrNotFound(updatedUser,
+ HeaderUtil.createAlert("A user is updated with identifier " + userDTO.getLogin(), userDTO.getLogin()));
+ }
+
+ /**
+ * GET /users : get all users.
+ *
+ * @param pageable the pagination information
+ * @return the ResponseEntity with status 200 (OK) and with body all users
+ */
+ @GetMapping("/users")
+ @Timed
+ public ResponseEntity<List<UserDTO>> getAllUsers(Pageable pageable) {
+ final Page<UserDTO> page = userService.getAllManagedUsers(pageable);
+ HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users");
+ return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
+ }
+
+ /**
+ * @return a string list of the all of the roles
+ */
+ @GetMapping("/users/authorities")
+ @Timed
+ @Secured(AuthoritiesConstants.ADMIN)
+ public List<String> getAuthorities() {
+ return userService.getAuthorities();
+ }
+
+ /**
+ * GET /users/:login : get the "login" user.
+ *
+ * @param login the login of the user to find
+ * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found)
+ */
+ @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
+ @Timed
+ public ResponseEntity<UserDTO> getUser(@PathVariable String login) {
+ log.debug("REST request to get User : {}", login);
+ return ResponseUtil.wrapOrNotFound(
+ userService.getUserWithAuthoritiesByLogin(login)
+ .map(UserDTO::new));
+ }
+
+ /**
+ * DELETE /users/:login : delete the "login" User.
+ *
+ * @param login the login of the user to delete
+ * @return the ResponseEntity with status 200 (OK)
+ */
+ @DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
+ @Timed
+ @Secured(AuthoritiesConstants.ADMIN)
+ public ResponseEntity<Void> deleteUser(@PathVariable String login) {
+ log.debug("REST request to delete User: {}", login);
+ userService.deleteUser(login);
+ return ResponseEntity.ok().headers(HeaderUtil.createAlert( "A user is deleted with identifier " + login, login)).build();
+ }
+}
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.web.rest.controller;
+
+import com.samsung.samserver.domain.Device;
+import com.samsung.samserver.web.rest.service.AccountService;
+import com.samsung.samserver.web.rest.service.UserJWTService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.*;
+
+import javax.validation.Valid;
+import java.util.List;
+import com.samsung.samserver.web.rest.errors.UserServiceError;
+
+/**
+ * Rest Interface for dashboard.
+ *
+ * @author <A HREF="mailto:m.dalakov@samsung.com">Mykhailo Dalakov</A>
+ * @version 1.0
+ */
+@RequestMapping("/dashboard")
+public interface IRestDashboard {
+
+ /**
+ * GET /devices : get all the devices.
+ *
+ * @return the ResponseEntity with status 200 (OK) and the list of devices in body
+ */
+ @ApiOperation(value = "getAllDevices", notes = "The “getAllDevices” operation is used to obtain all registered devices.")
+ @ApiResponses(value = {
+ @ApiResponse(code = 200, message = "OK. Request executed successfully."),
+ @ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
+ @ApiResponse(code = 500, message = "Internal server error. The user has to repeat action.")
+ })
+ @RequestMapping(value ="/devices", method = RequestMethod.GET)
+ public List<Device> getAllDevices();
+
+
+ /**
+ * POST request login
+ *
+ * @return the ResponseEntity with status 200 (OK) and JWT
+ */
+ @ApiOperation(value = "login", notes = "The “login” operation is used to authenticate user and receive JWT token.")
+ @ApiResponses(value = {
+ @ApiResponse(code = 200, message = "OK. Login was successful."),
+ @ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
+ @ApiResponse(code = 500, message = "Internal server error. The user has to repeat action.")
+ })
+ @RequestMapping(value ="/auth/login", method = RequestMethod.POST)
+ public ResponseEntity<UserJWTService.JWTToken> login(
+ @Valid @ApiParam(value = "Login Data", required = true) @RequestBody UserJWTService.LoginVM loginVM);
+
+
+ /**
+ * POST request register the user.
+ *
+ * @param managedUserVM the managed user View Model
+ * @throws UserServiceError.InvalidPasswordException 400 (Bad Request) if the password is incorrect
+ * @throws UserServiceError.EmailAlreadyUsedException 400 (Bad Request) if the email is already used
+ * @throws UserServiceError.LoginAlreadyUsedException 400 (Bad Request) if the login is already used
+ */
+ @ApiOperation(value = "register", notes = "The “register” operation is used to register new user.")
+ @ApiResponses(value = {
+ @ApiResponse(code = 201, message = "Register was successful. New User was created."),
+ @ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
+ @ApiResponse(code = 500, message = "Internal server error. The user has to repeat action.")
+ })
+ @RequestMapping(value ="/auth/register", method = RequestMethod.POST)
+ @ResponseStatus(HttpStatus.CREATED)
+ public void registerAccount(
+ @Valid @ApiParam(value = "Managed User", required = true) @RequestBody AccountService.ManagedUserVM managedUserVM);
+
+
+}
@ApiResponse(code = 200, message = "OK. The updates are found and should apply by device."),
@ApiResponse(code = 304, message = "Not Modified. The updates aren’t required"),
@ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
- @ApiResponse(code = 404, message = "Device not found. The device should be registered"),
@ApiResponse(code = 500, message = "Internal server error. The device has to repeat action")
})
@RequestMapping(value ="/get-updates", method = RequestMethod.GET, produces = {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK. Send data was successful."),
@ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
- @ApiResponse(code = 404, message = "Device not found. The device should be registered"),
@ApiResponse(code = 500, message = "Internal server error. The device has to repeat action")
})
@RequestMapping(value ="/send-data", method = RequestMethod.POST)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK. The data are found and should apply by device."),
@ApiResponse(code = 400, message = "Bad Request. The reason is contained in the tags “errorKey”, “message”, “title”"),
- @ApiResponse(code = 404, message = "Device not found. The device should be registered"),
@ApiResponse(code = 500, message = "Internal server error. The device has to repeat action")
})
@RequestMapping(value ="/get-udata", method = RequestMethod.GET)
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.web.rest.controller.impl;
+
+import com.samsung.samserver.domain.Device;
+import com.samsung.samserver.service.DeviceService;
+import com.samsung.samserver.web.rest.controller.IRestDashboard;
+import com.samsung.samserver.web.rest.service.AccountService;
+import com.samsung.samserver.web.rest.service.UserJWTService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * REST dashboard controller.
+ *
+ * @author <A HREF="mailto:m.dalakov@samsung.com">Mykhailo Dalakov</A>
+ * @version 1.0
+ */
+@RestController
+public class RestDashboard implements IRestDashboard {
+
+ private final Logger log = LoggerFactory.getLogger(RestDashboard.class);
+
+ @Autowired
+ private DeviceService deviceService;
+
+ @Autowired
+ private UserJWTService userJWTService;
+
+ @Autowired
+ private AccountService accountService;
+
+ /**
+ * GET /devices : get all the devices.
+ *
+ * @return the ResponseEntity with status 200 (OK) and the list of devices in body
+ */
+ @Override
+ public List<Device> getAllDevices() {
+ return deviceService.findAll();
+ }
+
+ /**
+ * POST request login
+ *
+ * @return the ResponseEntity with status 200 (OK) and JWT
+ */
+ @Override
+ public ResponseEntity<UserJWTService.JWTToken> login(@Valid @RequestBody UserJWTService.LoginVM loginVM) {
+ return userJWTService.authorize(loginVM);
+ }
+
+ /**
+ * POST request register the user.
+ *
+ * @param managedUserVM the managed user View Model
+ */
+ @Override
+ public void registerAccount(@Valid @RequestBody AccountService.ManagedUserVM managedUserVM){
+ accountService.registerAccount(managedUserVM);
+ }
+
+}
* LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
* Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
*/
-package com.samsung.samserver.web.rest.controller;
+package com.samsung.samserver.web.rest.controller.impl;
+import com.samsung.samserver.web.rest.controller.IRestDevice;
import com.samsung.samserver.web.rest.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
--- /dev/null
+/*
+ * In Samsung Ukraine R&D Center (SRK under a contract between)
+ * LLC "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+package com.samsung.samserver.web.rest.service;
+
+import com.samsung.samserver.domain.User;
+import com.samsung.samserver.repository.UserRepository;
+import com.samsung.samserver.security.SecurityUtils;
+import com.samsung.samserver.service.impl.MailService;
+import com.samsung.samserver.service.impl.UserService;
+import com.samsung.samserver.service.dto.UserDTO;
+
+import com.samsung.samserver.web.rest.errors.InternalServerErrorException;
+import com.samsung.samserver.web.rest.errors.UserServiceError;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import javax.validation.constraints.Size;
+import java.util.*;
+
+/**
+ * REST service for managing the current user's account.
+ */
+@Service
+public class AccountService {
+
+ private final Logger log = LoggerFactory.getLogger(AccountService.class);
+
+ private final UserRepository userRepository;
+
+ private final UserService userService;
+
+ private final MailService mailService;
+
+ public AccountService(UserRepository userRepository, UserService userService, MailService mailService) {
+
+ this.userRepository = userRepository;
+ this.userService = userService;
+ this.mailService = mailService;
+ }
+
+ /**
+ * POST /register : register the user.
+ *
+ * @param managedUserVM the managed user View Model
+ * @throws UserServiceError.InvalidPasswordException 400 (Bad Request) if the password is incorrect
+ * @throws UserServiceError.EmailAlreadyUsedException 400 (Bad Request) if the email is already used
+ * @throws UserServiceError.LoginAlreadyUsedException 400 (Bad Request) if the login is already used
+ */
+ public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) {
+ if (!checkPasswordLength(managedUserVM.getPassword())) {
+ throw new UserServiceError.InvalidPasswordException();
+ }
+ userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()).ifPresent(u -> {throw new UserServiceError.LoginAlreadyUsedException();});
+ userRepository.findOneByEmailIgnoreCase(managedUserVM.getEmail()).ifPresent(u -> {throw new UserServiceError.EmailAlreadyUsedException();});
+ User user = userService.registerUser(managedUserVM, managedUserVM.getPassword());
+ mailService.sendActivationEmail(user);
+ }
+
+ /**
+ * GET /activate : activate the registered user.
+ *
+ * @param key the activation key
+ * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be activated
+ */
+ public void activateAccount(@RequestParam(value = "key") String key) {
+ Optional<User> user = userService.activateRegistration(key);
+ if (!user.isPresent()) {
+ throw new InternalServerErrorException("No user was found for this reset key");
+ }
+ }
+
+ /**
+ * GET /authenticate : check if the user is authenticated, and return its login.
+ *
+ * @param request the HTTP request
+ * @return the login if the user is authenticated
+ */
+ public String isAuthenticated(HttpServletRequest request) {
+ log.debug("REST request to check if the current user is authenticated");
+ return request.getRemoteUser();
+ }
+
+ /**
+ * GET /account : get the current user.
+ *
+ * @return the current user
+ * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be returned
+ */
+ public UserDTO getAccount() {
+ return userService.getUserWithAuthorities()
+ .map(UserDTO::new)
+ .orElseThrow(() -> new InternalServerErrorException("User could not be found"));
+ }
+
+ /**
+ * POST /account : update the current user information.
+ *
+ * @param userDTO the current user information
+ * @throws UserServiceError.EmailAlreadyUsedException 400 (Bad Request) if the email is already used
+ * @throws RuntimeException 500 (Internal Server Error) if the user login wasn't found
+ */
+ public void saveAccount(@Valid @RequestBody UserDTO userDTO) {
+ final String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found"));
+ Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
+ if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) {
+ throw new UserServiceError.EmailAlreadyUsedException();
+ }
+ Optional<User> user = userRepository.findOneByLogin(userLogin);
+ if (!user.isPresent()) {
+ throw new InternalServerErrorException("User could not be found");
+ }
+ userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(),
+ userDTO.getLangKey(), userDTO.getImageUrl());
+ }
+
+ /**
+ * POST /account/change-password : changes the current user's password
+ *
+ * @param password the new password
+ * @throws UserServiceError.InvalidPasswordException 400 (Bad Request) if the new password is incorrect
+ */
+ public void changePassword(@RequestBody String password) {
+ if (!checkPasswordLength(password)) {
+ throw new UserServiceError.InvalidPasswordException();
+ }
+ userService.changePassword(password);
+ }
+
+ /**
+ * POST /account/reset-password/init : Send an email to reset the password of the user
+ *
+ * @param mail the mail of the user
+ * @throws UserServiceError.EmailNotFoundException 400 (Bad Request) if the email address is not registered
+ */
+ public void requestPasswordReset(@RequestBody String mail) {
+ mailService.sendPasswordResetMail(
+ userService.requestPasswordReset(mail)
+ .orElseThrow(UserServiceError.EmailNotFoundException::new)
+ );
+ }
+
+ /**
+ * POST /account/reset-password/finish : Finish to reset the password of the user
+ *
+ * @param keyAndPassword the generated key and the new password
+ * @throws UserServiceError.InvalidPasswordException 400 (Bad Request) if the password is incorrect
+ * @throws RuntimeException 500 (Internal Server Error) if the password could not be reset
+ */
+ public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
+ if (!checkPasswordLength(keyAndPassword.getNewPassword())) {
+ throw new UserServiceError.InvalidPasswordException();
+ }
+ Optional<User> user =
+ userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey());
+
+ if (!user.isPresent()) {
+ throw new InternalServerErrorException("No user was found for this reset key");
+ }
+ }
+
+ private static boolean checkPasswordLength(String password) {
+ return !StringUtils.isEmpty(password) &&
+ password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH &&
+ password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH;
+ }
+
+
+ /**
+ * View Model object for storing the user's key and password.
+ */
+ public static class KeyAndPasswordVM {
+
+ private String key;
+
+ private String newPassword;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+ }
+
+
+ /**
+ * View Model extending the UserDTO, which is meant to be used in the user management UI.
+ */
+ public static class ManagedUserVM extends UserDTO {
+
+ public static final int PASSWORD_MIN_LENGTH = 4;
+
+ public static final int PASSWORD_MAX_LENGTH = 100;
+
+ @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH)
+ private String password;
+
+ public ManagedUserVM() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public String toString() {
+ return "ManagedUserVM{" +
+ "} " + super.toString();
+ }
+ }
+
+
+}
--- /dev/null
+package com.samsung.samserver.web.rest.service;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.samsung.samserver.security.jwt.JWTConfigurer;
+import com.samsung.samserver.security.jwt.TokenProvider;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * REST service implementation for get jwt token.
+ *
+ * @author <A HREF="mailto:m.dalakov@samsung.com">Mykhailo Dalakov</A>
+ * @version 1.0
+ */
+@Service
+public class UserJWTService {
+
+ private final TokenProvider tokenProvider;
+
+ private final AuthenticationManager authenticationManager;
+
+ public UserJWTService(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
+ this.tokenProvider = tokenProvider;
+ this.authenticationManager = authenticationManager;
+ }
+
+ public ResponseEntity<JWTToken> authorize(@Valid @RequestBody LoginVM loginVM) {
+
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
+
+ Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
+ String jwt = tokenProvider.createToken(authentication, rememberMe);
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.add(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
+ return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
+ }
+
+
+ /**
+ * Object to return as body in JWT Authentication.
+ */
+ public static class JWTToken {
+
+ private String idToken;
+
+ JWTToken(String idToken) {
+ this.idToken = idToken;
+ }
+
+ @JsonProperty("id_token")
+ String getIdToken() {
+ return idToken;
+ }
+
+ void setIdToken(String idToken) {
+ this.idToken = idToken;
+ }
+ }
+
+
+ /**
+ * View Model object for storing a user's credentials.
+ */
+ public static class LoginVM {
+
+ @NotNull
+ @Size(min = 1, max = 50)
+ private String username;
+
+ @NotNull
+ @Size(min = AccountService.ManagedUserVM.PASSWORD_MIN_LENGTH, max = AccountService.ManagedUserVM.PASSWORD_MAX_LENGTH)
+ private String password;
+
+ private Boolean rememberMe;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Boolean isRememberMe() {
+ return rememberMe;
+ }
+
+ public void setRememberMe(Boolean rememberMe) {
+ this.rememberMe = rememberMe;
+ }
+
+ @Override
+ public String toString() {
+ return "LoginVM{" +
+ "username='" + username + '\'' +
+ ", rememberMe=" + rememberMe +
+ '}';
+ }
+ }
+}
#H2 Server Properties
-#Wed Feb 14 10:46:33 GMT+02:00 2018
+#Tue Feb 20 15:10:21 GMT+02:00 2018
0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:samserver|samserver
webAllowOthers=true
webPort=8082
--- /dev/null
+name
+ROLE_ADMIN
+ROLE_USER
<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
- xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
- xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<property name="now" value="now()" dbms="h2"/>
The initial schema has the '00000000000001' id, so that it is over-written if we re-generate it.
-->
<changeSet id="00000000000001" author="jhipster">
+ <createTable tableName="jhi_user">
+ <column name="id" type="bigint" autoIncrement="${autoIncrement}">
+ <constraints primaryKey="true" nullable="false"/>
+ </column>
+ <column name="login" type="varchar(50)">
+ <constraints unique="true" nullable="false" uniqueConstraintName="ux_user_login"/>
+ </column>
+ <column name="password_hash" type="varchar(60)"/>
+ <column name="first_name" type="varchar(50)"/>
+ <column name="last_name" type="varchar(50)"/>
+ <column name="email" type="varchar(100)">
+ <constraints unique="true" nullable="true" uniqueConstraintName="ux_user_email"/>
+ </column>
+ <column name="image_url" type="varchar(256)"/>
+ <column name="activated" type="boolean" valueBoolean="false">
+ <constraints nullable="false" />
+ </column>
+ <column name="lang_key" type="varchar(6)"/>
+ <column name="activation_key" type="varchar(20)"/>
+ <column name="reset_key" type="varchar(20)"/>
+ <column name="created_by" type="varchar(50)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="created_date" type="timestamp" defaultValueDate="${now}">
+ <constraints nullable="false"/>
+ </column>
+ <column name="reset_date" type="timestamp">
+ <constraints nullable="true"/>
+ </column>
+ <column name="last_modified_by" type="varchar(50)"/>
+ <column name="last_modified_date" type="timestamp"/>
+ </createTable>
+ <createIndex indexName="idx_user_login"
+ tableName="jhi_user"
+ unique="true">
+ <column name="login" type="varchar(50)"/>
+ </createIndex>
+
+ <createIndex indexName="idx_user_email"
+ tableName="jhi_user"
+ unique="true">
+ <column name="email" type="varchar(100)"/>
+ </createIndex>
+ <createTable tableName="jhi_authority">
+ <column name="name" type="varchar(50)">
+ <constraints primaryKey="true" nullable="false"/>
+ </column>
+ </createTable>
+
+ <createTable tableName="jhi_user_authority">
+ <column name="user_id" type="bigint">
+ <constraints nullable="false"/>
+ </column>
+ <column name="authority_name" type="varchar(50)">
+ <constraints nullable="false"/>
+ </column>
+ </createTable>
+
+ <addPrimaryKey columnNames="user_id, authority_name" tableName="jhi_user_authority"/>
+
+ <addForeignKeyConstraint baseColumnNames="authority_name"
+ baseTableName="jhi_user_authority"
+ constraintName="fk_authority_name"
+ referencedColumnNames="name"
+ referencedTableName="jhi_authority"/>
+ <addForeignKeyConstraint baseColumnNames="user_id"
+ baseTableName="jhi_user_authority"
+ constraintName="fk_user_id"
+ referencedColumnNames="id"
+ referencedTableName="jhi_user"/>
+ <loadData encoding="UTF-8"
+ file="config/liquibase/users.csv"
+ separator=";"
+ tableName="jhi_user">
+ <column name="activated" type="boolean"/>
+ <column name="created_date" type="timestamp"/>
+ </loadData>
+ <dropDefaultValue tableName="jhi_user" columnName="created_date" columnDataType="datetime"/>
+ <loadData encoding="UTF-8"
+ file="config/liquibase/authorities.csv"
+ separator=";"
+ tableName="jhi_authority"/>
+
+ <loadData encoding="UTF-8"
+ file="config/liquibase/users_authorities.csv"
+ separator=";"
+ tableName="jhi_user_authority"/>
<createTable tableName="jhi_persistent_audit_event">
<column name="event_id" type="bigint" autoIncrement="${autoIncrement}">
<constraints primaryKey="true" nullable="false"/>
--- /dev/null
+id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by
+1;system;$2a$10$mE.qmcV0mFU5NcKh73TZx.z4ueI/.bDWbj0T1BYyqP481kGGarKLG;System;System;system@localhost;;true;en;system;system
+2;anonymoususer;$2a$10$j8S5d7Sr7.8VTOYNviDPOeWX8KcYILUVJBsYV83Y5NtECayypx9lO;Anonymous;User;anonymous@localhost;;true;en;system;system
+3;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system
+4;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system
--- /dev/null
+user_id;authority_name
+1;ROLE_ADMIN
+1;ROLE_USER
+3;ROLE_ADMIN
+3;ROLE_USER
+4;ROLE_USER