I have class Registration with username email password
I have following function in dao , service classes
public Registration get( Integer id ) {
logger.debug("Getting person");
return registrationDAO.findUserByID(id);
}
#Resource(name="registrationService")
private RegistrationService registrationService;
public Registration findUserByID(Integer ID) {
try {
Session session = sessionFactory.getCurrentSession();
Registration person = (Registration) session.get(Registration.class, ID);
return person;
} catch (Exception e) {
System.out.println(e);
throw new RuntimeException("DAO failed", e);
}
}
I am using that function in following function
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
// Declare a null Spring User
UserDetails user = null;
logger.debug(username);
//for testing -- i get error here
Registration regUser = registrationService.get(1);
logger.debug(regUser);
try {
DbUser dbUser = userDAO.searchDatabase(username);
I get error when i add this line
Registration regUser = registrationService.get(1);
logger.debug(regUser);
Edit: For clarified question
#Resource
private RegistrationService registrationService;
See the tutorial at: http://download.oracle.com/javaee/5/tutorial/doc/bncjk.html#bncjl
Related
I am working with Spring boot and Spring security to build a back end application, I am storing users into Cloud Firestore NonRelational Database, I am using an Admin SDK token provided by Google on the Firebase platform. I am initializing my Firestore in the following way.
#Service
public class UserFirestoreInitialize {
#Value("classpath:static/gamingplatform-c922d-firebase-adminsdk-c25o8-06e92edfd5.json")
Resource resourceFile;
#PostConstruct
public void initialize() {
try {
InputStream serviceAccount = resourceFile.getInputStream();
GoogleCredentials cred = GoogleCredentials.fromStream(serviceAccount)
.createScoped("https://www.googleapis.com/auth/datastore");
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(cred)
.setDatabaseUrl("FIREBASE_URL")
.build();
FirebaseApp.initializeApp(options);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
I also had a Configuration class which looks like this.
#Configuration
public class UserFirestoreConfiguration{
#Bean
public Firestore getFirestore(){
return FirestoreClient.getFirestore();
}
}
After this, I could easily use this bean in my UserService as follows:
#Service
public class UserService{
#Autowired
private Firestore firestore;
public User getUser(){
//Query for user.
}
//Post, Put, delete
}
This worked at some point. The problem came when I added Spring Security into my applicatio. When I ran a Maven Install, the application did not build, the problem looks like this:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jwtTokenFilter': Unsatisfied dependency expressed through field 'userDetailsService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceDetailsImpl' defined in file [/Users/igorzelaya/SoftwareDev/D1Gaming-User-Back-end1/target/classes/com/d1gaming/user/security/UserServiceDetailsImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [/Users/igorzelaya/SoftwareDev/D1Gaming-User-Back-end1/target/classes/com/d1gaming/user/user/UserService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.d1gaming.user.user.UserService]: Constructor threw exception; nested exception is java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
I have a tried to isolate the problem, I created the another project and tried connecting to my database like I did in the snippet above^, everything worked just fine, I then copied my configuration classes one by one, I figured my application started to crash the moment I added my JWT Token Filter class, this class looks like this
#Component
public class JwtTokenFilter extends OncePerRequestFilter{
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private UserServiceDetailsImpl userDetailsService;
#Override
//Get authorization header and validate it.
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException, NullPointerException {
try {
String jwt = parseJwt(request);
if(jwt != null && jwtTokenUtil.validate(jwt)) {
String username = jwtTokenUtil.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
catch(Exception e) {
logger.error("Cannot set user authentication: {}", e);
}
chain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if(StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7, headerAuth.length());
}
return null;
}
}
As you can notice on my stack trace shown above, the error starts on the dependencies injected in this class, the jwtTokenUtil class and the UserDetailsImpl
the JwtTokenUtil class is this:
#Component
public class JwtTokenUtil {
#Value("${app.jwtSecret}")
private String jwtSecret;
#Value("${app.jwtExpirationMs}")
private int jwtExpirationMs;
private final Logger logger = LoggerFactory.getLogger(JwtTokenUtil.class);
public String generateJwtToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
return Jwts.builder()
.setSubject(userPrincipal.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parser().setSigningKey(jwtSecret)
.parseClaimsJws(token).getBody().getSubject();
}
public String getUserId(String token) {
Claims claims = Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody();
return claims.getSubject().split(",")[0];
}
public String getUsername(String token) {
Claims claims = Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody();
return claims.getSubject().split(",")[0];
}
public Date getExpirationDate(String token) {
Claims claims = Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody();
return claims.getExpiration();
}
public boolean validate(String token) {
try {
Jwts.parser()
.setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
}
catch(SignatureException e) {
logger.error("Invalid JWT signature - {}",e.getMessage());
}
catch(MalformedJwtException e) {
logger.error("Invalid JWT token - {}", e.getMessage());
}
catch(ExpiredJwtException e) {
logger.error("Invalid JWT token - {}",e.getMessage());
}
catch(UnsupportedJwtException e) {
logger.error("Invalid JWT token - {}", e.getMessage());
}
catch(IllegalArgumentException e) {
logger.error("Invalid JWT token - {}", e.getMessage());
}
return false;
}
}
The UserServiceDetailsImpl class:
public class UserDetailsImpl implements UserDetails{
private static final long serialVersionUID = 1L;
private String userId;
private String userRealName;
private String userName;
#JsonIgnore
private String userPassword;
private String userEmail;
private UserStatus userStatusCode;
private Team userTeam;
private Map<String,Object> userBilling;
private String userCountry;
private int userTokens;
private double userCash;
private Map<String, Object> userBirthDate;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(String userId, String userRealName, String userName, String userPassword, String userEmail,
UserStatus userStatusCode, Team userTeam, Map<String, Object> userBilling, String userCountry,
int userTokens, double userCash, Map<String, Object> userBirthDate,
Collection<? extends GrantedAuthority> authorities) {
this.userId = userId;
this.userRealName = userRealName;
this.userName = userName;
this.userPassword = userPassword;
this.userEmail = userEmail;
this.userStatusCode = userStatusCode;
this.userTeam = userTeam;
this.userBilling = userBilling;
this.userCountry = userCountry;
this.userTokens = userTokens;
this.userCash = userCash;
this.userBirthDate = userBirthDate;
this.authorities = authorities;
}
public static UserDetailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getUserRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getRoleType().name()))
.collect(Collectors.toList());
return new UserDetailsImpl(user.getUserId(),user.getUserRealName(),user.getUserName(),user.getUserPassword(),user.getUserEmail()
,user.getStatusCode(),user.getUserTeam(),user.getUserBilling(),user.getUserCountry(),
user.getUserTokens(),user.getUserCash(),user.getUserBirthDate(),authorities
);
}
//Getters and setters
}
As you can see, these classes both have nothing to do with Firestore, At the moment I was pretty confused so I did the following. I noticed that for some strange reason the #PostConstruct annotation was not working, Spring was not initializing my initializeFirestore() method on the first snippet of code, so I placed a initialize() method directly on spring boot as follows:
#SpringBootApplication
public class UserApplication(){
public static void main(String[] args) {
//Basically does the same as the initialize method mentioned before.
UserFirestoreUtils.initialize(UserFirestoreUtils.getOptions());
SpringApplication.run(D1GamingUserBackEnd1Application.class, args);
}
}
The interesting thing is that when I debugged this I had the following error:
The dependencies of some of the beans in the application context form a cycle:
jwtTokenFilter (field private com.d1gaming.user.security.UserServiceDetailsImpl com.d1gaming.user.security.JwtTokenFilter.userDetailsService)
┌─────┐
| userServiceDetailsImpl defined in file [/Users/igorzelaya/SoftwareDev/D1Gaming-User-Back-end1/target/classes/com/d1gaming/user/security/UserServiceDetailsImpl.class]
↑ ↓
| userService (field private org.springframework.security.crypto.password.PasswordEncoder com.d1gaming.user.user.UserService.passwordEncoder)
↑ ↓
| userSecurityConfiguration (field com.d1gaming.user.security.UserServiceDetailsImpl com.d1gaming.user.security.UserSecurityConfiguration.userDetailsService)
└─────┘
The weird thing is that when I run a Maven install on it, the stack trace is the same as the one I showed at the beginning of the question, I feel there is not enough documentation on Cloud Firestore and its normal considering it is "New", but still it was annoying because I couldn't find the "Right way" of doing this and Google Documentation was clearly not enough. I am sorry If I included way too much code, I think it is necessary, but anyways thank you for your time, I appreciate if anyone could help me. Have a nice day.
This looks like a collision between Spring dependencies and Firebase Admin. You can try with Firestore client library. Firebase admin SDK is a wider library that some part of code can collision with Spring security
I trying to implement spring security + jwt.I done log-in and log-out methods, jwt filter,provider and web config is configured. So the main problem is my controller and how to return error messages to user, for example if user typed wrong password/username or user account is banned etc.
I got a structure built on exception handling, looks terible.
controller
#PostMapping("/log-in")
public ResponseEntity logIn(#RequestBody UserDto userDto) {
log.info("[LOG-IN] user with username " + userDto.getUsername());
try {
HashMap<String, String> response = userService.logIn(userDto);
return ResponseEntity.ok(response);
} catch (UserStatusException ex) {
return ResponseEntity.badRequest().body("Account is Pending");
} catch (UsernameNotFoundException ex) {
return ResponseEntity.badRequest().body("Could not find account!");
} catch (AuthenticationException ex) {
log.error("Wrong username or password!");
return ResponseEntity.badRequest().body("Wrong username or password!");
}
}
service
#Override
public HashMap<String, String> logIn(UserDto userDto)throws AuthenticationException, UserStatusException{
User user = findByUsername(userDto.getUsername());
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userDto.getUsername(), userDto.getPassword())); //login
checkUserStatus(user); //check if user pending or banned
user.setUserStatus(UserStatus.ACTIVE);
String token = jwtTokenProvider.createToken(user.getUsername(), user.getUserRoles());
HashMap<String, String> response = new HashMap<>();
response.put("token", token);
response.put("username", user.getUsername());
userRepository.save(user);
return response;
}
#Override
public User findByUsername(String username)throws UsernameNotFoundException {
log.info("[UserService, findByUsername]");
User user = userRepository.findByUsername(username);
if(user == null){
log.error("User not found with {} username: ", username);
throw new UsernameNotFoundException("User not found!");
}
log.info("User {} successfully loaded ",username);
return user;
}
#Override
public void checkUserStatus(User user)throws UserStatusException {
if (user.getUserStatus().equals(UserStatus.BANNED)
|| user.getUserStatus().equals(UserStatus.PENDING)) {
throw new UserStatusException("Not confirmed");
}
}
Is there any other way to replace this structure?
You should use a ControllerAdvice (see a tutorial here).
It's a special class that look like this
#ControllerAdvice
public class ControllerAdvice {
#ExceptionHandler(PersonNotFoundException.class)
public ResponseEntity <VndErrors > notFoundException(final PersonNotFoundException e) {
return error(e, HttpStatus.NOT_FOUND, e.getId().toString());
}
}
It will allow you to bind a specific return code and response to each exception you need to handle, and it will automatically catch all exception returned by your controller. It's also a good way to handle all exceptions at the same place instead of over each exceptions...
I'm not sure about it, but I think you even can bind it to a specific mapping of your API for more granularity.
Hope this help! Have fun!
You could add the repose status directly to your custom exception class:
#ResponseStatus(HttpStatus.BAD_REQUEST)
public class UsernameNotFoundException extends RuntimeException {
public UsernameNotFoundException(String message) {
super(message);
}
public UsernameNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
In this way you don't need anymore to catch them in the controller and add the message and the status in ResponseEntity.
In spring boot Junit testing when it call when(mockRestTemplate.postForObject(Mockito.any(), Mockito.any(),Mockito.any())).thenReturn(searchDTO) return null instead of searchDTO.
#RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest {
#InjectMocks
private UserServiceImpl userService;
#Mock
private RestTemplate mockRestTemplate;
#Mock
private BeanMapperUtil mockBeanMapperUtil;
#Mock
private UserDomain mockUserDomain;
/**
* This method will test find by SSN method running as per code or not
*
* #throws Exception
*/
#Test
public void findBySSNTest() throws Exception {
UserDTO userDTO = getUserDTO("93ff6e85-fcf4-40c3-9ae8-566791daafa6");
SearchDTO searchDTO = new SearchDTO();
searchDTO.setUid("93ff6e85-fcf4-40c3-9ae8-566791daafa6");
when(mockUserDomain.findByUID("93ff6e85-fcf4-40c3-9ae8-566791daafa6"))
.thenReturn(getUser("93ff6e85-fcf4-40c3-9ae8-566791daafa6"));
when(mockRestTemplate.postForObject(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(searchDTO);
when(mockBeanMapperUtil.createDtoFromEntity(Mockito.any(), Mockito.any())).thenReturn(userDTO);
UserDTO mockUserDTO = userService.findBySSN("123-45-6022");
Assert.assertEquals(mockUserDTO, userDTO);
}
/**
*
* This method is used to get User in methods for testing
*
* #return User
*
*/
private User getUser(String id) {
User mockUser = new User();
mockUser.setUid(id);
mockUser.setFirstName("test");
mockUser.setLastName("test");
mockUser.setEmail("Test#test.com");
mockUser.setAddressLine1("Temp Address");
mockUser.setCity("Temp");
return mockUser;
}
private UserDTO getUserDTO(String id) throws ParseException {
UserDTO mockUserDTO = new UserDTO();
mockUserDTO.setUid(id);
mockUserDTO.setFirstName("test");
mockUserDTO.setLastName("test");
mockUserDTO.setEmail("Test#test.com");
mockUserDTO.setAddressLine1("Temp Address");
mockUserDTO.setCity("Temp");
return mockUserDTO;
}
}
This test is link with UserServiceImpl class and here is implementation of UserServiceImpl class where I found null instead of searchDTO at
SearchDTO searchDTO = restTemplate.postForObject( REST_END_POINT_STAFF_MASTER_FIND_SSN , requestBody,SearchDTO.class);
UserServiceImpl method where it is call and All other variables are define in class already Found error of NullpointerException at getting searchDTO by restTemplate.
public UserDTO findBySSN(String id) throws UserServiceException {
try {
logger.logMethodStart(MessageConstant.METHOD_FIND_BY_USER_WORK_DAY_ID);
Map<String, String> ssnMap = new HashMap<String, String>();
ssnMap.put("ssn", id);
HttpEntity<Map<String, String>> requestBody = new HttpEntity<>(ssnMap);
SearchDTO searchDTO = restTemplate.postForObject(REST_END_POINT_STAFF_MASTER_FIND_SSN, requestBody,
SearchDTO.class);
System.out.println(searchDTO);
UserDTO userDTO = null;
if (searchDTO != null && searchDTO.getUid() != null) {
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, "SearchDTO :", searchDTO);
userDTO = findByUID(searchDTO.getUid());
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, "Find user by UID", userDTO);
// If the DTO is null, it means request for new external user, so
// it'll create a new external user with returned UID and return it.
if (userDTO != null) {
userDTO.setNewExternalUser(false);
logger.logMethodEnd(MessageConstant.METHOD_FIND_BY_USER_SSN, userDTO);
return userDTO;
}
// If the userDTO is not null, it means found userDTO is not new external user,
// So, set corresponding field to false
userDTO = new UserDTO();
userDTO.setUid(searchDTO.getUid());
userDTO.setNewExternalUser(true);
logger.logMethodEnd(MessageConstant.METHOD_FIND_BY_USER_SSN, userDTO);
return userDTO;
} else {
String msg = messageSource.getMessage(ErrorMessageEnum.USER_STAFF_MASTER_ERROR.toString(), null,
Locale.getDefault());
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, msg);
throw new UserServiceException(msg, UserServiceExceptionEnum.GET_USER_BY_SSN.toString(),
searchDTO.toString(), null);
}
} catch (UserServiceException e) {
throw e;
} catch (Exception e) {
String msg = messageSource.getMessage(ErrorMessageEnum.USER_FIND_BY_SSN_ERROR.toString(), null,
Locale.getDefault());
logger.logException(MessageConstant.METHOD_FIND_BY_USER_SSN, e, msg);
throw new UserServiceException(msg, UserServiceExceptionEnum.GET_USER_BY_SSN.toString(), e.getMessage(),
null);
}
}
Try this:
when(mockRestTemplate.postForObject(Mockito.any(String.class),
Mockito.any(HttpEntity.class),
Mockito.eq(SearchDTO.class)))
.thenReturn(searchDTO);
I'm trying to use #DELETE request after a made some simple web application which I've tested using soapui. With this application I can add and get users/book to database. Now I'm trying to made a #DELETE request but I can't make it. Here is the code:
//UserServiceImpl
#PersistenceContext
private EntityManager em;
#Override
public void deleteUser(Long id) {
if (null == id || id.longValue() < 1) {
throw new IllegalArgumentException(" User id can not be null or less than zero. ");
}
User u = em.find(User.class, id);
em.remove(u);
}
//UserResource
#Autowired
private UserService userService;
#DELETE
#Path("/delete/{id}")
public Response deleteUser(#PathParam("id") String id) {
Response response;
try {
User user = userService.deleteUser(Long.valueOf(id));//here is the error
if (user != null) {
response = Response.status(HttpServletResponse.SC_OK).entity(user).build();
} else {
response = Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
} catch (IllegalArgumentException e) {
response = Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
return response;
}
I`ve fix my problem. The delete method which is in UserServiceImpl must not be void.... it must be public User deleteUser(Long id). The other delete method in Resource class ... just need to be of void type. There i do not use Response and i simply print the result like this:
System.out.print(Response.status(HttpServletResponse.SC_OK).entity(user).build());
So I have set up my shiro to have two Realms. A Username and Password Realm, using the standard UsernamePasswordToken. I have also set up a Custom Bearer Authentication Token that works off a token passed in from the user.
If i just use my passwordValidatorRealm it works find, if no user is found throws unknown account, if password doesn’t match throws incorrect credentials, perfect. But as soon as i put in my tokenValidatorRealm it throws a
org.apache.shiro.authc.AuthenticationException: Authentication token of type [class org.apache.shiro.authc.UsernamePasswordToken] could not be authenticated by any configured realms.
In this instance my tokenValidatorRealm returns null as no token was provided, so it moves on to the passwordValidatorRealm and just breaks.
Any ideas why introducing a second Realm will cause my working passwordValidatorRealm to break?
Have tried with different authentication strategies, and no luck there.
Using shiro 1.2.2
EDIT
I have two implementations, one for password and one for token
Password:
public class PasswordAuthorizingRealm extends AuthenticatingRealm {
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (authenticationToken instanceof UsernamePasswordToken) {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
String username = usernamePasswordToken.getUsername();
char[] password = usernamePasswordToken.getPassword();
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm!");
}
//Null password is invalid
if (password == null) {
throw new AccountException("Null passwords are not allowed by this realm!");
}
UserService userService = new UserServiceImpl();
User user = userService.getUserByUsername(username);
if (user == null) {
throw new UnknownAccountException("Could not authenticate with given credentials");
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(), "passwordValidatorRealm");
return simpleAuthenticationInfo;
} else {
return null;
}
}
}
and Bearer Token
public class TokenAuthorizingRealm extends AuthorizingRealm {
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (authenticationToken instanceof BearerAuthenticationToken) {
BearerAuthenticationToken bearerAuthenticationToken = (BearerAuthenticationToken) authenticationToken;
String username = "" + bearerAuthenticationToken.getPrincipal();
User user = userService.getUserByUsername(username);
//User with such username has not found
if (user == null) {
throw new UnknownAccountException("Could not authenticate with given credentials");
}
BearerAuthenticationInfo bearerAuthenticationInfo = new BearerAuthenticationInfo(user);
return bearerAuthenticationInfo;
}
}
Shiro config
[main]
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
hashService.privateSalt = ****
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordMatcher.passwordService = $passwordService
authc = my.BearerTokenAuthenticatingFilter
tokenValidatorRealm = my.TokenAuthorizingRealm
passwordValidatorRealm = my.PasswordAuthorizingRealm
passwordValidatorRealm.credentialsMatcher = $passwordMatcher
securityManager.realms = $tokenValidatorRealm,$passwordValidatorRealm
These have been stripped out a bit, removed logging and other unnecessary code
The BearerTokenAuthenticatingFilter, just basically checks if a token has been supplied in the header if has
private void loginUser(ServletRequest request, ServletResponse response) throws Exception {
BearerAuthenticationToken token = (BearerAuthenticationToken) createToken(request, response);
if (token == null) {
String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken "
+ "must be created in order to execute a login attempt.";
throw new IllegalStateException(msg);
}
try {
Subject subject = getSubject(request, response);
subject.login(token);
onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException e) {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.sendRedirect("login");
}
}
BearerAuthenticationInfo class
public class BearerAuthenticationInfo implements AuthenticationInfo {
private final PrincipalCollection principalCollection;
private final User user;
public BearerAuthenticationInfo(User user) {
this.user = user;
this.principalCollection = buildPrincipalCollection(user);
}
public PrincipalCollection getPrincipals() {
return principalCollection;
}
public Object getCredentials() {
return user.getUsername();
}
private PrincipalCollection buildPrincipalCollection(User user) {
Collection<String> principals = new ArrayList<String>();
principals.add(user.getUsername());
return new SimplePrincipalCollection(principals, "tokenValidatorRealm");
}
}
Looks like it is expected behavior.
If you look at the javadoc for ModularRealmAuthenticator:
* #throws AuthenticationException if the user could not be authenticated or the user is denied authentication
* for the given principal and credentials.
*/
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
If you are having problems with the exception, you might need to change the code that calls the authentication to expect this exception.
Left for other searches:
You might have a missing supports method in your TokenAuthorizingRealm class.
Something like
#Override
public boolean supports(AuthenticationToken token) {
return token instanceof BearerAuthenticationToken;
}
should be present.
This discussion help me solve a similar problem. I wanted to authenticate a user by the application itself, not using any Shiro default implementation. To do that we must subclass AuthenticatingRealm, override doGetAuthenticationInfo and declare this realm as the validation one.
public class PasswordAuthorizingRealm extends AuthenticatingRealm {
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
In Shiro.ini:
passwordValidatorRealm = my.PasswordAuthorizingRealm