package de.passau.uni.sec.compose.id.core.service.security;
import java.util.Collection;
import java.util.LinkedList;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
//import com.sun.org.apache.xml.internal.security.utils.Base64;
import de.passau.uni.sec.compose.id.common.exception.IdManagementException;
import de.passau.uni.sec.compose.id.common.exception.IdManagementException.Level;
import de.passau.uni.sec.compose.id.core.domain.ComposeComponentPrincipal;
import de.passau.uni.sec.compose.id.core.domain.ComposeUserPrincipal;
import de.passau.uni.sec.compose.id.core.domain.IPrincipal;
import de.passau.uni.sec.compose.id.core.event.Event;
import de.passau.uni.sec.compose.id.core.persistence.entities.User;
import de.passau.uni.sec.compose.id.core.persistence.repository.UserRepository;
import de.passau.uni.sec.compose.id.core.service.security.uaa.OpenIdUserData;
@Service
@PropertySource("classpath:anonymousUser.properties")
public class RestAuthentication
{
private static final String UPPER_CASE_TOKEN_OAUTH2 = "BEARER";
private static final String[] Roles = {"COMPONENT"};
private static Logger LOG = LoggerFactory.getLogger(RestAuthentication.class);
@Resource
private Environment env;
@Autowired
private UsersAuthzAndAuthClient uaa;
@Autowired
UserRepository userRepository;
/**
* This method only builds the Collection of Principals.It needs to be checked by the sub classes whether the principals have
* sufficient permissions for the requested action.
* @param credentials list of credentials provided.
* @throws IdManagementException when the credentials are not valid
*/
public Collection<IPrincipal> authenticatePrincipals(Logger logger,Collection<String> credentials) throws IdManagementException
{
Collection<IPrincipal> principals = new LinkedList<IPrincipal>();
// This object comes from Spring authentication to the API.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
IPrincipal principal = null;
String credentialsUsedToAuthenticate="none";
boolean componentThere=false,userThere=false;
//if there are tokens for users
for( String cred: credentials)
{
if(cred == null)
throw new IdManagementException("Field with empty credentials",null, LOG," A null credential string was found while trying to authenticate: ",Level.ERROR, 401);
if(cred.toUpperCase().startsWith(UPPER_CASE_TOKEN_OAUTH2))
{
cred = cred.substring(UPPER_CASE_TOKEN_OAUTH2.length());
cred = cred.trim();
credentialsUsedToAuthenticate=cred;
//if the user provides the generic token set for anonymous
//create a garbage uaa token and set principals accordingly
if(credentialsUsedToAuthenticate.equals(env.getRequiredProperty("anontoken"))) {
String username = env.getProperty("anonusername");
OpenIdUserData openId = new OpenIdUserData();
openId.setEmail(env.getProperty("anonemail"));
openId.setFamily_name("compose");
openId.setGiven_name(username);
openId.setName(username + " compose");
openId.setUser_id(env.getProperty("anonid"));
openId.setUser_name(username);
principal = new ComposeUserPrincipal();
principal.setTokenCredentials("anonymousUserUaaToken");
((ComposeUserPrincipal)principal).setOpenId(openId);
userThere=true;
principals.add(principal);
LOG.debug("User with user_id: "+openId.getUser_id()+" has been authenticated");
}else {
OpenIdUserData openId = uaa.getOpenIdData(cred);
principal = new ComposeUserPrincipal();
principal.setTokenCredentials(cred);
((ComposeUserPrincipal)principal).setOpenId(openId);
userThere=true;
principals.add(principal);
LOG.debug("User with user_id: "+openId.getUser_id()+" has been authenticated");
}
}
}
//If there is a component calling the API
if(auth!=null && auth.getPrincipal()!=null)
{
Object o = auth.getPrincipal();
if(!userThere && o instanceof String)
LOG.error("The principal seems to be an anonymous user (unauthenticated Compose Component)?: \""+o+"\" disregarding credentials");
else if(o instanceof org.springframework.security.core.userdetails.User)
{
credentialsUsedToAuthenticate="HTTP Digest credentials";
UserDetails component = (UserDetails)o;
//authentication successful with Spring methods (used for components)
ComposeComponentPrincipal p = new ComposeComponentPrincipal();
p.setComposeComponentName(component.getUsername()+": authenticated with http digest auth");
principal = p;
componentThere=true;
principals.add(principal);
LOG.debug("Compose entity authentication successfull: entity: "+component.getUsername());
}
else if(!userThere)
LOG.error("Unexpected Principal from spring security framework: class coming from autheorization.getUserDetails(): "+o.getClass().toString());
}
if(!componentThere&&!userThere)
throw new IdManagementException("Authentication failed, wrong credentials ",null, LOG," Incorrect credentials: \""+credentialsUsedToAuthenticate+"\"",Level.ERROR, 401);
return principals;
}
/**
*
* @return basic information for the authenticated principals
*/
public static String getBasicInfoPrincipals(Collection<IPrincipal> principals)
{
String ret = "";
for(IPrincipal p: principals)
{
ret += p.getStringBasicInfo()!=null?p.getStringBasicInfo():"";
}
return ret;
}
public static ComposeUserPrincipal getComposeUser(Collection<IPrincipal> principals) throws IdManagementException
{
ComposeUserPrincipal user = null;
for(IPrincipal p: principals)
if(p instanceof ComposeUserPrincipal)
user = (ComposeUserPrincipal) p;
if(user != null)
return user;
throw new IdManagementException("Error in authentication of the user",null,LOG,"Null ComposeUser as ComposeIPrincipal",Level.ERROR,500);
}
/**
* This method is used to get the actual user from the database, which corresponds to the first user in the list of Principals for the event.
* @param event
* @return
* @throws IdManagementException if there is not user found in the list of principals of the event, or if the user is not found in the local database
*/
public User getUserFromEvent(Event event) throws IdManagementException
{
Collection<IPrincipal> principals = event.getPrincipals();
ComposeUserPrincipal user = null;
for(IPrincipal p: principals)
if(p instanceof ComposeUserPrincipal)
user = (ComposeUserPrincipal) p;
if(user != null)
{
User u = userRepository.getOne(user.getOpenId().getUser_id());
if(u != null)
return u;
else
LOG.error("User with id "+user.getOpenId().getUser_id()+" not found in the local database");
}
throw new IdManagementException("No user authenticated successfully for the request",null,LOG,"There is no user in principals priovided for the request, or it is not in the local database: "+ event.getLoggingDetails(),Level.ERROR,401);
}
/*public String createBasicHTTPAuthenticationToken(String username, String password)
{
String plainCreds = username + ":" + password;
byte[] plainCredsBytes = plainCreds.getBytes();
String base64Creds = Base64.encode(plainCredsBytes);
return base64Creds;
}*/
}