Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YarepGroup.addMember() not multi-threadable #1

Open
baszero opened this issue Feb 21, 2012 · 0 comments
Open

YarepGroup.addMember() not multi-threadable #1

baszero opened this issue Feb 21, 2012 · 0 comments

Comments

@baszero
Copy link
Contributor

baszero commented Feb 21, 2012

Use-Case:

Last evening we had the rare situation where two different users did exactly the same thing.
The triggered action involved adding the user to a specific Yarep group.

My realm's code is using the group.addMember() method in order to assign a user to a specific group.

Error Description:

What happened was the following: Two threads tried to manipulate the .xml file via the standard Yarep API.
The group XML was corrupted after this and we had to manually repair the file.

Suggestion for improvement:

All methods that do physical changes in files should do this in a synchronized way.
But just applying synchronized(LOCK) in the addMember() method will not suffice, because when you save the file you must be sure that no other thread has already read the file as well. Two writes one after the other can overwrite their changes.

So my proposal would be to synchronized(LOCK) the addMember() method, and INSIDE the locked code I would reread the group, only then you can be sure that you are the only one reading the file for manipulation.

So the code could look like this:

private static final Object LOCK = new Object(); // The best way to have class locks!

public void addMember(Item item) throws AccessManagementException {
        if (null != item){
            if (item instanceof User) {
                memberUserIDs.add(item.getID());
                ((YarepUser) item).addGroup(getID());
                save();
            } else if (item instanceof Group) {
                if (wouldCreateGroupLoop(getID(), (Group)item)) {
                    // ...
                }
                // don't do this: memberGroupIDs.add(item.getID()); --> remove this line
                // Instead:
                synchronized(LOCK) {
                  Group g = ...; // Read group again
                  g.addParentGroup(getID()); // INFO: Add back/bi-directional link
                  g.save();
                }
            } else {
                log.warn("Item '" + item.getID() + "' is neither user nor group: " + item.getClass().getName());
            }
        } else {
            log.warn("Item is null. Can't add item (user or group) to the group '" + getID() + "'");
        }
    }

If you like, I can send a patch for this as an example? Please let me know.

Workaround:
The best workaround for this is to use synchronized blocks in the realm's code. Then the complexity of locking is transferred into the realm's code. But it would probably be easier for Yanel-Developers if they would not have to deal with this.

Source Code:

Link to method:
https://github.com/wyona/security/blob/master/src/impl/java/org/wyona/security/impl/yarep/YarepGroup.java#L191

csstaub pushed a commit that referenced this issue Jul 27, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant