|  | @@ -0,0 +1,145 @@
 | 
	
		
			
				|  |  | +package id.co.hanoman.ngdemo;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import java.security.MessageDigest;
 | 
	
		
			
				|  |  | +import java.security.NoSuchAlgorithmException;
 | 
	
		
			
				|  |  | +import java.util.UUID;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import javax.servlet.http.HttpServletRequest;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import org.slf4j.Logger;
 | 
	
		
			
				|  |  | +import org.slf4j.LoggerFactory;
 | 
	
		
			
				|  |  | +import org.springframework.beans.factory.annotation.Autowired;
 | 
	
		
			
				|  |  | +import org.springframework.security.core.context.SecurityContextHolder;
 | 
	
		
			
				|  |  | +import org.springframework.stereotype.Component;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.LoginRequest;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.LoginUser;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.RefreshTokenRequest;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.TokenAuthentication;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.domain.AuthToken;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.domain.SecurityUser;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.rs.AuthenticationException;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.rs.InvalidRefreshTokenException;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.rs.InvalidSaltException;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.rs.InvalidUserPasswordException;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.service.AuthenticationService;
 | 
	
		
			
				|  |  | +import com.senomas.boot.security.service.TokenService;
 | 
	
		
			
				|  |  | +import com.senomas.common.RateLimiterService;
 | 
	
		
			
				|  |  | +import com.senomas.common.U;
 | 
	
		
			
				|  |  | +import com.senomas.common.rs.InvalidTimestampException;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import id.co.hanoman.ngdemo.domain.AppUser;
 | 
	
		
			
				|  |  | +import id.co.hanoman.ngdemo.domain.AppUserRepository;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@Component
 | 
	
		
			
				|  |  | +public class AuthenticationServiceImpl implements AuthenticationService {
 | 
	
		
			
				|  |  | +	private static final Logger log = LoggerFactory.getLogger(AuthenticationServiceImpl.class);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	@Autowired
 | 
	
		
			
				|  |  | +	protected AppUserRepository userRepo;
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	@Autowired
 | 
	
		
			
				|  |  | +	protected RateLimiterService rateLimiterService;
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	@Autowired
 | 
	
		
			
				|  |  | +	protected TokenService tokenService;
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	@Override
 | 
	
		
			
				|  |  | +	public AuthToken login(HttpServletRequest request, LoginRequest login) {
 | 
	
		
			
				|  |  | +		if (Math.abs(System.currentTimeMillis() - login.getTimestamp().getTime()) > 300000) {
 | 
	
		
			
				|  |  | +			log.info("TIMESTAMP " + System.currentTimeMillis() + "  "
 | 
	
		
			
				|  |  | +					+ (System.currentTimeMillis() - login.getTimestamp().getTime()));
 | 
	
		
			
				|  |  | +			throw new InvalidTimestampException();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!rateLimiterService.acquire("/ip/auth", request.getRemoteAddr())) {
 | 
	
		
			
				|  |  | +			throw new AuthenticationException("Too many request");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if (!rateLimiterService.acquire("/auth", login.getLogin())) {
 | 
	
		
			
				|  |  | +			throw new AuthenticationException("Too many request");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (login.getSalt() == null)
 | 
	
		
			
				|  |  | +			throw new InvalidSaltException(login.getTimestamp().getTime(), generateSalt(request, login),
 | 
	
		
			
				|  |  | +					"Invalid salt");
 | 
	
		
			
				|  |  | +		String salt = generateSalt(request, login);
 | 
	
		
			
				|  |  | +		if (!salt.equals(login.getSalt()))
 | 
	
		
			
				|  |  | +			throw new InvalidSaltException(login.getTimestamp().getTime(), generateSalt(request, login),
 | 
	
		
			
				|  |  | +					"Invalid salt");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		AppUser user = userRepo.findOne(login.getLogin());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (user == null) {
 | 
	
		
			
				|  |  | +			log.info("INVALID LOGIN [" + login.getLogin() + "]");
 | 
	
		
			
				|  |  | +			throw new InvalidUserPasswordException();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		String securePasscode = U.digest(user.getPasscode(), "|", login.getSalt());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!securePasscode.equals(login.getSecurePasscode())) {
 | 
	
		
			
				|  |  | +			log.info("INVALID TOKEN ["+user.getPasscode()+"]  [" + securePasscode + "]  [" + login.getSecurePasscode() + "]");
 | 
	
		
			
				|  |  | +			throw new InvalidUserPasswordException();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		LoginUser loginUser = tokenService.create(user);
 | 
	
		
			
				|  |  | +		log.info("LOGIN-USER "+U.dump(loginUser));
 | 
	
		
			
				|  |  | +		String token = loginUser.getToken();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		String refreshToken = UUID.randomUUID().toString();
 | 
	
		
			
				|  |  | +		user.setLoginToken(refreshToken);
 | 
	
		
			
				|  |  | +		userRepo.save(user);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		return new AuthToken(token, refreshToken, user);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	protected String generateSalt(HttpServletRequest request, LoginRequest login) {
 | 
	
		
			
				|  |  | +		try {
 | 
	
		
			
				|  |  | +			MessageDigest md = MessageDigest.getInstance("SHA-256");
 | 
	
		
			
				|  |  | +			md.update(U.getBytes(login.getLogin()));
 | 
	
		
			
				|  |  | +			md.update(U.getBytes(request.getRemoteAddr()));
 | 
	
		
			
				|  |  | +			md.update(U.getBytes(login.getTimestamp().getTime()));
 | 
	
		
			
				|  |  | +			return U.encode64(md.digest());
 | 
	
		
			
				|  |  | +		} catch (NoSuchAlgorithmException e) {
 | 
	
		
			
				|  |  | +			throw new RuntimeException(e.getMessage(), e);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	@Override
 | 
	
		
			
				|  |  | +	public SecurityUser getUser() {
 | 
	
		
			
				|  |  | +		AppUser user = (AppUser) ((TokenAuthentication) SecurityContextHolder.getContext().getAuthentication()).getUser();
 | 
	
		
			
				|  |  | +		return user;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	@Override
 | 
	
		
			
				|  |  | +	public AuthToken refresh(HttpServletRequest request, RefreshTokenRequest refreshToken) {
 | 
	
		
			
				|  |  | +		if (Math.abs(System.currentTimeMillis() - refreshToken.getTimestamp().getTime()) > 300000) {
 | 
	
		
			
				|  |  | +			log.info("TIMESTAMP " + System.currentTimeMillis() + "  "
 | 
	
		
			
				|  |  | +					+ (System.currentTimeMillis() - refreshToken.getTimestamp().getTime()));
 | 
	
		
			
				|  |  | +			throw new InvalidTimestampException();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!rateLimiterService.acquire("/ip/auth", request.getRemoteAddr())) {
 | 
	
		
			
				|  |  | +			throw new AuthenticationException("Too many request");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if (!rateLimiterService.acquire("/auth", refreshToken.getLogin())) {
 | 
	
		
			
				|  |  | +			throw new AuthenticationException("Too many request");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +		AppUser user = userRepo.findOne(refreshToken.getLogin());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (user == null) {
 | 
	
		
			
				|  |  | +			log.info("INVALID LOGIN [" + refreshToken.getLogin() + "]");
 | 
	
		
			
				|  |  | +			throw new InvalidRefreshTokenException("Invalid login");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +		if (!U.digest(String.valueOf(refreshToken.getTimestamp().getTime()), "|", user.getLogin(), "|", user.getLoginToken()).equals(refreshToken.getRefreshTokenHash())) {
 | 
	
		
			
				|  |  | +			log.info("INVALID REFRESH-TOKEN " + U.dump(refreshToken));
 | 
	
		
			
				|  |  | +			throw new InvalidRefreshTokenException("Invalid refresh-token");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		LoginUser loginUser = tokenService.create(user);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		return new AuthToken(loginUser.getToken(), null, user);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 |