How to get a exception from Mono<Void> reactor Java - spring-boot

I am using spring cloud gateway to authenticate the application via identity providers.
I have implemented the GlobalFilter where I get the Principal from exchange class as OAuth2AuthenticationToken. Here is code snippet
return exchange.getPrincipal()
.defaultIfEmpty(DEFAULT_PRINCIPAL).map(principal -> {
// adds header to proxied request
ServerHttpRequest.Builder b = exchange.getRequest().mutate();
if (principal.getClass()
.equals(OAuth2AuthenticationToken.class)) {
OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) principal;
OAuth2User p = (OAuth2User) auth.getPrincipal();
String userId = (String) p.getAttributes()
.getOrDefault("sub", new String());
String firstName = (String) p.getAttributes()
.getOrDefault("given_name", new String());
String lastName = (String) p.getAttributes()
.getOrDefault("family_name", new String());
String name = (String) p.getAttributes()
.getOrDefault("preferred_username",
new String());
String email = (String) p.getAttributes()
.getOrDefault("email",
new String());
String groupName = (String) p.getAttributes()
.getOrDefault("group",
new String());
if (groupName.equalsIgnoreCase("data-admins")) {
// TODO throw something HTML
}
if (principal != DEFAULT_PRINCIPAL) {
b.header("X-APP-USER", p.getName());
b.header("X-APP-USERID", userId);
if (firstName != null) {
b.header("X-APP-FIRSTNAME", firstName);
}
if (lastName != null) {
b.header("X-APP-LASTNAME", lastName);
}
if (name != null) {
b.header("X-APP-PREFERRED-USERNAME", name);
}
if (email != null) {
b.header("X-APP-EMAIL", email);
}
}
}
b.build();
return exchange;
}).flatMap(chain::filter);
Inside the if condition I need to check if in principal object the group value matching with as value data-admin or NOT. If principal (or User) doesn't belong with this group then throw an error (preferably HTML)
If make throw new RuntimeException("User is not part of a Group"); it works but how to send this as an HTML. As return can be Mono
How to achieve this?

Related

Unable to crate a Firestore Bean, BeanCreationException. java.lang.NoClassDefFoundError: com/google/api/gax/rpc/TransportChannelProvider

I am working with Spring Boot and Spring Security, but is my first time using Google cloud firebase Firestore, I am connecting to my database via Firebase Admin SDK. I have a configuration class that looks like this.
#Configuration
public class FirestoreUserConfig {
#Bean
public Firestore getDB() {
return FirestoreClient.getFirestore();
}
}
I have BeanCreationException, my stack trace, in summary, looks like this.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getDB' defined in class path resource [com/d1gaming/user/firebaseconfig/FirestoreUserConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.google.cloud.firestore.Firestore]: Factory method 'getDB' threw exception; nested exception is java.lang.NoClassDefFoundError: com/google/api/gax/rpc/TransportChannelProvider
Caused by: java.lang.ClassNotFoundException: com.google.api.gax.rpc.TransportChannelProvider
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_271]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_271]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355) ~[na:1.8.0_271]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_271]
... 105 common frames omitted
The weird thing is I followed Google's documentation on Initializing firebase Admin SDK, I added the corresponding dependencies to my pom.xml file but it does not seem to work anyway. This is my Admin SDK dependency.
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>7.0.1</version>
</dependency>
I imagine Maven is not able to find this TransportChannelProvider class, Im not sure. I also tried adding all of gcp core dependencies in case provided Admin SDK dependency didn't have the class but I had the same result. I am also making use of a Service and a RESTController for my back end application, I don't know if it is relevant to include it here but I am going to include it just in case.
#Service
public class UserService {
public final String USERS_COLLECTION = "users";
#Autowired
private PasswordEncoder passwordEncoder;
private Firestore firestore;
//get users collcetion from Firestore.
private CollectionReference getUsersCollection() {
return firestore.collection(this.USERS_COLLECTION);
}
//Post a user onto the user collection. documentID is auto-generated by firestore.
public String saveUser(User user) throws InterruptedException, ExecutionException {
Query query = getUsersCollection().whereEqualTo("userName", user.getUserName());
QuerySnapshot querySnapshot = query.get().get();
//Query to validate if userName is already in use.
if(querySnapshot.isEmpty()) {
ApiFuture<DocumentReference> document = getUsersCollection().add(user);
DocumentReference reference = document.get();
String userId = document.get().getId();
//Assign auto-generated Id to userId field for ease of querying.
WriteBatch batch = FirestoreClient.getFirestore().batch();
batch.update(reference, "userId",userId);
//ENCODE USER PASSWORD!
batch.update(reference, "userPassword",passwordEncoder.encode(reference.get().get().toObject(User.class).getUserPassword()));
List<WriteResult> results = batch.commit().get();
results.forEach(result -> {
System.out.println("Update Time: " + result.getUpdateTime());
});
return "Created user with ID: " + "'" + userId + "'";
}
return "Username is already in use";
}
//Get User by given its email.
public Optional<User> getUserByEmail(String userEmail) throws InterruptedException, ExecutionException{
Query query = getUsersCollection().whereEqualTo("userEmail", userEmail);
QuerySnapshot snapshot = query.get().get();
//if user with provided Email exists in collection.
if(!snapshot.isEmpty()) {
List<User> userLs = snapshot.toObjects(User.class);
//Since there is a unique email for each document,
//There will only be on User object on list, we will retrieve the first one.
for(User currUser: userLs) {
return Optional.of(currUser);
}
}
return null;
}
//Query for user by given userName.
public Optional<User> getUserByUserName(String userName) throws InterruptedException, ExecutionException{
//Perform a query based on a user's Name.
Query query = getUsersCollection().whereEqualTo("userName", userName);
QuerySnapshot snapshot = query.get().get();
if(!snapshot.isEmpty()) {
List<User> userList = snapshot.toObjects(User.class);
//Since there is a unique userName for each document,
//there will only be one User object on the list, we will retrieve the first one.
for(User currUser: userList) {
return Optional.of(currUser);
}
}
return null;
}
//Query for user by given userName.
public User getUserByName(String userName) throws InterruptedException, ExecutionException {
//Perform a query based on a user's Name.
Query query = getUsersCollection().whereEqualTo("userName", userName);
QuerySnapshot snapshot = query.get().get();
if(!snapshot.isEmpty()) {
List<User> userList = snapshot.toObjects(User.class);
//Since there is a unique userName for each document,
//there will only be one User object on the list, we will retrieve the first one.
for(User currUser : userList) {
return currUser;
}
}
return null;
}
//Get User by its auto-generated ID.
public User getUserById(String userId) throws InterruptedException, ExecutionException {
DocumentReference reference = getUsersCollection().document(userId);
if(reference.get().get().exists()) {
DocumentSnapshot snapshot = reference.get().get();
User user = snapshot.toObject(User.class);
return user;
}
return null;
}
//Get DocumentReference on a User.
public DocumentReference getUserReference(String userId) throws InterruptedException, ExecutionException {
DocumentReference reference = getUsersCollection().document(userId);
//Evaluate if documentExists in users collection.
if(reference.get().get().exists()) {
return reference;
}
return null;
}
//return a list of objects located in the users collection.
public List<User> getAllUsers() throws InterruptedException, ExecutionException {
//asynchronously retrieve all documents
ApiFuture<QuerySnapshot> future = getUsersCollection().get();
List<QueryDocumentSnapshot> objects = future.get().getDocuments();
//If there is no documents, return null.
if(!objects.isEmpty()) {
List<User> ls = new ArrayList<>();
objects.forEach((obj) -> {
User currUser = obj.toObject(User.class);
ls.add(currUser);
});
return ls;
}
return null;
}
//delete a User from users collection by a given id.
//In reality delete method just changes UserStatus from active to inactive or banned.
public String deleteUserById(String userId) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
DocumentReference reference = db.collection(USERS_COLLECTION).document(userId);
User user = reference.get().get().toObject(User.class);
if(user == null) {
return "User not found.";
}
WriteBatch batch = db.batch();
batch.update(reference, "userStatusCode",UserStatus.INACTIVE);
ApiFuture<List<WriteResult>> result = batch.commit();
List<WriteResult> results = result.get();
results.forEach(response -> {
System.out.println("Update Time:" + response.getUpdateTime());
});
//Check if user did actually change status.
if(reference.get().get().toObject(User.class).getStatusCode().equals(UserStatus.ACTIVE)) {
return "User with ID: " + "'" + userId + "'" + " was deleted.";
}
return "User could not be deleted";
}
//Delete a User's certain field value.
public String deleteUserField(String userId, String userField) throws InterruptedException, ExecutionException {
Firestore firestore = FirestoreClient.getFirestore();
DocumentReference reference = getUsersCollection().document(userId);
if(!reference.get().get().exists()) {
return "User not found.";
}
Map<String,Object> map = new HashMap<>();
map.put(userField, FieldValue.delete());
WriteBatch batch = firestore.batch();
batch.update(reference, map);
List<WriteResult> results = batch.commit().get();
results.forEach(response -> System.out.println("Update Time: " + response.getUpdateTime()));
return "Field deleted Successfully";
}
//Change UserStatus to BANNED
public String banUserById(String userId) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
final DocumentReference reference = db.collection(this.USERS_COLLECTION).document(userId);
WriteBatch batch = db.batch().update(reference,"userStatusCode",UserStatus.BANNED);
List<WriteResult> results = batch.commit().get();
results.forEach(response -> System.out.println("Update Time: " + response.getUpdateTime()));
if(reference.get().get().toObject(User.class).getStatusCode().equals(UserStatus.BANNED)) {
return "User with ID: " + "'" + userId + "'" + " was BANNED.";
}
return "User could not be BANNED.";
}
//Set a user with all new fields.
public String updateUser(User user) throws InterruptedException, ExecutionException {
Firestore firestore = FirestoreClient.getFirestore();
final DocumentReference reference = getUsersCollection().document(user.getUserId());
DocumentSnapshot snapshot = reference.get().get();
if(snapshot.exists()) {
WriteBatch batch = firestore.batch();
batch.set(reference, user);
List<WriteResult> results = batch.commit().get();
results.forEach(response -> System.out.println("Update time: " + response.getUpdateTime()));
return "User updated successfully";
}
return "User not found.";
}
// Update a specific field on a given document by another given value. In case userId is field to be changed, one integer will be subtracted from userTokens field.
public String updateUserField(String userId,String objectField, String replaceValue) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
final DocumentReference reference = getUsersCollection().document(userId);
if(!reference.get().get().exists()) {
return "User not found.";
}
WriteBatch batch = db.batch();
List<WriteResult> results = new ArrayList<>();
//These fields cannot be updated.
if(!objectField.equals("userName") && !objectField.equals("userCash") && !objectField.equals("userTokens") && !objectField.equals("userId")) {
batch.update(reference, objectField, replaceValue);
results = batch.commit().get();
results.forEach(response ->{
System.out.println("Update time: " + response.getUpdateTime());
});
}
else if(objectField.equals("userName")) {
String response = updateUserName(userId, replaceValue);
return response;
}
else {
return "This field canntot be updated.";
}
return "User field could not be updated.";
}
//Update a user's userName depending of availability and token adquisition capacity. i.e. if user has enough tokens to pay fee.
public String updateUserName(String userId, String newUserName) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
final DocumentReference reference = getUsersCollection().document(userId);
DocumentSnapshot snapshot = reference.get().get();
if(!snapshot.exists()) {
return "User not found.";
}
Query query = getUsersCollection().whereEqualTo("userName", newUserName);
QuerySnapshot querySnapshot = query.get().get();
//Evaluate if userName is already in use.
String response = "Username is already taken";
if(querySnapshot.isEmpty()) {
//Transaction to get() tokens and update() tokens.
ApiFuture<String> futureTransact = db.runTransaction(transaction -> {
DocumentSnapshot doc = transaction.get(reference).get();
double tokens = doc.getDouble("userTokens");
//evaluate if user holds more than one token
if(tokens >= 1) {
transaction.update(reference, "userTokens", tokens - 1);
transaction.update(reference, "userName", newUserName);
return "Username updated to: '"+ newUserName +"'";
}
else {
throw new Exception("Not enough Tokens");
}
});
response = futureTransact.get();
}
return response;
}
//update user Currency field.
public String updateUserCash(String userId, double cashQuantity) throws InterruptedException, ExecutionException {
Firestore firestore = FirestoreClient.getFirestore();
final DocumentReference reference = getUsersCollection().document(userId);
DocumentSnapshot snapshot = reference.get().get();
String response = "User not found.";
//evaluate if document exists
if(snapshot.exists()) {
ApiFuture<String> futureTransaction = firestore.runTransaction(transaction -> {
Map<String,Object> map = new HashMap<>();
map.put("userCash", FieldValue.increment(cashQuantity));
transaction.update(reference, map);
return "Updated userCash";
});
response = futureTransaction.get();
return response;
}
return response;
}
//Update user Token field.
public String updateUserTokens(String userId, double tokenQuantity) throws InterruptedException, ExecutionException {
Firestore firestore = FirestoreClient.getFirestore();
final DocumentReference reference = getUsersCollection().document(userId);
String response = "User not found.";
//evaluate if user exists on collection.
if(reference.get().get().exists()) {
ApiFuture<String> futureTransaction = firestore.runTransaction(transaction -> {
Map<String,Object> map = new HashMap<>();
map.put("userTokens",tokenQuantity);
transaction.update(reference, map);
return "Updated userTokens";
});
response = futureTransaction.get();
return response;
}
return response;
}
//evaluate if given documentId exists on given collection.
public static boolean isPresent(String userId,String collectionName) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
DocumentReference reference = db.collection(collectionName).document(userId);
ApiFuture<DocumentSnapshot> snapshot = reference.get();
DocumentSnapshot document = snapshot.get();
if(!document.exists()) {
return false;
}
return true;
}
//Evaluate if given document's status corresponds to active.
public static boolean isActive(String userId, String collectionName) throws InterruptedException, ExecutionException {
Firestore db = FirestoreClient.getFirestore();
DocumentReference reference = db.collection(collectionName).document(userId);
ApiFuture<DocumentSnapshot> snapshot = reference.get();
DocumentSnapshot result = snapshot.get();
User user = result.toObject(User.class);
if(user.getStatusCode().equals(UserStatus.ACTIVE)) {
return true;
}
return false;
}
}
My Controller class:
#RestController
#RequestMapping("/userapi")
#CrossOrigin(origins = "http://localhost:4200")
public class UserController {
#Autowired
UserService userServ;
#GetMapping(value = "/users/search",params="userName")
#PreAuthorize("hasRole('PLAYER')")
public ResponseEntity<Object> getUserByName(#RequestParam(value = "userName", required = true)final String userName) throws InterruptedException, ExecutionException{
if(userName == null) {
return new ResponseEntity<>("Invalid Input",HttpStatus.BAD_REQUEST);
}
User user = userServ.getUserByName(userName);
if(user == null) {
return new ResponseEntity<>("User Not Found", HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(user,HttpStatus.OK);
}
#GetMapping("/users")
#PreAuthorize("hasRole('PLAYER')")
public ResponseEntity<List<User>> getAllUsers() throws InterruptedException, ExecutionException{
List<User> ls = userServ.getAllUsers();
if(ls.isEmpty()) {
return new ResponseEntity<List<User>>(ls, HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<User>>(ls, HttpStatus.OK);
}
#DeleteMapping(value = "/users/delete",params="userId")
#PreAuthorize("hasRole('ADMINISTRATOR')")
public ResponseEntity<Object> deleteUserById(#RequestParam(value="userId", required = true)String userId, #RequestParam(required = false, value="userField") String userField) throws InterruptedException, ExecutionException{
if(userField != null) {
String response = userServ.deleteUserField(userId, userField);
if(response.equals("User not found.")) {
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
String response = userServ.deleteUserById(userId);
if(response.equals("User not found.")) {
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
#PutMapping(value = "/users/update")
#PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('PLAYER')")
public ResponseEntity<Object> updateUser(#RequestBody User user) throws InterruptedException, ExecutionException{
String response = userServ.updateUser(user);
if(response.equals("User not found.")) {
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
#PutMapping(value = "/users/update",params="userId")
#PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('PLAYER')")
public ResponseEntity<Object> updateUserField(#RequestParam(required = true, value="userId")String userId, #RequestParam(required = true)String userField, #RequestParam(required = true)String replaceValue) throws InterruptedException, ExecutionException{
String response = userServ.updateUserField(userId, userField, replaceValue);
if(response.equals("User not found.")) {
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
else if(response.equals("This field cannot be updated.")) {
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
I didn't find ANY documentation on this particular problem and that is why I am here, I would be glad if anyone could help me solving this problem. Am I missing something? Anyways thank you for your time, happy coding.
as you said, you are missing the TransportChannelProvider interface and it's implementations. it's not provided in the dependency you added.
try to add this dependency to your POM:
<dependency>
<groupId>com.google.api</groupId>
<artifactId>gax</artifactId>
<version>1.57.0</version>
</dependency>
the interface included there.
After checking my pom.xml and my dependency hierarchies(On Eclipse, found on the toolbar above the console when the pom.xml file is being viewed.), I found I had another dependency on another Spring Boot project that was overriding the one I had on my project, make sure to check all dependencies on different projects as well. The dependency version I had on my other project did not include the classes Spring needed to create a a bean.

Multiple authentication attributes

I`m working on my website using .net web-api as back .
Now I made different authentication attributes on the web site such as users employees and admin .
for my question how can I use multiple authentication attributes on a controller?
public class AuthFilterManager : Attribute, IAuthenticationFilter
{
public bool AllowMultiple => throw new NotImplementedException();
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var auth = context.Request.Headers.Authorization;
string[] UserNameAndPass = (auth.Parameter).Split(':');
string UserName = UserNameAndPass[0];
string Pass = UserNameAndPass[1];
Luxury_wheelsEntities entities = new Luxury_wheelsEntities();
Management manager = entities.Managements.FirstOrDefault(m => m.User_name == UserName);
if (auth != null && auth.Scheme == "LuxuryWheelsLogin")
{
if (LoginSecurity.CheckManagerLogin(UserName, Pass))
{
var Claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier,(manager.ID)),
new Claim(ClaimTypes.Name,(manager.Full_name)),
new Claim(ClaimTypes.Gender,(manager.Sex))
};
var identity = new ClaimsIdentity(Claims, "Token");
context.Principal = new ClaimsPrincipal(new[] { identity });
}
else
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
}
return Task.FromResult(0);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
return Task.FromResult(0);
}
}
seperatly the AuthFilterEmployee and the AuthFilterManager works just fine.
[AuthFilterEmployee ]
[AuthFilterManager]
[Authorize]
public IEnumerable<User> Get()
{
return LuxuryWheelsDB.Users;
}

Generate Access token and Refresh token without username and password

I am implementing oauth2 with spring-security using springboot2.
I am authenticating user using spring-security only and returning a user Object back by using username and password. (http://localhost:8181/login)
Here users might be multiple with same mail. so again from user object which i got i am taking userid and sending to (http://localhost:8181/oauth/token)
here i want to pass only grant_type and userId not username and password again in order to generate access token and refresh token using oauth2.
How can i acheive this.
can i get username and password from previous request. And how i can configure in oauth2 to fulfill my requirement.
please help.
In below code i am authenticating one user by keeping limit 1 later i am fetching all users with same mail id. password is same for all.
#Override
#Transactional
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = new User();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
String stringuserId = request.getParameter("userId");
Long userId = 0L;
try {
if (stringuserId != null) {
userId = Long.parseLong(stringuserId);
System.out.println(userId);
System.out.println(request.getParameter("username"));
user = userRepository.findByUserId(userId).orElseThrow(
() -> new UsernameNotFoundException("User Not Found with -> username or email : " + email));
System.out.println(user.toString());
return UserPrinciple.build(user);
} else {
Set<GrantedAuthority> authorities = new HashSet<>();
CustomUser userDetails = new CustomUser(email, "", authorities);
String checkUser = "SELECT \"USER_ID\",\"EMAIL_ID\",\"PASSWORD\" FROM \"TU_IOT_PLATFORM_PROD\".\"USER_MASTER\" WHERE \"EMAIL_ID\"='john#test.com' LIMIT 1;";
List<Map<String, Object>> toValues = new ArrayList<Map<String, Object>>();
toValues = jdbcTemplate.queryForList(checkUser);
if(toValues.size()>0) {
for (Map<String, Object> map : toValues) {
userDetails.setUserId((int) map.get("USER_ID"));
userDetails.setEmail((String)map.get("EMAIL_ID"));
userDetails.setPassword((String)map.get("PASSWORD"));
}
}else {
throw new UsernameNotFoundException("User Not Found with -> username or email : " + email);
}
System.out.println(userDetails.toString());
return userDetails;
}
} catch (NumberFormatException e) {
userId = 0L;
user = userRepository.findByEmail(email).orElseThrow(
() -> new UsernameNotFoundException("User Not Found with -> username or email : " + email));
}
return UserPrinciple.build(user);
}
}
var tokenExpiration = Startup.TokenExpiration; //超期时长
var data = new Dictionary<string, string>
{
{"as:client_id", clientId },
{"userID",user.Id},
{"commID","0" }
};
var IssueTime = DateTime.UtcNow;
var properties = new AuthenticationProperties(data)
{
IssuedUtc = IssueTime,
ExpiresUtc = IssueTime.Add(tokenExpiration),
};
var oAuthIdentity = _userManager.CreateIdentity(user, "JWT");
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
//var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
//var rToken= Startup.OAuthOptions.RefreshTokenFormat.Protect(ticket);
var context = new AuthenticationTokenCreateContext(Request.GetOwinContext(), Startup.OAuthOptions.AccessTokenFormat, ticket);
//await Startup.OAuthOptions.AccessTokenProvider.CreateAsync(context);
//accessToken = context.Token;
var refreshTkLifeTime = ;
context.OwinContext.Set("as:clientAllowedOrigin", "*");
context.OwinContext.Set("as:clientRefreshTokenLifeTime", refreshTkLifeTime.ToString());
await Startup.OAuthOptions.RefreshTokenProvider.CreateAsync(context);
var refreshToken = context.Token;
return new JObject(
new JProperty("access_token", accessToken),
new JProperty("refresh_token", refreshToken),
new JProperty("token_type", "bearer"),
new JProperty("expires_in", tokenExpiration.TotalSeconds.ToString()),
new JProperty(".issued", IssueTime.ToString()),
new JProperty(".expires", IssueTime.Add(tokenExpiration).ToString())
);

Unable to mock value in Junit/Mockito

I have this auth method for login and i am doing a junit test on it.
I am using Mockito, spring4, hibernate5.
What i am facing is this.
The junit test result is correct for testIsAuthorizedUser_normalLogin().
However for testIsAuthorizedUser_blackListUser(), it is not.
I am expecting it to throw an exception.
The problem lies in this line of code.
when(blacklistDeviceService.getBlacklistDeviceForSearch(
eq(PropertiesUtil.BlacklistType.IP_ADDRESS.ordinal()), eq(request.getRemoteAddr()), eq(true), eq(null), eq(null), eq(null)))
.thenReturn(deviceListForIp);
When i debug the code blacklistDeviceService.getBlacklistDeviceForSearch does not return me the object that i force it to return. instead it return me a empty list.
How do i return the value?
Main implementation
public Map<String,String> isAuthorizedUser(String username, String password, Integer loginType, String imei, HttpServletRequest req) throws ErrorException
{
HashMap<String,String> result = new HashMap<>();
UUID uuid = UUID.randomUUID();
UserInfo user = null;
user = isAuthorizedUser(username, password, loginType, imei, req, uuid.toString());
if (isPolicyEnforce)
{
validate(user);
//trigger when user pwd is expired or when password is reset
if (user.getExpire() || user.getIsPasswordReset())
{
result.put(PropertiesUtil.MAPPING_TOKEN, generateToken(user, uuid.toString()));
result.put(PropertiesUtil.MAPPING_CHANGE_PASSWORD, "true");
return result;
}
}
result.put(PropertiesUtil.MAPPING_TOKEN, generateToken(user, uuid.toString()));
result.put(PropertiesUtil.MAPPING_CHANGE_PASSWORD, "false");
return result;
}
private UserInfo isAuthorizedUser(String username, String password, Integer loginType, String imei, HttpServletRequest req, String uuid) throws ErrorException
{
UserInfo user = userInfoDAO.findById(username);
if (GlobUtil.isNotEmpty(user))
{
try
{
if (isPolicyEnforce && (maxFailAttempt < 0))
{
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_INVALID_POLICY));
}
Set<Role> roles = new HashSet<>(userRoleDAO.getRoleBy(user));
if(roles.isEmpty())
{
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_UNAUTHORIZED_USER));
}
if (PasswordEncoder.verifyPassword(password, user.getPassword()))
{
if(isBlacklist(req.getRemoteAddr(), imei))
{
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_UNAUTHORIZED_DEVICE));
}
if(GlobUtil.isNotEmpty(user.getErrorCount()) && user.getErrorCount() > 0)
{
user.setErrorCount(0);
accessControlTransNewService.transNewUpdateUser(user);
}
accessControlTransNewService.transNewAddLoginLog(username, PropertiesUtil.ACTION_LOGIN, PropertiesUtil.getEnum(PropertiesUtil.LoginType.values(), loginType).name(), "Login - Success.", req);
}
else
{
if (user.getIsActive() && !user.getIsLock())
{
accessControlTransNewService.transNewAddLoginLog(username, PropertiesUtil.ACTION_LOGIN, PropertiesUtil.getEnum(PropertiesUtil.LoginType.values(), loginType).name(), "Login - Fail. Invalid password.", req);
unauthorizedAccess(user, maxFailAttempt);
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_INVALID_USERPWD));
}
else
{
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_INACTIVE_USER));
}
}
}
catch (CannotPerformOperationException | InvalidHashException e)
{
throw new ErrorException(e);
}
catch (NumberFormatException nfe)
{
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_INVALID_POLICY));
}
}
else
{
accessControlTransNewService.transNewAddLoginLog(username, PropertiesUtil.ACTION_LOGIN, PropertiesUtil.getEnum(PropertiesUtil.LoginType.values(), loginType).name(), "Login - Fail. User do not exist.", req);
throw new ErrorException(msgProperty.getProperty(MessageUtil.ERR_AUTH_INVALID_USERPWD));
}
addUserToSession(user, req, uuid);
return user;
}
private boolean isBlacklist(String ipAddress, String imei)
{
List<BlacklistDevice> deviceListForImei = new ArrayList<>();
List<BlacklistDevice> deviceListForIp = new ArrayList<>();
if(GlobUtil.isNotEmpty(imei))
{
deviceListForImei = blacklistDeviceService.getBlacklistDeviceForSearch(PropertiesUtil.BlacklistType.IMEI.ordinal(), imei, true, null, null, null);
}
if(GlobUtil.isNotEmpty(ipAddress))
{
deviceListForIp = blacklistDeviceService.getBlacklistDeviceForSearch(PropertiesUtil.BlacklistType.IP_ADDRESS.ordinal(), ipAddress, true, null, null, null);
}
return (!deviceListForImei.isEmpty()) || (!deviceListForIp.isEmpty());
}
Mock
#Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
user = new UserInfo("user1", "sha1:64000:18:VFNOK/vZ3W8Zd9/xDQKUBNlccvpmydbu:rlemV/kvTi/FNZpEA/9jf+Wh", "User 1", "User 1",
"User 1",0, true,false, new Date(), false, null, false, false);
roles = new ArrayList<>();
roles.add(new Role("ADMIN","ADMIN"));
deviceListForImei = new ArrayList<>();
deviceListForIp = new ArrayList<>();
BlacklistDevice blacklistDevice = new BlacklistDevice(1, "Blacklist", PropertiesUtil.BlacklistType.IP_ADDRESS.ordinal(), "192.168.1.100", "admin", new Date(), true);
deviceListForIp.add(blacklistDevice);
}
/**
* Test method for
* {#link com.stengg.stee.auth.service.impl.AccessControlServiceImpl#isAuthorizedUser(java.lang.String, java.lang.String, java.lang.Integer, java.lang.String, javax.servlet.http.HttpServletRequest)}.
*/
#Test
public void testIsAuthorizedUser_normalLogin()
{
MockHttpServletRequest request = new MockHttpServletRequest();
String username = "user1";
String password = "password";
Integer loginType = PropertiesUtil.LoginType.IPAC2.ordinal();
String imei = "";
when(userInfoDAO.findById(anyString())).thenReturn(user);
when(userRoleDAO.getRoleBy(any(UserInfo.class))).thenReturn(roles);
when(blacklistDeviceService.getBlacklistDeviceForSearch(anyInt(), anyString(), anyBoolean(), anyInt(), anyInt(), anyString())).thenReturn(Collections.EMPTY_LIST);
doNothing().when(accessControlTransNewService).transNewAddLoginLog(anyString(), anyString(), anyString(), anyString(), any(HttpServletRequest.class));
when(onlineUsers.getOnlineUser(anyString())).thenReturn(null);
when(blueForceTrackerStore.removeViewer(anyString())).thenReturn(false);
Map<String, String> result1 = accessControlService.isAuthorizedUser(username, password, loginType, imei, request);
//login success
assertNotNull(result1);
assertNotNull(result1.get("token"));
assertNotNull(result1.get("token").contains("Bearer "));
}
#Test(expected = ErrorException.class)
public void testIsAuthorizedUser_blackListUser()
{
MockHttpServletRequest request = new MockHttpServletRequest();
String username = "user1";
String password = "password";
Integer loginType = PropertiesUtil.LoginType.IPAC2.ordinal();
String imei = "";
when(userInfoDAO.findById(anyString())).thenReturn(user);
when(userRoleDAO.getRoleBy(any(UserInfo.class))).thenReturn(roles);
when(blacklistDeviceService.getBlacklistDeviceForSearch(
eq(PropertiesUtil.BlacklistType.IP_ADDRESS.ordinal()), eq(request.getRemoteAddr()), eq(true), eq(null), eq(null), eq(null)))
.thenReturn(deviceListForIp);
doNothing().when(accessControlTransNewService).transNewAddLoginLog(anyString(), anyString(), anyString(), anyString(), any(HttpServletRequest.class));
when(onlineUsers.getOnlineUser(anyString())).thenReturn(null);
when(blueForceTrackerStore.removeViewer(anyString())).thenReturn(false);
Map<String, String> result2 = accessControlService.isAuthorizedUser(username, password, loginType, imei, request);
assertNull(result2);
}
You may want to use another construct:
doReturn(deviceListForIp)
.when(blacklistDeviceService)
.getBlacklistDeviceForSearch(eq(PropertiesUtil.BlacklistType.IP_ADDRESS.ordinal()), eq(request.getRemoteAddr()), eq(true), eq(null), eq(null), eq(null))
An empty list is a sign of not properly mocked behaviour, its default.

Mock default role provider for controller's action unit test

Hope this is not a dumb question. I've been searching for two days a way to mock calls for system.web.security.roles on my actions.
I want my unit tests to be isolated and not involve calls to external resources such as database where the roles get Stored.
all the answers i found suggested the creation of a custom role provider, but i prefer mocking over the creation of fakes.
the closest i got was with this solution but i didn't found a way for ninject to pass the default role Provider to the constructor when running the project outside the tests.
I know that type Mock provides a more easy solution to this, but I'm using rhino Mocks and is too late to change now.
I've had same problem like you and after two hours searching I gave it up.
Finally I ended up with creating own mocking role provider - code bellow.
public class MockRoleProvider : RoleProvider
{
public MockRoleProvider()
: base()
{
Users = new List<User>();
Roles = new List<Role>();
}
#region RoleProvider members
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
if (usernames == null) throw new ArgumentNullException("usernames");
if (roleNames == null) throw new ArgumentNullException("roleNames");
foreach (string role in roleNames)
{
if (!RoleExists(role)) throw new ProviderException("Role name does not exist.");
}
foreach (string user in usernames)
{
if (Users.FirstOrDefault(u => u.Username == user) == null) throw new ProviderException("Username does not exist.");
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (var rolename in roleNames)
{
Role role = Roles.FirstOrDefault(r => r.RoleName == rolename);
user.Roles.Add(role);
role.Users.Add(user);
}
}
}
public override string ApplicationName { get; set; }
public override void CreateRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (roleName.Contains(",")) throw new ArgumentException("Role names cannot contain commas.");
if (RoleExists(roleName)) throw new ProviderException("Role name already exists.");
Roles.Add(new Role { RoleName = roleName });
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role name does not exist.");
if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0) throw new ProviderException("Cannot delete a populated role.");
Roles.Remove(Roles.FirstOrDefault(r => r.RoleName == roleName));
return true;
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
return GetUsersInRole(roleName).Where(n => n.Contains(usernameToMatch)).ToArray();
}
public override string[] GetAllRoles()
{
return Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetRolesForUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) return new string[0];
return user.Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetUsersInRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role '" + roleName + "' does not exist.");
return role.Users.Select(u => u.Username).OrderBy(n => n).ToArray();
}
public override bool IsUserInRole(string username, string roleName)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
return role != null && role.Users.FirstOrDefault(u => u.Username == username) != null;
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
foreach (string roleName in roleNames)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (!RoleExists(roleName)) throw new ProviderException("Role name not found.");
}
foreach (string username in usernames)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
foreach (string roleName in roleNames)
{
if (!IsUserInRole(username, roleName)) throw new ProviderException("User is not in role.");
}
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (string roleName in roleNames)
{
Role role = user.Roles.FirstOrDefault(r => r.RoleName == roleName);
role.Users.Remove(user);
user.Roles.Remove(role);
}
}
}
public override bool RoleExists(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
return Roles.FirstOrDefault(r => r.RoleName == roleName) != null;
}
#endregion
public void ClearAll()
{
Users = new List<User>();
Roles = new List<Role>();
}
public void ClearRoles()
{
Roles = new List<Role>();
Users.ForEach(u => u.Roles = new List<Role>());
}
public void ClearUsers()
{
Users = new List<User>();
Roles.ForEach(r => r.Users = new List<User>());
}
public void CreateUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (UserExists(username)) throw new ProviderException("User name already exists.");
Users.Add(new User { Username = username });
}
public bool DeleteUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) throw new ProviderException("User name does not exist.");
foreach (Role role in user.Roles)
{
role.Users.Remove(user);
}
Users.Remove(user);
return true;
}
public bool UserExists(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
return Users.FirstOrDefault(u => u.Username == username) != null;
}
private List<Role> Roles { get; set; }
private List<User> Users { get; set; }
private class Role
{
public Role()
{
Users = new List<User>();
}
public string RoleName { get; set; }
public List<User> Users { get; set; }
}
private class User
{
public User()
{
Roles = new List<Role>();
}
public string Username { get; set; }
public List<Role> Roles { get; set; }
}
}
It is really basic but full implementation of RoleProvider.
For use MockRoleProvider add to you App.config this lines of XML into <configuration> element:
<system.web>
<roleManager enabled="true" defaultProvider="MockRoleProvider">
<providers>
<add name="MockRoleProvider" type="YourProject.Tests.MockRoleProvider, YourProject.Tests"/>
</providers>
</roleManager>
</system.web>
Then in unit test arrange part use this code:
MockRoleProvider mock = Roles.Provider as MockRoleProvider;
if (mock == null) throw new NullReferenceException("MockRoleProvider null exception.");
mock.ClearAll();
mock.CreateUser("SomeUser");
mock.CreateRole("SomeRole");
mock.AddUsersToRoles(new string[] { "SomeUser" }, new string[] { "SomeRole" });

Resources