I'm trying to implement Basic Auth with the play framework.
public class BasicAuth extends Action.Simple {
private static final String REALM = "Authorisation Needed";
private static final String AUTHORISATION = "authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final F.Promise<Result> UNAUTHORISED = F.Promise.pure((Result) unauthorized());
#Override
public F.Promise<Result> call(Http.Context context) throws Throwable {
Optional<String> auth_header = Optional.ofNullable(context.request().getHeader(AUTHORISATION));
if (!auth_header.isPresent()) {
context.response().setHeader(WWW_AUTHENTICATE, REALM);
return UNAUTHORISED;
}
String encoded_credentials = auth_header.get().substring(6);
byte[] decoded_credentials = Base64.getDecoder().decode(encoded_credentials);
String[] credentials = new String(decoded_credentials, "UTF-8").split(":");
if (credentials == null || credentials.length != 2) {
return UNAUTHORISED;
}
User user = authorise(credentials);
if (user == null) {
return UNAUTHORISED;
}
context.session().put("email", user.getEmail());
return delegate.call(context);
}
private User authorise(String[] credentials) {
String username = credentials[0];
String password = credentials[1];
return User.find.where().eq("email", username).eq("password", password).findUnique();
}
}
But the user doesn't change between requests. I.e. I log in with Joe Bloggs after initialising the server and it returns Joe as the current user.
Next request I log in with Bill Gates, and it returns Joe Bloggs as the current user.
I am returning the email stored in the session in the controller as so:
User logged_user = UserDao.findByEmail(context.session().get("email"));
I really need to fix this. Any help please?
Related
Im making a basic reset password functionality in my API but when i try to fetch the PasswordResetToken object from the repository hibernate doesnt fetch it and instead sends back null. Im 99% sure the PasswordResetToken that im trying to fetch is inside of the repository because i did some system.out.println's and it shows the PasswordResetToken is in there with the matching token it just doesnt send anything back.
heres the email varification and token creation
#PostMapping("/resetPassword")
public String resetPassword(#RequestBody PasswordModel passwordModel, HttpServletRequest request) {
User user = userService.findUserByEmail(passwordModel.getEmail());
String url = "";
if(user!=null) {
String token = UUID.randomUUID().toString();
userService.createPasswordResetTokenForUser(user, token);
url = passwordResetTokenMail(user, applicationUrl(request), token);
}
return url;
}
service methods that go along with it
#Override
public User findUserByEmail(String email) {
return userRepository.findByEmail(email);
}
#Override
public void createPasswordResetTokenForUser(User user, String token) {
PasswordResetToken passwordResetToken
= new PasswordResetToken(user, token);
passwordResetTokenRepo.save(passwordResetToken);
}
save new password functionality where the issue happens
#PostMapping("/savePassword")
public String savePassword(#RequestParam("token") String token,
#RequestBody PasswordModel passwordModel) {
String result = userService.validatePasswordResetToken(token);
if(!result.equalsIgnoreCase("valid")) {
return "Invalid token";
}
Optional<User> userOptional = userService.getUserByPasswordResetToken(token);
if(userOptional.isPresent()) {
userService.changePassword(userOptional.get(), passwordModel.getNewPassword());
return "Password has been updated";
} else {
return "Invalid token";
}
}
service methods
#Override
public String validatePasswordResetToken(String token) {
PasswordResetToken passwordResetToken
= passwordResetTokenRepo.findByToken(token);
if(passwordResetToken == null) {
return "invalid";
}
User user = passwordResetToken.getUser();
Calendar cal = Calendar.getInstance();
if((passwordResetToken.getExpirationTime().getTime())
- cal.getTime().getTime() <=0) {
passwordResetTokenRepo.delete(passwordResetToken);
return "expired";
}
return "valid";
}
#Override
public Optional<User> getUserByPasswordResetToken(String token) {
return Optional.ofNullable(passwordResetTokenRepo.findByToken(token).getUser());
}
#Override
public void changePassword(User user, String newPassword) {
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
}
and finally the repository
#Repository
public interface PasswordResetTokenRepo extends JpaRepository<PasswordResetToken, Long> {
PasswordResetToken findByToken(String token);
}
Figured it out incase anyone runs into the same issue. I was using postman on the client side and for some reason when I was copying the URL and pasting it into postman it was adding a space after the url so the token ended up being token=xyz with a space after instead of just token xyz. That’s why it looked like the token was there in the repo because you couldn’t tell there was a space after it.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am a beginner in spring security.
I have implement UserDetailsService interface of method public UserDetails loadUserByUsername(String email)
My problem is below.......
username and password both are entered wrong then it can work properly. but when I enter the correct username and incorrect password then I want to add an attempt in the database otherwise not. if the username and password are correct then I don't want to update attempt into the database.
private static final int MAX_ATTEMPTS = 3;
int MIN_ATTEMPTS = 0;
#Override
public UserDetails loadUserByUsername(String email) {
Members members = membersDao.findByEmail(email);
Set<GrantedAuthority> authorities = new HashSet<>();
if (members == null) {
throw new RuntimeException("Invalid username and password");
} else {
if (members == null) {
} else {
MIN_ATTEMPTS = members.getAttempts();
MIN_ATTEMPTS ++;
members.setAttempts(MIN_ATTEMPTS);
membersDao.save(members);
throw new RuntimeException("Login Attepmts "+MIN_ATTEMPTS);
}
if (members.getAttempts() <= MAX_ATTEMPTS) {
Role role = members.getRoles();
authorities.add(new SimpleGrantedAuthority(role.getRole()));
return new User(members.getEmail(), members.getPassword(),authorities);
} else {
throw new RuntimeException("blocked");
}
}
}
Ive tryed to change your Code a bit
private static final int MAX_ATTEMPTS = 3;
#Override
public UserDetails loadUserAndCheckLogin(String email, String enteredPassword) {
Members members = membersDao.findByEmail(email);
if (members == null) {
//Create Error Message for User
return null;
}
if (members.getAttempts() > MAX_ATTEMPTS) {
//Create Error Message for User
return null;
}
if (members.getPassword().equals(enteredPassword)) {
Set<GrantedAuthority> authorities = new HashSet<>();
Role role = members.getRoles();
authorities.add(new SimpleGrantedAuthority(role.getRole()));
members.setAttempts(0);
membersDao.save(members);
return new User(members.getEmail(), members.getPassword(), authorities);
} else {
int attempts = members.getAttempts();
members.setAttempts(++attempts);
membersDao.save(members);
//Create Error Message for User
return null;
}
}
Btw. im not sure if you realy want to create a new "SimpleGrantedAuthority" and "User" or if you want to load existing ones from your Database.
And you should use a hash for your Passwords.
Login controller
#PostMapping("/login")
public ResponseEntity<?> login(#RequestBody LoginMembers loginMembers) throws AuthenticationException, IOException, ServletException {
final Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginMembers.getEmail(),
loginMembers.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
final String token = jwtTokenUtil.generateToken(authentication);
logger.info("You are log in successfully with token");
return ResponseEntity.ok(new AuthTokenRequest(token));
}
I have customize your code and add into calling Method as per you suggest #Pitzas
thanks for suggest me............
private static final int MAX_ATTEMPTS = 3;
#PostMapping("/login")
public ResponseEntity<?> login(#RequestBody LoginMembers loginMembers) throws AuthenticationException, IOException, ServletException {
Members members = membersDao.findByEmail(loginMembers.getEmail());
PasswordEncoder passencoder = new BCryptPasswordEncoder();
if (members == null) {
//Create Error Message for User
throw new RuntimeException("Invalid Username and Password");
}
if (members.getAttempts() >= MAX_ATTEMPTS) {
//Create Error Message for User
throw new RuntimeException("Login Attempt exceeds "+MAX_ATTEMPTS);
}
if (passencoder.matches(loginMembers.getPassword(), members.getPassword())) {
final Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginMembers.getEmail(),
loginMembers.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
final String token = jwtTokenUtil.generateToken(authentication);
logger.info("You are log in successfully with token");
return ResponseEntity.ok(new AuthTokenRequest(token));
} else {
int attempts = members.getAttempts();
members.setAttempts(++attempts);
membersDao.save(members);
//Create Error Message for User
throw new RuntimeException("Login attempts "+attempts);
}
}
I am working on a java server which is sending Firebase Cloud Messaging notification to devices using OAUTH 2.0 authentication.
According to guide (https://firebase.google.com/docs/cloud-messaging/auth-server?authuser=0) I have generated key from an account service with editor role, but I keep getting 403 SENDER_ID_MISMATCH error.
Any suggestion?
public class FcmManager {
private static final String DEVICE_NOTIFICATION_URL = "https://fcm.googleapis.com/v1/projects/myprojectid/messages:send";
private static final String JSON_STR_DEVICE_NOTIFICATION = "{\"message\":{\"token\" : " +"\"%s\"" + ",\"notification\" : " +
"{\"body\" : \"%s\",\"title\" : \"%s\"}}}";
public static boolean sendNotificationDevice(DeviceNotification deviceNotification, String msgTitle,
String msgBody) throws Exception{
String accessToken = getAccessToken();
System.out.println(msgBody);
String jsonStr = String.format(JSON_STR_DEVICE_NOTIFICATION, deviceNotification.getToken()
,msgBody,msgTitle);
System.out.println(jsonStr);
F.Promise<String> response = WS.url(DEVICE_NOTIFICATION_URL)
.setContentType("application/json").setHeader("Authorization","Bearer " +
accessToken).post(jsonStr).map(
new F.Function<WS.Response, String>() {
public String apply(WS.Response response) {
String result = response.getBody();
System.out.println(result);
return result;
}
}
);
return true;
}
private static String getAccessToken() throws IOException {
GoogleCredential googleCredential = GoogleCredential
.fromStream(new FileInputStream("mygeneratedkeyfromaccountservice.json"))
.createScoped(Arrays.asList("https://www.googleapis.com/auth/firebase.messaging"));
googleCredential.refreshToken();
return googleCredential.getAccessToken();
}
}
I currently have a working web app, but I need to provide means for friend website to consume my data.
There is currently JSON response in place which retrieves some data from my website to caller. It's without authentication currently and I'd like to implement some kind of per request authentication.
My web app has users which are logged in and there is a authentication in place for that. But
I have 3 requests in total for which callers can get data off of my website, what would be the simplest way to add some kind of authentication just for those 3 requests?
I'm using play framework + java
Imo the best options for this would be in the order of simplicity:
Basic authentication (since it's possible to choose either to auth once and then do session-base user recognition or authorize on every request)
2-way SSL
Combination of both
What toolkit do you use for authentication part?
I personally stuck with play-authenticate. So I might be able to answer you question in regard to this toolkit, please apply it to your particular toolkit as needed.
I will provide Basic authentication example as the easiest one. The benefit is: you could start with it and add on top it later (e.g. add Client certificate authentication via Apache later on).
So, my controller code snippet
#Restrict(value = #Group({"ROLE_WEB_SERVICE1"}), handler = BasicAuthHandler.class)
public static Result ws1() {
return TODO;
}
And the authentification handler itself
public class BasicAuthHandler extends AbstractDeadboltHandler {
public static final String HEADER_PREFIX = "Basic ";
private static final String AUTHORIZATION = "authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
#Override
public Result beforeAuthCheck(final Http.Context context) {
return basicAuthenticate(context);
}
private Result basicAuthenticate(Http.Context context) {
if (PlayAuthenticate.isLoggedIn(context.session())) {
// user is logged in
return null;
}
final String authHeader = context.request().getHeader(AUTHORIZATION);
if (authHeader == null || !authHeader.toLowerCase().startsWith(HEADER_PREFIX.toLowerCase())) {
return onAuthFailure(context, "Basic authentication header is missing");
}
final String auth = authHeader.substring(HEADER_PREFIX.length());
final byte[] decodedAuth;
final String[] credentials;
try {
decodedAuth = Base64.base64ToByteArray(auth);
credentials = new String(decodedAuth, "UTF-8").split(":");
} catch (final IOException e) {
Logger.error("basicAuthenticate", e);
return Results.internalServerError();
}
if (credentials.length != 2) {
return onAuthFailure(context, "Could not authenticate with absent password");
}
final String username = credentials[0];
final String password = credentials[1];
final AuthUser authUser = new AuthUser(password, username);
final Enum result = AuthProvider.getProvider().loginUser(authUser);
if ("USER_LOGGED_IN".equals(result.name())) {
PlayAuthenticate.storeUser(context.session(), authUser);
return null;
}
return onAuthFailure(context, "Authenticate failure");
}
#Override
public Subject getSubject(final Http.Context context) {
// your implementation
}
#Override
public Result onAuthFailure(final Http.Context context,
final String content) {
// your error hangling logic
return super.onAuthFailure(context, content);
}
}
Hopefully it fills in some blanks
I am trying to write a server side Facebook Notification service in my GWT app. The idea is that I will run this as a timertask or cron job sort of.
With the code below, I get a login URL, I want to be able to Login programmatically as this is intended to be automated (Headless sort of way). I was gonna try do a submit with HTMLunit but I thought the FB API should cater for this.
Please advice.
public class NotificationServiceImpl extends RemoteServiceServlet implements NotificationService {
/**serialVersionUID*/
private static final long serialVersionUID = 6893572879522128833L;
private static final String FACEBOOK_USER_CLIENT = "facebook.user.client";
long facebookUserID;
public String sendMessage(Notification notification) throws IOException {
String api_key = notification.getApi_key();
String secret = notification.getSecret_key();
try {
// MDC.put(ipAddress, req.getRemoteAddr());
HttpServletRequest request = getThreadLocalRequest();
HttpServletResponse response = getThreadLocalResponse();
HttpSession session = getThreadLocalRequest().getSession(true);
// session.setAttribute("api_key", api_key);
IFacebookRestClient<Document> userClient = getUserClient(session);
if(userClient == null) {
System.out.println("User session doesn't have a Facebook API client setup yet. Creating one and storing it in the user's session.");
userClient = new FacebookXmlRestClient(api_key, secret);
session.setAttribute(FACEBOOK_USER_CLIENT, userClient);
}
System.out.println("Creating a FacebookWebappHelper, which copies fb_ request param data into the userClient");
FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(request, response, api_key, secret, userClient);
String nextPage = request.getRequestURI();
nextPage = nextPage.substring(nextPage.indexOf("/", 1) + 1); //cut out the first /, the context path and the 2nd /
System.out.println(nextPage);
boolean redirectOccurred = facebook.requireLogin(nextPage);
if(redirectOccurred) {
return null;
}
redirectOccurred = facebook.requireFrame(nextPage);
if(redirectOccurred) {
return null;
}
try {
facebookUserID = userClient.users_getLoggedInUser();
if (userClient.users_hasAppPermission(Permission.STATUS_UPDATE)) {
userClient.users_setStatus("Im testing Facebook With Java! This status is written using my Java code! Can you see it? Cool :D", false);
}
} catch(FacebookException ex) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while fetching user's facebook ID");
System.out.println("Error while getting cached (supplied by request params) value " +
"of the user's facebook ID or while fetching it from the Facebook service " +
"if the cached value was not present for some reason. Cached value = {}" + userClient.getCacheUserId());
return null;
}
// MDC.put(facebookUserId, String.valueOf(facebookUserID));
// chain.doFilter(request, response);
} finally {
// MDC.remove(ipAddress);
// MDC.remove(facebookUserId);
}
return String.valueOf(facebookUserID);
}
public static FacebookXmlRestClient getUserClient(HttpSession session) {
return (FacebookXmlRestClient)session.getAttribute(FACEBOOK_USER_CLIENT);
}
}
Error message:
[ERROR] com.google.gwt.user.client.rpc.InvocationException: <script type="text/javascript">
[ERROR] top.location.href = "http://www.facebook.com/login.php?v=1.0&api_key=MY_KEY&next=notification";
[ERROR] </script>