/*
* Copyright 2012 Nodeable Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.streamreduce.core.service;
import com.streamreduce.ValidationException;
import com.streamreduce.connections.GatewayProvider;
import com.streamreduce.core.dao.ConnectionDAO;
import com.streamreduce.core.dao.RoleDAO;
import com.streamreduce.core.dao.UserDAO;
import com.streamreduce.core.model.APIAuthenticationToken;
import com.streamreduce.core.model.Account;
import com.streamreduce.core.model.Connection;
import com.streamreduce.core.model.Role;
import com.streamreduce.core.model.User;
import com.streamreduce.core.service.exception.UserNotFoundException;
import com.streamreduce.rest.resource.ErrorMessages;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("securityService")
public class SecurityServiceImpl extends AbstractService implements SecurityService {
@Autowired
private UserDAO userDAO;
@Autowired
private RoleDAO roleDAO;
@Autowired
private ConnectionDAO connectionDAO;
@Override
public User getCurrentUser() {
return getShiroUser();
}
@Override
public Connection getCurrentGatewayConnection() {
final String apiKey = (String) SecurityUtils.getSubject().getPrincipal();
if (apiKey != null) {
return getByApiKey(apiKey, GatewayProvider.TYPE);
} else {
throw new AuthenticationException("A gateway connection must be logged in!");
}
}
@Override
public void logoutCurrentUser(String token) {
Subject s = SecurityUtils.getSubject();
if (s != null) {
logger.debug("Logout user: kill the Shiro Session");
s.logout();
} else {
logger.debug("Logout user, subject not found in SecurityUtils");
}
}
@Override
public APIAuthenticationToken issueAuthenticationToken(User user) throws ValidationException, UserNotFoundException {
APIAuthenticationToken newToken = new APIAuthenticationToken();
user.setAuthenticationToken(newToken);
userDAO.save(user);
return newToken;
}
@Override
public boolean hasRole(String roleName) {
Subject currentUser = SecurityUtils.getSubject();
return (currentUser.hasRole(roleName));
}
@Override
public Role findRole(String role) {
return roleDAO.findRole(role);
}
@Override
public Set<User> getActiveUsers(Account account, Long maxInactivity) {
// TODO: cache this
return userDAO.getActiveLoggedInUsers(account, maxInactivity);
}
@Override
public User getUserFromAuthenticationToken(final String token) {
return userDAO.findByAuthToken(token);
}
@Override
public Connection getByApiKey(final String token, final String type) {
return connectionDAO.getByAPIKey(token, type);
}
/**
* Sort of a fragile wrapper to get the User from the User Realm or the Gateway Realm
* TODO: we need a better way to store these
*
* @return - The User who is logged in, or the User who is owns the IMG connection request.
*/
private User getShiroUser() {
try {
final Object id = SecurityUtils.getSubject().getPrincipal();
if (id != null) {
if (id instanceof ObjectId) {
return userDAO.get((ObjectId) id);
} else if (id instanceof String) { // must be IMG
Connection connection = connectionDAO.getByAPIKey((String) id, GatewayProvider.TYPE);
return connection.getUser();
}
}
} catch (UnavailableSecurityManagerException e) {
throw new AuthenticationException(e.getMessage());
}
throw new AuthenticationException(ErrorMessages.INVALID_CREDENTIAL);
}
}