Commit 6b52ff0f by Jan Hrabal

fix

parent f94ac8fb
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.date>${maven.build.timestamp}</project.build.date> <project.build.date>${maven.build.timestamp}</project.build.date>
<java.version>8</java.version> <java.version>8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
......
package com.jh.boot;
import com.jh.boot.template.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import com.jh.boot.email.LocalEmailService;
import com.jh.boot.security.utils.TemplateEmailAuthServiceListener;
import com.jh.boot.template.handlebars.HandlebarsTemplateEngine;
public class JhBootApplication {
@Bean
@ConditionalOnProperty(value = "email.local.enabled", havingValue = "true", matchIfMissing = true)
public LocalEmailService emailService() {
return new LocalEmailService();
}
@Bean
@ConditionalOnProperty(value = "auth.listener.email.enabled", havingValue = "true", matchIfMissing = true)
public TemplateEmailAuthServiceListener authServiceListener() {
return new TemplateEmailAuthServiceListener();
}
@Bean
@ConditionalOnMissingBean(TemplateEngine.class)
public TemplateEngine templateEngine() {
return new HandlebarsTemplateEngine();
}
@Bean
@ConditionalOnMissingBean(TemplateLoader.class)
public TemplateLoader templateLoader() {
return new HibernateTemplateLoader();
}
@Bean
@ConditionalOnMissingBean(TemplateService.class)
public TemplateService templateService() {
return new HibernateLoaderTemplateService();
}
@Bean
public TemplateValuesConfig templateValuesConfig() {
return new TemplateValuesConfig();
}
}
package com.jh.boot.attachment;
import java.io.InputStream;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractHibernateAttachmentService implements AttachmentService {
private AttachmentRepository repository;
@Override
public Attachment saveAttachment(Attachment attachment, InputStream content) {
saveAttachment(attachment);
saveData(attachment, content);
return attachment;
}
protected abstract void saveData(Attachment attachment, InputStream stream);
@Override
public Attachment saveAttachment(Attachment attachment) {
repository.save(attachment);
return attachment;
}
@Override
public List<Attachment> fetchAttachments(Long unitId, String objectType, Long objectId) {
return repository.findForUnitIdAndObject(unitId, objectType, objectId);
}
@Override
public Attachment fetchAttachment(Long attachmentId) {
return repository.findById(attachmentId);
}
@Override
public void deleteAttachment(Long attachmentId) {
Attachment a = repository.findById(attachmentId);
if (a != null) {
repository.delete(a);
deleteData(a);
}
}
protected abstract void deleteData(Attachment attachment);
@Autowired(required = false)
public void setRepository(AttachmentRepository repository) {
this.repository = repository;
}
}
package com.jh.boot.attachment;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
/**
* The Class Attachment.
*/
@Entity
@Table(name = "ATTACHMENT")
public class Attachment extends AbstractIdEntity {
/** The unit id. */
@Column(name = "UNIT_ID")
private Long unitId;
/** The object type. */
@Column(name = "OBJECT_TYPE")
private String objectType;
/** The object id. */
@Column(name = "OBJECT_ID")
private Long objectId;
/** The name. */
private String name;
/** The mime type. */
@Column(name = "MIME_TYPE")
private String mimeType;
/** The size. */
@Column(name = "SIZE")
private Long size;
/** The filename. */
@Column(name = "FILENAME")
private String filename;
/** The uploaded. */
@Column(name = "UPLOADED")
private Date uploaded;
/**
* Gets the unit id.
*
* @return the unit id
*/
public Long getUnitId() {
return unitId;
}
/**
* Sets the unit id.
*
* @param unitId the new unit id
*/
public void setUnitId(Long unitId) {
this.unitId = unitId;
}
/**
* Gets the object type.
*
* @return the object type
*/
public String getObjectType() {
return objectType;
}
/**
* Sets the object type.
*
* @param objectType the new object type
*/
public void setObjectType(String objectType) {
this.objectType = objectType;
}
/**
* Gets the object id.
*
* @return the object id
*/
public Long getObjectId() {
return objectId;
}
/**
* Sets the object id.
*
* @param objectId the new object id
*/
public void setObjectId(Long objectId) {
this.objectId = objectId;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the mime type.
*
* @return the mime type
*/
public String getMimeType() {
return mimeType;
}
/**
* Sets the mime type.
*
* @param mimeType the new mime type
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/**
* Gets the size.
*
* @return the size
*/
public Long getSize() {
return size;
}
/**
* Sets the size.
*
* @param size the new size
*/
public void setSize(Long size) {
this.size = size;
}
/**
* Gets the filename.
*
* @return the filename
*/
public String getFilename() {
return filename;
}
/**
* Sets the filename.
*
* @param filename the new filename
*/
public void setFilename(String filename) {
this.filename = filename;
}
/**
* Gets the uploaded.
*
* @return the uploaded
*/
public Date getUploaded() {
return uploaded;
}
/**
* Sets the uploaded.
*
* @param uploaded the new uploaded
*/
public void setUploaded(Date uploaded) {
this.uploaded = uploaded;
}
}
package com.jh.boot.attachment;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import com.jh.boot.jpa.AbstractHibernateRepository;
import com.jh.boot.web.list.Page;
import com.jh.boot.web.list.PagingInfo;
/**
* The Class AttachmentRepository.
*/
@Repository
public class AttachmentRepository extends AbstractHibernateRepository {
/**
* Find for unit id and object.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @param paging the paging
* @return the page
*/
public Page<Attachment> findForUnitIdAndObject(Long unitId, String objectType, Long objectId, PagingInfo paging) {
TypedQuery<Attachment> query = getListQuery(unitId, objectType, objectId);
query.setFirstResult(paging.getPage() * paging.getPageSize());
query.setMaxResults(paging.getPageSize());
//return new Page<>(0, 0, 0, 0, null, objectType, null);
//FIXME
return Page.empty();
}
/**
* Find for unit id and object.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @return the list
*/
public List<Attachment> findForUnitIdAndObject(Long unitId, String objectType, Long objectId) {
TypedQuery<Attachment> query = getListQuery(unitId, objectType, objectId);
return query.getResultList();
}
protected TypedQuery<Attachment> getListQuery(Long unitId, String objectType, Long objectId) {
String hql = "select a from Attachment a";
if (unitId != null || objectType != null || objectId != null) {
hql += " where ";
if (unitId != null) {
hql += " a.unitId = :unitId";
}
if (objectType != null) {
hql += " a.objectType = :objectType";
}
if (objectId != null) {
hql += " a.objectId = :objectId";
}
}
TypedQuery<Attachment> query = entityManager.createQuery(hql, Attachment.class);
if (unitId != null) {
query.setParameter("unitId", unitId);
}
if (objectType != null) {
query.setParameter("objectType", objectType);
}
if (objectId != null) {
query.setParameter("objectId", objectId);
}
return query;
}
/**
* Rename.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @param attachmentId the attachment id
* @param name the name
*/
public void rename(Long attachmentId, String name) {
Attachment a = findById(attachmentId);
a.setName(name);
}
public Attachment findById(Long id) {
return entityManager.find(Attachment.class, id);
}
}
package com.jh.boot.attachment;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.web.multipart.MultipartFile;
public interface AttachmentService {
Attachment saveAttachment(Attachment attachment, InputStream content);
Attachment saveAttachment(Attachment attachment);
List<Attachment> fetchAttachments(Long unitId, String objectType, Long objectId);
Attachment fetchAttachment(Long attachmentId);
InputStream fetchAttachmentBody(Attachment attachment);
void deleteAttachment(Long attachmentId);
// default methods
public default Attachment addAttachment(String objectType, Long objectId, MultipartFile file) {
return addAttachment(null, objectType, objectId, file);
}
public default Attachment addAttachment(Long unitId, String objectType, Long objectId, MultipartFile file) {
Attachment a = new Attachment();
a.setFilename(file.getOriginalFilename());
a.setSize(file.getSize());
a.setObjectId(objectId);
a.setObjectType(objectType);
try {
saveAttachment(a, file.getInputStream());
} catch (Exception e) {
throw new RuntimeException("Cannot upload attachment", e);
}
return a;
}
public default Attachment syncAttachment(String objectType, Long objectId, Attachment currentAttachment, Attachment newAttachment, MultipartFile file) {
return syncAttachment(null, objectType, objectId, currentAttachment, newAttachment, file);
}
public default Attachment syncAttachment(Long unitId, String objectType, Long objectId, Attachment currentAttachment, Attachment newAttachment, MultipartFile file) {
Attachment a = null;
if (currentAttachment != null && newAttachment == null) {
//delete current attachment
deleteAttachment(currentAttachment.getId());
}
if (file != null) {
a = addAttachment(unitId, objectType, objectId, file);
} else {
a = currentAttachment;
}
return a;
}
public default <C extends Collection<Attachment>> C syncAttachments(String objectType, Long objectId, C currentAttachments, C newAttachments, MultipartFile[] files, Class<C> clazz) {
return syncAttachments(null, objectType, objectId, currentAttachments, newAttachments, files, clazz);
}
public default <C extends Collection<Attachment>> C syncAttachments(Long unitId, String objectType, Long objectId, C currentAttachments, C newAttachments, MultipartFile[] files, Class<C> clazz) {
//decide whether Set or List
if (currentAttachments == null) {
if (Set.class.isAssignableFrom(clazz)) {
currentAttachments = (C) new HashSet<Attachment>();
} else if (List.class.isAssignableFrom(clazz)) {
currentAttachments = (C) new ArrayList<Attachment>();
} else {
throw new IllegalArgumentException("Invalid collection type");
}
}
if (newAttachments == null || newAttachments.isEmpty()) {
currentAttachments.clear();
} else {
Iterator<Attachment> it = currentAttachments.iterator();
while (it.hasNext()) {
Attachment a = it.next();
if (!newAttachments.contains(a)) {
it.remove();
}
}
}
//TODO add attachments?
if (files != null && files.length > 0) {
for (MultipartFile f : files) {
currentAttachments.add(addAttachment(unitId, objectType, objectId, f));
}
}
return currentAttachments;
}
}
package com.jh.boot.attachment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
public class FileBasedAttachmentService extends AbstractHibernateAttachmentService {
private String dataDirectory;
@Override
public InputStream fetchAttachmentBody(Attachment attachment) {
try {
return new FileInputStream(file(attachment));
} catch (FileNotFoundException e) {
throw new RuntimeException("File not found", e);
}
}
@Override
protected void saveData(Attachment attachment, InputStream stream) {
try (FileOutputStream fos = new FileOutputStream(file(attachment))) {
IOUtils.copy(stream, fos);
} catch (Exception e) {
throw new RuntimeException("Cannot write data", e);
}
}
@Override
protected void deleteData(Attachment attachment) {
File file = file(attachment);
if (file.exists()) {
file.delete();
file = file.getParentFile();
if (file.listFiles().length == 0) {
//delete ?
file.delete();
}
}
}
protected File file(Attachment attachment) {
Objects.requireNonNull(attachment, "Attachment must not be null");
File file = Paths.get(dataDirectory, s(attachment.getUnitId()), attachment.getObjectType(), s(attachment.getObjectId()), attachment.getFilename()).toFile();
file.getParentFile().mkdirs();
return file;
}
protected String s(Number n) {
return n == null ? "0" : String.valueOf(n);
}
@Value("${attachment.store.path:/var/data}")
public void setDataDirectory(String dataDirectory) {
this.dataDirectory = dataDirectory;
}
}
package com.jh.boot.security;
import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import com.jh.boot.security.model.AppUser;
public class AppUserAuthentication extends AbstractAuthenticationToken {
private static final long serialVersionUID = 1L;
private AppUser user;
public AppUserAuthentication(AppUser user, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.user = user;
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return user;
}
public AppUser getUser() {
return user;
}
@Override
public boolean isAuthenticated() {
return true;
}
}
package com.jh.boot.security;
/**
* The Class AuthError.
*/
public class AuthError {
/** The Constant USERNAME_FIELD. */
public static final String USERNAME_FIELD = "username";
/** The Constant PASSWORD_FIELD. */
public static final String PASSWORD_FIELD = "password";
/** The field. */
String field;
/** The code. */
String code;
/**
* Instantiates a new auth error.
*
* @param field the field
* @param error the error
*/
public AuthError(String field, String error) {
super();
this.field = field;
this.code = error;
}
/**
* Gets the field.
*
* @return the field
*/
public String getField() {
return field;
}
/**
* Gets the code.
*
* @return the code
*/
public String getCode() {
return code;
}
/**
* Username error.
*
* @param error the error
* @return the auth error
*/
public static AuthError usernameError(String error) {
return new AuthError(USERNAME_FIELD, error);
}
/**
* Password error.
*
* @param error the error
* @return the auth error
*/
public static AuthError passwordError(String error) {
return new AuthError(PASSWORD_FIELD, error);
}
}
package com.jh.boot.security;
import java.util.Locale;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import com.jh.boot.security.model.AppUser;
/**
* TODO.
*
* @author jh
*/
public interface AuthService {
/**
* Authenticate.
*
* @param username the username
* @param password the password
* @return the authentication
* @throws BadCredentialsException the bad credentials exception
*/
Authentication authenticate(String username, String password) throws BadCredentialsException;
/**
* Register.
* @param signup the signup
* @param email
* @param locale TODO
*/
void register(String login, String email, String password, Locale locale) throws AuthenticationException;
/**
* This method is responsible for creating new reset password request
* for provided login (or should do nothing if the login is unknown).
*
* <p>The way of letting the user know the token is up to the implementation</p>
*
* @param login
*/
String generateResetToken(String login);
/**
* TODO
* @param resetPassword
* @throws AuthenticationException TODO
*/
void resetPassword(String login, String token, String newPassword) throws AuthenticationException;
void changePassword(String login, String currentPassword, String newPassword) throws AuthenticationException;
/**
* TODO
*
* @param login
*/
void delete(AppUser login);
}
package com.jh.boot.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
/**
* The Class UserAuthenticationProvider.
*/
//TODO
public class AuthServiceAuthenticationProvider implements AuthenticationProvider {
/** The auth service. */
private AuthService authService;
/**
* Authenticate.
*
* @param authentication the authentication
* @return the authentication
* @throws AuthenticationException the authentication exception
* @see org.springframework.security.authentication.AuthenticationProvider#authenticate(org.springframework.security.core.Authentication)
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = String.valueOf(authentication.getPrincipal());
String password = String.valueOf(authentication.getCredentials());
//TODO refactor
return authService.authenticate(email, password);
}
/**
* Supports.
*
* @param authentication the authentication
* @return true, if successful
* @see org.springframework.security.authentication.AuthenticationProvider#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> authentication) {
return true;
}
@Autowired
public void setAuthService(AuthService authService) {
this.authService = authService;
}
}
package com.jh.boot.security;
import com.jh.boot.security.model.AppUser;
import com.jh.boot.security.model.ResetPasswordToken;
public interface AuthServiceListener {
default void registerUser(AppUser user, String password) {
}
default void initializeUser(AppUser user) {
}
default void generateResetToken(AppUser user, ResetPasswordToken token) {
}
default void deleteUser(AppUser user) {
}
}
package com.jh.boot.security;
import org.springframework.security.core.GrantedAuthority;
public class GrantedRole implements GrantedAuthority {
private static final long serialVersionUID = 1L;
private String role;
public GrantedRole(String role) {
super();
this.role = role;
}
@Override
public String getAuthority() {
return role;
}
}
package com.jh.boot.security;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import com.jh.boot.security.repository.AppUserRepository;
import com.jh.boot.security.service.AppUserAuthService;
/**
* The Class ReactApplicationSecurityContext.
*/
public class JhSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* @param http
* @throws Exception
* @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
HttpSecurity cfg = http
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.clearAuthentication(true)
.permitAll()
.and();
cfg.httpBasic();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
http.headers().frameOptions().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/**
* @param auth
* @throws Exception
* @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder)
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
/**
* Override this method to provide custom {@link AuthenticationEntryPoint}.
*
* It returns {@link RestAuthenticationEntryPoint} by default
*
* @return the authentication entry point
*/
protected AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public final void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
};
}
@Bean
public AuthenticationProvider authenticationProvider() {
return new AuthServiceAuthenticationProvider();
}
@Bean
public AuthService authService() {
AppUserAuthService appUserAuthService = new AppUserAuthService();
appUserAuthService.setAppUserRepository(appUserRepository());
return appUserAuthService;
}
@Bean
public AppUserRepository appUserRepository() {
return new AppUserRepository();
}
// @Bean
// public GrantedAuthorityDefaults grantedAuthorityDefaults() {
// return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
// }
}
package com.jh.boot.security;
/**
* The Class PasswordHash.
*/
public class PasswordHash {
/** The hash. */
private String hash;
/** The salt. */
private String salt;
/** The iterations. */
private int iterations;
/**
* Instantiates a new password hash.
*
* @param hash the hash
* @param salt the salt
*/
public PasswordHash(String hash, String salt) {
this(hash, salt, 1);
}
/**
* Instantiates a new password hash.
*
* @param hash the hash
* @param salt the salt
* @param iterations the iterations
*/
public PasswordHash(String hash, String salt, int iterations) {
super();
this.hash = hash;
this.salt = salt;
this.iterations = iterations;
}
/**
* Gets the hash.
*
* @return the hash
*/
public String getHash() {
return hash;
}
/**
* Gets the salt.
*
* @return the salt
*/
public String getSalt() {
return salt;
}
/**
* Gets the iterations.
*
* @return the iterations
*/
public int getIterations() {
return iterations;
}
/**
* @return
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "PasswordHash [hash=" + hash + ", salt=" + salt + ", iterations=" + iterations + "]";
}
}
package com.jh.boot.security;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.springframework.util.StringUtils;
/**
* The Class PasswordSecurity.
*/
public abstract class PasswordUtils {
/** The Constant ITERATIONS. */
private static final int ITERATIONS = 1;
/** The b 64 encoder. */
private static Encoder b64Encoder = Base64.getEncoder();
/** The b 64 decoder. */
private static Decoder b64Decoder = Base64.getDecoder();
/**
* Hash password.
*
* @param password the password
* @return the password hash
*/
public static PasswordHash hashPassword(String password) {
try {
byte[] salt = getSalt();
String hash = createHash(password, salt);
String salt64 = new String(b64Encoder.encode(salt));
return new PasswordHash(hash, salt64);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Check password.
*
* @param password the password
* @param storedHash the stored hash
* @param storedSalt the stored salt
* @return true, if successful
*/
public static boolean checkPassword(String password, String storedHash, String storedSalt) {
if (password == null || storedSalt == null || storedHash == null) {
return false;
}
byte[] salt = b64Decoder.decode(storedSalt);
try {
String hash = createHash(password, salt);
return hash.equals(storedHash);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Validate password.
*
* @param password the password
* @return true, if successful
*/
public static boolean validatePassword(String password) {
return StringUtils.hasText(password);
}
/**
* Creates the hash.
*
* @param password the password
* @param salt the salt
* @return the string
* @throws NoSuchAlgorithmException the no such algorithm exception
* @throws InvalidKeySpecException the invalid key spec exception
*/
protected static String createHash(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, 2048);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
String hash = new String(b64Encoder.encode(factory.generateSecret(spec).getEncoded()));
spec.clearPassword();
return hash;
}
/**
* Gets the salt.
*
* @return the salt
* @throws NoSuchAlgorithmException the no such algorithm exception
*/
private static byte[] getSalt() throws NoSuchAlgorithmException {
//Always use a SecureRandom generator
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
//Create array for salt
byte[] salt = new byte[128];
//Get a random salt
sr.nextBytes(salt);
//return salt
return salt;
}
}
package com.jh.boot.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.jh.boot.security.model.AppUser;
public class SecurityHelper {
private SecurityHelper() {
}
public static AppUser getUser() {
return (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public static AppUser getUser(Authentication auth) {
if (auth == null) {
return null;
}
return (AppUser) auth.getPrincipal();
}
public static boolean hasAnyRole(Authentication auth, String...roles) {
AppUser user = auth instanceof AppUserAuthentication ? ((AppUserAuthentication) auth).getUser() : null;
return hasAnyRole(user, roles);
}
public static boolean hasAnyRole(AppUser user, String... roles) {
if (user == null || user.getRolesMap() == null || roles == null || roles.length == 0) {
return false;
}
for (String role : roles) {
if (user.getRolesMap().containsKey(role)) {
return true;
}
}
return false;
}
}
package com.jh.boot.template;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
public class HibernateLoaderTemplateService implements TemplateService {
private static final Logger LOG = LoggerFactory.getLogger(HibernateLoaderTemplateService.class);
private TemplateLoader loader;
private TemplateEngine engine;
private TemplateValuesConfig valuesConfig;
@Override
@Transactional
public String evaluate(String templateCode, Map<String, Object> data, Locale locale) {
Template t = loader.loadTemplate(templateCode, locale);
if (t == null) {
LOG.warn("Cannot find template {}", templateCode);
return null;
}
Map<String, Object> values = new HashMap<String, Object>();
if (valuesConfig != null) {
values.putAll(valuesConfig.getValues());
}
if (data != null) {
values.putAll(data);
}
String content = t.getTemplate();
StringWriter sw = new StringWriter();
engine.evaluate(sw, content, values);
content = sw.toString();
if (t.getLayoutCode() != null) {
t = loader.loadTemplate(t.getLayoutCode(), locale);
if (t != null) {
values.put("__layout_content__", content);
}
sw = new StringWriter();
engine.evaluate(sw, t.getTemplate(), values);
content = sw.toString();
}
return content;
}
@Autowired
public void setLoader(TemplateLoader loader) {
this.loader = loader;
}
@Autowired
public void setEngine(TemplateEngine engine) {
this.engine = engine;
}
@Autowired
public void setValuesConfig(TemplateValuesConfig valuesConfig) {
this.valuesConfig = valuesConfig;
}
}
package com.jh.boot.template;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
public class HibernateTemplateLoader implements TemplateLoader {
@Autowired
private HibernateTemplateRepository repository;
@Override
@Transactional
public Template loadTemplate(String code, Locale locale) {
Template t = null;
if (locale != null) {
if (StringUtils.hasText(locale.getCountry())) {
t = repository.loadTemplate(code, locale.getLanguage() + "-" + locale.getCountry());
}
if (t == null) {
t = repository.loadTemplate(code, locale.getLanguage());
}
}
if (t == null) {
t = repository.loadTemplate(code, null);
}
return t;
}
}
package com.jh.boot.template;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import com.jh.boot.jpa.AbstractHibernateRepository;
@Repository
public class HibernateTemplateRepository extends AbstractHibernateRepository {
public Template loadTemplate(String code, String locale) {
if (code == null) {
return null;
}
String hql = "select t from Template t where lower(code) = :code";
if (StringUtils.hasText(locale)) {
hql += " and lower(locale) = :locale";
} else {
hql += " and locale is null";
}
TypedQuery<Template> q = entityManager.createQuery(hql, Template.class);
q.setParameter("code", code.toLowerCase());
if (StringUtils.hasText(locale)) {
q.setParameter("locale", locale.toLowerCase());
}
List<Template> list = q.getResultList();
return list == null || list.isEmpty() ? null : list.get(0);
}
}
package com.jh.boot.template;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
@Entity
@Table(name = "TEMPLATE")
public class Template extends AbstractIdEntity {
@Column(name = "CODE")
private String code;
@Column(name = "LAYOUT_CODE")
private String layoutCode;
@Column(name = "TEMPLATE")
private String template;
@Column(name = "LOCALE")
private String locale;
public Template() {
super();
}
public Template(Long templateId) {
super();
setId(templateId);
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getLayoutCode() {
return layoutCode;
}
public void setLayoutCode(String name) {
this.layoutCode = name;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
}
package com.jh.boot.template;
import java.io.Writer;
import java.util.Map;
public interface TemplateEngine {
void evaluate(Writer writer, String templateContent, Map<String, Object> data);
}
\ No newline at end of file
package com.jh.boot.template;
import java.util.Locale;
public interface TemplateLoader {
Template loadTemplate(String code, Locale locale);
}
package com.jh.boot.template;
import java.util.Locale;
import java.util.Map;
public interface TemplateService {
String evaluate(String templateCode, Map<String, Object> data, Locale locale);
}
package com.jh.boot.template;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "template")
public class TemplateValuesConfig {
private Map<String, String> values;
public Map<String, String> getValues() {
return values;
}
public void setValues(Map<String, String> values) {
this.values = values;
}
}
package com.jh.boot.web;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.jh.boot.jpa.AbstractIdEntity;
import com.jh.boot.web.list.Page;
import com.jh.boot.web.list.SortTrend;
public class Converter {
private Converter() {}
public static <S, D> D convert(S source, Function<S, D> mappingFunction) {
if (source == null || mappingFunction == null) {
return null;
}
return mappingFunction.apply(source);
}
public static <S, D> Set<D> convertSet(Collection<S> list, Function<S, D> mappingFunction) {
if (list == null) {
return null;
}
return list.stream().map(mappingFunction).collect(Collectors.toSet());
}
public static <S, D> List<D> convertList(Collection<S> list, Function<S, D> mappingFunction) {
if (list == null) {
return null;
}
return list.stream().map(mappingFunction).collect(Collectors.toList());
}
public static <S, D> Page<D> convertPage(Page<S> page, Function<S, D> mappingFunction) {
if (page == null || mappingFunction == null) {
return null;
}
List<D> content = new ArrayList<>();
if (page.getContent() != null) {
for (S s : page.getContent()) {
content.add(mappingFunction.apply(s));
}
}
return new Page<D>(page.getPage(), page.getPagesCount(), page.getPageSize(), page.getTotalElements(), content, page.getSortBy(), SortTrend.parse(page.getTrend()));
}
public static <T> List<IdNameDto> mapToDtos(Collection<T> collection, Function<T, Long> getId, Function<T, String> getName) {
if (collection == null || collection.isEmpty() || getId == null || getName == null) {
return Collections.emptyList();
}
List<IdNameDto> result = new ArrayList<IdNameDto>();
for (T t : collection) {
result.add(new IdNameDto(getId.apply(t), getName.apply(t)));
}
return result;
}
//public static <T> T toEntity(IdNameDto )
/**
* Helper function to safely get id
*
* @param entity
* @return
*/
public static Long getId(AbstractIdEntity entity) {
return entity == null ? null : entity.getId();
}
}
/*
* Created on 29. 1. 2018 13:40:45
*
*/
package com.jh.boot.web;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.util.WebUtils;
/**
* The Class FallbackLocaleResolver.
*
* @author Jan Hrabal
*/
public class FallbackLocaleResolver extends AcceptHeaderLocaleResolver/* LocaleResolver*/ {
/** The locales string. */
@Value("${app.locales:en}")
private String localesString;
/** The default locale. */
@Value("${app.locale.default:en}")
private String defaultLocale;
/** The default country. */
@Value("${app.locale.defaultCountry:US}")
private String defaultCountry;
/** The locales. */
private Set<String> locales;
/**
* Inits the.
*/
@PostConstruct
public void init() {
locales = new LinkedHashSet<>();
if (localesString != null) {
String[] ls = localesString.split("[\\s,;]");
for (String s : ls) {
if (StringUtils.hasText(s)) {
locales.add(s.trim().toLowerCase());
}
}
} else {
locales.add("en");//TODO default config?
}
if (defaultLocale == null) {
defaultLocale = "en";
} else {
defaultLocale = defaultLocale.trim().toLowerCase();
}
}
/**
* Resolve locale.
*
* @param httpRequest the http request
* @return the locale
* @see org.springframework.web.servlet.LocaleResolver#resolveLocale(javax.servlet.http.HttpServletRequest)
*/
@Override
public Locale resolveLocale(HttpServletRequest httpRequest) {
String code = null;
//get param
String lang = httpRequest.getParameter("lang");
if (StringUtils.hasText(lang)) {
if (locales.contains(langCode(lang))) {
code = lang;
}
}
Cookie c = WebUtils.getCookie(httpRequest, "lang");
if (c != null) {
lang = c.getValue();
if (StringUtils.hasText(lang)) {
if (locales.contains(langCode(lang))) {
code = lang;
}
}
}
if (code == null) {
String acceptLanguage = httpRequest.getHeader("Accept-Language");
if (StringUtils.hasText(acceptLanguage)) {
String[] als = acceptLanguage.split(",");
for (String s : als) {
if (locales.contains(langCode(s))) {
code = s;
break;
}
}
}
}
String country = null;
if (code == null) {
code = defaultLocale;
country = defaultCountry;
} else {
country = countryCode(code);
code = langCode(code);
}
return country == null ? new Locale(code) : new Locale(code, country);
}
/**
* Sets the locale.
*
* @param arg0 the arg 0
* @param arg1 the arg 1
* @param arg2 the arg 2
* @see org.springframework.web.servlet.LocaleResolver#setLocale(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.util.Locale)
*/
@Override
public void setLocale(HttpServletRequest arg0, HttpServletResponse arg1, Locale arg2) {
// TODO do nothing
}
/**
* Lang code.
*
* @param s the s
* @return the string
*/
protected String langCode(String s) {
if (s == null) {
return defaultLocale;
}
s = s.trim().toLowerCase();
if (s.length() > 2) {
return s.substring(0, 2);
}
return s;
}
/**
* Lang name.
*
* @param s the s
* @return the string
*/
protected String langName(String s) {
if (s == null) {
return defaultLocale;
}
return s.trim().replace("-", "_");
}
/**
* Country code.
*
* @param s the s
* @return the string
*/
protected String countryCode(String s) {
if (s == null || s.length() < 5 ) {
return null;
}
return s.substring(3);
}
}
package com.jh.boot.web;
import org.springframework.http.HttpStatus;
import org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The Class GlobalControllerExceptionHandler.
*/
@ControllerAdvice
class GlobalControllerExceptionHandler {
/**
* Handle conflict.
*/
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(HibernateOptimisticLockingFailureException.class)
public void handleConflict() {
}
}
\ No newline at end of file
package com.jh.boot.web;
public class IdNameDto {
private Long id;
private String name;
public IdNameDto() {
}
public IdNameDto(Long id, String name) {
super();
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.jh.boot.web;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module.Feature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jh.boot.web.list.PagingArgumentResolver;
import com.jh.boot.web.list.SortingArgumentResolver;
public class JhWebConfig implements WebMvcConfigurer {
/**
* @param converters
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureMessageConverters(java.util.List)
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
converters.add(converter);
}
/**
* Object mapper.
*
* @return the object mapper
*/
@Bean
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(Include.NON_NULL);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(new JavaTimeModule());
Hibernate5Module module = new Hibernate5Module();
module.disable(Feature.USE_TRANSIENT_ANNOTATION);
module.enable(Feature.REPLACE_PERSISTENT_COLLECTIONS);
om.registerModule(module);
return om;
}
/**
* @param argumentResolvers
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addArgumentResolvers(java.util.List)
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new PagingArgumentResolver());
argumentResolvers.add(new SortingArgumentResolver());
}
/**
* Locale resolver.
*
* @return the locale resolver
*/
@Bean
@Primary
public LocaleResolver localeResolver() {
return new FallbackLocaleResolver();
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
/**
* @param configurer
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configurePathMatch(org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
// .setUseTrailingSlashMatch(false)
// .setUseRegisteredSuffixPatternMatch(true)
// .setPathMatcher(antPathMatcher())
// .setUrlPathHelper(urlPathHelper());
}
}
package com.jh.boot.web;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
/**
* The Class LocalDateControllerAdvice.
*/
@ControllerAdvice
public class LocalDateControllerAdvice {
/**
* Inits the binder.
*
* @param binder the binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_DATE));
}
});
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment