/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.service.security.acl.sids;
import org.jtalks.common.model.entity.Entity;
import org.jtalks.common.model.entity.Group;
import org.jtalks.common.model.entity.User;
import org.jtalks.jcommune.model.entity.UserInfo;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Decides what implementation of {@link Sid} should be created by the string representation of the sid name (or sid id)
* or its class or whatever. There are might be either standard {@link Sid}s or custom sids like {@link UserGroupSid}.
* If you want to add another possible implementation, take a look at the methods {@link #create(Entity)} and {@link
* #parseCustomSid(String)}.
*
* @author stanislav bashkirtsev
* @see Sid
* @see UniversalSid
*/
public class JtalksSidFactory implements SidFactory {
/**
* This is a static factory, it shouldn't be instantiated.
*/
public JtalksSidFactory() {
}
/**
* {@inheritDoc}
*/
@Override
public Sid createPrincipal(Authentication authentication) {
Object principal = authentication.getPrincipal();
if (principal instanceof UserInfo) {
return new UserSid((UserInfo) principal);
} else if (UserSid.isAnonymous(principal.toString())) {
return UserSid.createAnonymous();
} else {
return new UserSid(principal.toString());
}
}
/**
* {@inheritDoc}
*/
@Override
public List<? extends Sid> createGrantedAuthorities(Collection<? extends GrantedAuthority> grantedAuthorities) {
List<Sid> sids = new ArrayList<Sid>();
for (GrantedAuthority authority : grantedAuthorities) {
sids.add(new GrantedAuthoritySid(authority));
}
return sids;
}
/**
* Creates a list of sids by the underlying classes that were specified.
*
* @param receivers the list of receivers to be wrapped with the respective implementations of {@link Sid}s
* @return the list of sids that wrap the specified receivers. The list might contain {@code null}s if some of
* specified receivers don't have the matching {@link Sid} implementation.
* @see #create(Entity)
*/
public List<Sid> create(List<? extends Entity> receivers) {
List<Sid> sids = new ArrayList<Sid>(receivers.size());
for (Entity next : receivers) {
sids.add(create(next));
}
return sids;
}
/**
* Creates the instance of custom sid that works with specified {@code receiver}. E.g. if the {@link User} or one of
* its children was specified, then a {@link UserSid} instance will be returned.
*
* @param receiver the object to be wrapped with the Sid to become a real receiver from the Spring Security
* perspective
* @return the instance of custom sid that works with specified {@code receiver} or {@code null} if no respective
* sid class was found
*/
public Sid create(Entity receiver) {
if (User.class.isAssignableFrom(receiver.getClass())) {
return new UserSid(receiver.getId());
} else if (Group.class.isAssignableFrom(receiver.getClass())) {
return new UserGroupSid((Group) receiver);
} else {
return null;
}
}
/**
* Looks at the format of the {@code sidName} and finds out what sid implementation should be created. If the
* specified name doesn't comply with the format of custom sids (prefix + {@link UniversalSid#SID_NAME_SEPARATOR} +
* entity id), then ordinary Spring Security implementations are used (either {@link PrincipalSid} or {@link
* GrantedAuthoritySid} which is defined by the second parameter {@code principal}.
*
* @param sidName the name of the sid (its id) to look at its format and decide what implementation of sid should
* be created
* @param principal pass {@code true} if it's some kind of entity ID (like user or group), or {@code false} if it's
* some standard role ({@link GrantedAuthoritySid}
* @return created instance of sid that has the {@code sidName} as the sid id inside
*/
@Override
public Sid create(@Nonnull String sidName, boolean principal) {
Sid toReturn = parseCustomSid(sidName);
if (toReturn == null) {
if (principal) {
toReturn = new PrincipalSid(sidName);
} else {
toReturn = new GrantedAuthoritySid(sidName);
}
}
return toReturn;
}
/**
* Iterates through all the available sid prefixes and finds out what of them suites more to the specified sid
* name.
*
* @param sidName the name of the sid to find the respective sid implementation
* @return the instantiated sid implementation that complies with the pattern of specified sid name or {@code null}
* if no mapping for that name was found and there are no appropriate custom implementations of sid
*/
private static Sid parseCustomSid(String sidName) {
if (sidName.startsWith(UserGroupSid.SID_PREFIX)) {
return new UserGroupSid(sidName);
} else if (sidName.startsWith(UserSid.SID_PREFIX)) {
return new UserSid(sidName);
} else {
return null;
}
}
}