Configuring more than one user in Embedded Tomcat Realm - java

I would like to support more than one user in my realm.
How can this be done?

The following methods should be override as follows:
#Override
protected String getPassword(String username)
{
if(username.equals(_firstUser))
return _firstUserPassword;
else if(username.equals(_secondUser))
return _secondUserPassword;
//etc with your other users
}
#Override
protected Principal getPrincipal(String username)
{
if(username.equals(_firstUser))
{
return new GenericPrincipal(username, _firstUserPassword, _roles);
}
else if(username.equals(_secondUser)
{
return new GenericPrincipal(username, _secondUserPassword, _roles);
}
//etc with your other users
}

Related

How to get the details of the user deleted in keycloak using AdminEvent

i have below code that gets executed when an admin is creating or deleting a user in the keycloak UI.
Through the help of the adminEvent: http://www.keycloak.org/docs/3.0/server_admin/topics/events/admin.html
Creating a user returns the user details via adminEvent.getRepresentation().
However when deleting a user returns me a null.
This is also the same when deleting a role, deleting a group or deleting a user_session.(ResourceTypes)
My question is how can i retrieve the deleted details?
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.models.UserModel;
public void handleResourceOperation(AdminEvent adminEvent, UserModel user) {
MQMessage queueMessage = new MQMessage();
queueMessage.setIpAddress(adminEvent.getAuthDetails().getIpAddress());
queueMessage.setUsername(user.getUsername());
switch (adminEvent.getOperationType()) {
case CREATE:
LOGGER.info("OPERATION : CREATE USER");
LOGGER.info("USER Representation : " + adminEvent.getRepresentation());
String[] split = adminEvent.getRepresentation().split(",");
queueMessage.setTransactionDetail("Created user " + split[0].substring(12));
sendQueueMessage(adminEvent, queueMessage);
break;
case DELETE:
LOGGER.info("OPERATION : DELETE USER");
LOGGER.info("USER Representation : " + adminEvent.getRepresentation());
queueMessage.setTransactionDetail("User has been deleted.");
sendQueueMessage(adminEvent, queueMessage);
break;
}
I'm not sure you got the answer by now. Sharing the solution that may be helpful for others. User details can be captured in postInit method of EventListenerProviderFactory as below,
public class UserEventListenerProviderFactory implements EventListenerProviderFactory {
#Override
public EventListenerProvider create(KeycloakSession keycloakSession) {
return new UserEventListenerProvider(keycloakSession);
}
#Override
public void init(Config.Scope scope) {
}
#Override
public void postInit(KeycloakSessionFactory keycloakSessionFactory) {
keycloakSessionFactory.register(
(event) -> {
if (event instanceof UserModel.UserRemovedEvent) {
UserModel.UserRemovedEvent dEvent = (UserModel.UserRemovedEvent) event;
//TODO YOUR LOGIC WITH `dEvent.getUser()`
}
});
}
#Override
public void close() {
}
#Override
public String getId() {
return "sample_event_listener";
}
}

Create a global Realm file for a collaborative android app

My app is a collaborative app where users should be able to write/read into a global Realm file to share data between them. I would also like to include some initial data (realmObjects) in the Realm file which will be common to all users.
User will sign up to, then, be able to create data and share the data with all the users. The initial data, created only once, should be available to all users.
I am not able to assign user permissions (write/read) to each new user once they sign-up/login in the app. The common data is created multiple time since the query (realm.where(realmObject.class).findall() returns no results, even though it has been created.
public static final String AUTH_URL = "http://" + BuildConfig.OBJECT_SERVER_IP + ":9080/auth";
public static final String REALM_URL = "realm://" + BuildConfig.OBJECT_SERVER_IP + ":9080/default";
UserManager class
public class UserManager {
// Supported authentication mode
public enum AUTH_MODE {
PASSWORD,
FACEBOOK,
GOOGLE
}
private static AUTH_MODE mode = AUTH_MODE.PASSWORD; // default
public static void setAuthMode(AUTH_MODE m) {
mode = m;
}
public static void logoutActiveUser() {
switch (mode) {
case PASSWORD: {
break;
}
case FACEBOOK: {
LoginManager.getInstance().logOut();
break;
}
case GOOGLE: {
break;
}
}
SyncUser.currentUser().logout();
}
// Configure Realm for the current active user
public static void setActiveUser(SyncUser user) {
Realm.removeDefaultConfiguration();
SyncConfiguration defaultConfig = new SyncConfiguration.Builder(user, REALM_URL).name("Realm").schemaVersion(0).build();
Realm.setDefaultConfiguration(defaultConfig);
setDefaultPermissionsRealm(user);
}
private static void setDefaultPermissionsRealm(SyncUser user){
if (user.getIdentity().toString().equals(PRIVILAGE)){
Realm realm = user.getManagementRealm();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
Boolean mayRead = true; // Grant read access
Boolean mayWrite = true; // Keep current permission
Boolean mayManage = false; // Revoke management access
PermissionChange change = new PermissionChange(REALM_URL,
"*",
mayRead,
mayWrite,
mayManage);
realm.insert(change);
}
});
}
}
}
SplashActivity
SyncUser.loginAsync(SyncCredentials.usernamePassword(eMail, password, true), AUTH_URL, new SyncUser.Callback() {
#Override
public void onSuccess(SyncUser syncUser) {
loginRegistrationSuccess = true;
registrationComplete(syncUser);
}
#Override
public void onError(ObjectServerError error) {
loginRegistrationSuccess = false;
}
});
facebookAuthRegistration = new FacebookAuth((LoginButton) findViewById(R.id.sign_up_facebook), this) {
#Override
public void onRegistrationComplete(final LoginResult loginResult, User userInfo) {
UserManager.setAuthMode(UserManager.AUTH_MODE.FACEBOOK);
SyncCredentials credentials = SyncCredentials.facebook(loginResult.getAccessToken().getToken());
SyncUser.loginAsync(credentials, AUTH_URL, SplashScreenActivity.this);
}
};
googleAuthRegistration = new GoogleAuth((Button) findViewById(R.id.sign_up_google), this, googleAuthLogin.getmGoogleApiClient()) {
#Override
public void onRegistrationComplete(GoogleSignInResult result) {
UserManager.setAuthMode(UserManager.AUTH_MODE.GOOGLE);
GoogleSignInAccount acct = result.getSignInAccount();
SyncCredentials credentials = SyncCredentials.google(acct.getIdToken());
SyncUser.loginAsync(credentials, AUTH_URL, SplashScreenActivity.this);
}
};
#Override
public void onSuccess(SyncUser syncUser) {
loginRegistrationSuccess = true;
showProgress(false);
registrationComplete(syncUser);
}
private void registrationComplete(SyncUser syncUser) {
UserManager.setActiveUser(syncUser);
Intent mainIntent = new Intent(SplashScreenActivity.this, MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
SplashScreenActivity.this.startActivity(mainIntent);
SplashScreenActivity.this.finish();
}
It looks like if I am creating a different realm for each user even though I am not including in the URL the "~".
Could anyone tell me what I am doing wrong?
Thanks
Initially, you will need to create the Realm using the admin user, and set the permissions for all other users can access it. If you are using the Pro edition, you could create the Realm using a small node.js script. Alternatively, you could create a small internal app with the single purpose of creating the Realm using the admin user.
Users are only allowed to create Realm within their home directory (~ so to speak) but they can share it with other users. Doing so, you will have to distribute the user id of that first user.

How to get key's names returning after Twitter Success?

I am a newbee in java. I have integrated Twitter with the help of Fabric SDK. I am getting data like screen_name,username etc. as mentioned in a tutorial. But I am unable to get the tweets.
I didn't know the Exact key name for that. When I am print the data returned after success All I see is an ID with models.User. This is confusing me.
MainActivity.java
loginButton = (TwitterLoginButton) findViewById(R.id.twitter_login_button);
loginButton.setCallback(new Callback<TwitterSession>() {
#Override
public void success(Result<TwitterSession> result) {
session = Twitter.getSessionManager().getActiveSession();
Twitter.getApiClient(session).getAccountService()
.verifyCredentials(true, false, new Callback<User>() {
#Override
public void success(Result<User> userResult) {
User user = userResult.data;
System.out.println(user);
}
#Override
public void failure(TwitterException e) {
}
});
loginButton.setVisibility(View.GONE);
}
#Override
public void failure(TwitterException exception) {
}
});
Console
I/System.out: com.twitter.sdk.android.core.models.User#427ba968
Hope that someone solve this.Regards
Well I found this
#Override
public void success(Result<User> userResult) {
User user = userResult.data;
System.out.println(user);
Gson gson = new Gson();
String userFeed = gson.toJson(user);
System.out.println(userFeed);
}
this gson gave json data from models.User.

Spring MVC #SessionAttributes

here's my code for the controller:
I have put my object in a map in the "doLogin" method below and I am trying to access it in my "logout" function but I am getting null value when I am trying to fetch value of my session attribute using "map.get(key)"
#Controller
#SessionAttributes(value={"session1"})
public class CredentialsController {
#Autowired
private Authentication authenticationDao;
#Autowired
private User userDao;
#RequestMapping(value="/start",method=RequestMethod.GET) //Default Method
public String doStart(#ModelAttribute CredentialsBean credentialsBean)
{
return "login";
}
#RequestMapping(value="/login",method=RequestMethod.GET) //Default Method
public String doLogin(#ModelAttribute CredentialsBean credentialsBean,Map<String,Object> map)
{
String result="";
if(credentialsBean!=null){
if(authenticationDao.authenticate(credentialsBean)){
String userType=authenticationDao.authorize(credentialsBean.getUserID());
if(userType.equalsIgnoreCase("A")){
CredentialsBean cBean= authenticationDao.changeLoginStatus(credentialsBean, 1);
map.put("session1",cBean); ----->Here I am putting the object inside a map .
result= "admin";
//map.put("username",credentialsBean.getProfileBean().getFirstName());
}
else{
CredentialsBean cBean=authenticationDao.changeLoginStatus(credentialsBean, 1);
map.put("session1",cBean.getUserID());
//System.out.println(cBean.getUserID());
result= "customer";
//map.put("username",credentialsBean.getProfileBean().getFirstName());
}
}
else{
result="ERROR";
}
}
return result;
}
#RequestMapping(value="/logout",method=RequestMethod.GET) //Default Method
public String doLogout(Map<String,Object > map)
{
CredentialsBean credentialsBean=(CredentialsBean)map.get("session1");
//System.out.println(userID);
System.out.println(credentialsBean.getUserID());
if(credentialsBean!=null){
if(userDao.logout(credentialsBean.getUserID())){
return "logout";
}
else{
return "error1";
}
}
else{
return "error";
}
}
}
Here is the way I would do it:
in your doLogin method you should add HttpSession session:
#RequestMapping(value="/login",method=RequestMethod.GET) //Default Method
public String doLogin(#ModelAttribute CredentialsBean credentialsBean, HttpSession session)
{
String result="";
if(credentialsBean!=null){
if(authenticationDao.authenticate(credentialsBean)){
String userType=authenticationDao.authorize(credentialsBean.getUserID());
if(userType.equalsIgnoreCase("A")){
CredentialsBean cBean= authenticationDao.changeLoginStatus(credentialsBean, 1);
// add object to session
session.setAttribute("session1",cBean);
result= "admin";
//map.put("username",credentialsBean.getProfileBean().getFirstName());
}
else{
CredentialsBean cBean=authenticationDao.changeLoginStatus(credentialsBean, 1);
session.setAttribute("session1",cBean);
result= "customer";
}
}
else{
result="ERROR";
}
}
return result;
}
Note, that you should add to session objects of the same type in order to safely retrieve it later (because now you added different objects cBean and cBean.getUserID() for the same key session1)
Then in your logout:
#RequestMapping(value="/logout",method=RequestMethod.GET) //Default Method
public String doLogout(HttpSession session)
{
CredentialsBean credentialsBean=(CredentialsBean)session.getAttribute("session1");
.....
}
But anyway, since you're implementing login\logout here I encourage you to learn more about Spring Security.

How to get username inside CustomPasswordEncoder in SpringSecurity?

I am introducing Spring Security in an existing application. Currently db has MD5 encoded passwords which we want to migrate to bcrypt. Since we have a large number of users initially we would like to support both MD5 and bcrypt together. We have thought off having a table which will store how many users are migrated to bcrypt once we have every one migrated we will stop supporting MD5.
So I thought of extending the BCryptPasswordEncoder class of SpringSecurity and do the things inside matches method. So I have below class,
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class CustomPasswordEncoder extends BCryptPasswordEncoder {
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (rawPassword == null || encodedPassword == null) {
return false;
}
if (!super.matches(rawPassword, encodedPassword)) { // This is not BCrypt password try OLD password encoding instead
boolean isOldPasswordMatched = rawPassword.equals(SHA1.getSHA1Hash(encodedPassword));
if(isOldPasswordMatched){
migrateToBCrypt(userName /* error here*/, encode(rawPassword));
}
return isOldPasswordMatched;
}
return true;
}
private boolean migrateToBCrypt(String userName, String newBcryptPassword){
//update password in database
//Insert to migrated table
return true;
}
}
However my problem is I don't get username inside this function to do the migration, How can I get username inside matches() of password encoder ? Am I doing something wrong here ? What could be the best approach in this situation ?
The proposed logic is just my idea, you can modify it as per your needs.
public class UserService extends BCryptPasswordEncoder{
public Response login(#RequestBody User user){
User existingUser = UserDao.getInstance().getUserByUsername( user.getUsername() );
//Assuming all the users have `PasswordType` column as "MD5" in user table
if( existingUser.getPasswordType().equals("MD5") ){
// Your MD5 verification method, return boolean
if( verifyMD5(user.getPassword, existingUser.getPassword()) ){
migrateToBCrypt(existingUser, user);
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}else if( existingUser.getPasswordType().equals("BCrypt") ){
if( matches(user.getPassword(), existingUser.getPassword()) ){
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}
}
private void migrateToBcrypt(User existingUser, User user){
existingUser.setPassword( encode(user.getPassword()) );
existingUser.setPasswordType( "Bcrypt" );
UserDao.getInstance().updateUser( existingUser );
}
}
Or if you don't want to introduce another column on table,
public class UserService extends BCryptPasswordEncoder{
public Response login(#RequestBody User user){
User existingUser = UserDao.getInstance().getUserByUsername( user.getUsername() );
if( !existingUser.getPassword().startsWith("$") ){
// Your MD5 verification method, return boolean
if( verifyMD5(user.getPassword, existingUser.getPassword()) ){
migrateToBCrypt(existingUser, user);
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}else {
if( matches(user.getPassword(), existingUser.getPassword()) ){
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}
}
private void migrateToBcrypt(User existingUser, User user){
existingUser.setPassword( encode(user.getPassword()) );
UserDao.getInstance().updateUser( existingUser );
}
}

Categories