/*******************************************************************************
*
* Copyright 2010 Alexandru Craciun, and individual contributors as indicated
* by the @authors tag.
*
* This 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 3 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
******************************************************************************/
package org.netxilia.api.impl.user;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.netxilia.api.INetxiliaSystem;
import org.netxilia.api.command.CellCommands;
import org.netxilia.api.exception.AlreadyExistsException;
import org.netxilia.api.exception.NetxiliaBusinessException;
import org.netxilia.api.exception.NetxiliaResourceException;
import org.netxilia.api.exception.NotFoundException;
import org.netxilia.api.exception.StorageException;
import org.netxilia.api.formula.Formula;
import org.netxilia.api.impl.model.SheetNames;
import org.netxilia.api.impl.model.WorkbookIds;
import org.netxilia.api.model.CellData;
import org.netxilia.api.model.ISheet;
import org.netxilia.api.model.SheetType;
import org.netxilia.api.model.WorkbookId;
import org.netxilia.api.operation.ISheetOperations;
import org.netxilia.api.reference.AreaReference;
import org.netxilia.api.reference.CellReference;
import org.netxilia.api.user.AclPrivilegedMode;
import org.netxilia.api.user.IUserService;
import org.netxilia.api.user.Role;
import org.netxilia.api.user.User;
import org.netxilia.api.utils.Matrix;
import org.netxilia.api.value.IGenericValue;
import org.netxilia.api.value.StringValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class UserServiceImpl implements UserDetailsService, IUserService, ISpringUserService {
private final static Logger log = Logger.getLogger(UserServiceImpl.class);
private String userSheetName = SheetNames.USERS;
@Autowired
private INetxiliaSystem workbookProcessor;
@Autowired
private ISheetOperations sheetOperations;
public INetxiliaSystem getWorkbookProcessor() {
return workbookProcessor;
}
public void setWorkbookProcessor(INetxiliaSystem workbookProcessor) {
this.workbookProcessor = workbookProcessor;
}
public String getUserSheetName() {
return userSheetName;
}
public void setUserSheetName(String userSheetName) {
this.userSheetName = userSheetName;
}
public ISheetOperations getSheetOperations() {
return sheetOperations;
}
public void setSheetOperations(ISheetOperations sheetOperations) {
this.sheetOperations = sheetOperations;
}
protected ISheet getUsersSheet() throws StorageException, NotFoundException {
try {
return workbookProcessor.getWorkbook(WorkbookIds.SYSTEM).getSheet(userSheetName);
} catch (NotFoundException e) {
return null;
}
}
protected ISheet getWriteableUsersSheet() throws StorageException, NotFoundException {
try {
return workbookProcessor.getWorkbook(WorkbookIds.SYSTEM).getSheet(userSheetName);
} catch (NotFoundException e) {
try {
return workbookProcessor.getWorkbook(WorkbookIds.SYSTEM).addNewSheet(userSheetName, SheetType.normal);
} catch (AlreadyExistsException e1) {
// try one more time
return workbookProcessor.getWorkbook(WorkbookIds.SYSTEM).getSheet(userSheetName);
}
}
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
ISheet sheet = null;
try {
log.info("Load user details for " + userName);
AclPrivilegedMode.set();
sheet = getUsersSheet();
if (sheet == null) {
throw new UsernameNotFoundException(userName);
}
CellReference ref = sheetOperations.find(sheet, null, new Formula("=A1=\"" + userName + "\""))
.getNonBlocking();
if (ref == null) {
throw new UsernameNotFoundException(userName);
}
// A=username
// B=password
// all=ROLE_USER,
// ROLE_ADMIN=?
Matrix<CellData> cells = sheet.receiveCells(
new AreaReference(null, ref.getRowIndex(), 0, ref.getRowIndex(), 3)).getNonBlocking();
String password = cells.get(0, 1).getValue().getStringValue();
String roles = cells.get(0, 3).getValue().getStringValue();
String[] rolesArray = StringUtils.split(roles, ",");
Role[] netxiliaRoles = new Role[rolesArray.length];
GrantedAuthority[] springRoles = new GrantedAuthority[rolesArray.length];
for (int i = 0; i < rolesArray.length; ++i) {
springRoles[i] = new GrantedAuthorityImpl(rolesArray[i]);
netxiliaRoles[i] = Role.valueOf(rolesArray[i]);
}
User netxiliaUser = new User();
netxiliaUser.setLogin(userName);
netxiliaUser.setPassword(password);
netxiliaUser.setRoles(netxiliaRoles);
SpringUserAdapter springUser = new SpringUserAdapter(netxiliaUser, true, true, true, true, springRoles);
log.info("Done user details for " + userName);
return springUser;
} catch (NotFoundException e) {
throw new DataRetrievalFailureException("Sheet 'system.users' not found", e);
} catch (StorageException e) {
throw new DataRetrievalFailureException("Sheet 'system.users' not found", e);
} catch (NetxiliaResourceException e) {
throw new DataRetrievalFailureException("Sheet 'system.users' not found", e);
} catch (NetxiliaBusinessException e) {
throw new DataRetrievalFailureException("Sheet 'system.users' not found", e);
} finally {
AclPrivilegedMode.clear();
}
}
@Override
public void addUser(User user) throws StorageException {
ISheet sheet = null;
Map<String, IGenericValue> values = new HashMap<String, IGenericValue>();
values.put("A", new StringValue(user.getLogin()));
values.put("B", new StringValue(user.getPassword()));
if (user.getEmail() != null) {
values.put("C", new StringValue(user.getEmail().getEmail()));
}
values.put("D", new StringValue(StringUtils.join(user.getRoles(), ',')));
try {
AclPrivilegedMode.set();
sheet = getWriteableUsersSheet();
sheet.sendCommand(CellCommands.mapValues(AreaReference.lastRow(0, 3), values));
} catch (NotFoundException e) {
// should not happen as the sheet was previously created
throw new RuntimeException(e);
} finally {
AclPrivilegedMode.clear();
}
}
@Override
public boolean isAdminAccountCreated() throws NetxiliaResourceException, NetxiliaBusinessException {
ISheet sheet = null;
try {
AclPrivilegedMode.set();
sheet = getUsersSheet();
if (sheet == null) {
return false;
}
List<Integer> rows = sheetOperations.filter(sheet, new Formula("=D1=\"ROLE_ADMIN\"")).getNonBlocking();
return rows != null && rows.size() > 0;
} catch (NotFoundException e) {
return false;
} finally {
AclPrivilegedMode.clear();
}
}
@Override
public User getCurrentUser() {
if (SecurityContextHolder.getContext() != null
&& SecurityContextHolder.getContext().getAuthentication() != null) {
if (!(SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof SpringUserAdapter)) {
return null;
}
SpringUserAdapter springUserAdapter = (SpringUserAdapter) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
if (springUserAdapter != null) {
return springUserAdapter.getNetxiliaUser();
}
}
return null;
}
public Authentication getSpringAuthentication() {
if (SecurityContextHolder.getContext() != null) {
return SecurityContextHolder.getContext().getAuthentication();
}
return null;
}
public void setSpringAuthentication(Authentication auth) {
if (SecurityContextHolder.getContext() != null) {
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
@Override
public WorkbookId getWorkbookId() {
return WorkbookIds.SYSTEM;
}
}