I have configured a security-interceptor which should have the user-session object (which is a singleton) injected here is what I tried:
public DependencyInjection extends AbstractModule{
//Class that has AccessLevel Annoation
bind(InterfaceA.class).to(ImplA.class);
bind(UserPersistor.class).to(UserPersistorImpl.class);
//My session that I wish to inject
bind(UserSession.class).to(UserSessionHandler.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
}
Here my UserSessionHandler:
#Singleton
public class UserSessionHandler implements UserSession {
private UserLevel userLevel = UserLevel.DEFAULT;
private final UserPersistor userPersistor;
#Inject
public UserSessionHandler(UserPersistor userPersistor) {
this.userPersistor = userPersistor;
}
#Override
public boolean loginUser(String userName, String password) {
Benutzer user = userPersistor.getUserByName(userName);
if (user == null) {
return false;
} else {
if (user.getKennwort().equals(password)) {
userLevel = UserLevel.valueOf(user.getRolleId().getBezeichnung().toUpperCase());
return true;
} else {
return false;
}
}
}
#Override
public boolean logoutUser() {
userLevel = UserLevel.DEFAULT;
return true;
}
#Override
public UserLevel getUserLevel() {
return userLevel;
}
}
Here how the SecurityInterceptor currently looks like:
#Singleton
public class SecurityInterceptor implements MethodInterceptor {
private final Provider<UserSession> session;
#Inject
public SecurityInterceptor(Provider<UserSession> session){
this.session = session;
}
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
AccessLevel[] acessRoles = invocation.getMethod().getAnnotationsByType(AccessLevel.class);
List<UserLevel> allowedRoles = new ArrayList<>();
for(AccessLevel accessRole: acessRoles){
allowedRoles.add(accessRole.value());
}
//Make sure that User has one of the allowed Access-Levels
if (!allowedRoles.contains(session.get().getUserLevel())) {
throw new InvalidAccessException("No Access allowed with userlevel" + session.get().getUserLevel());
}
return invocation.proceed();
}
}
Now I managed to get it working in my Mockito-Test with a binding to an instance like this:
bind(MockInterface.class).to(MockClass.class);
bind(UserSession.class).toInstance(user);
bind(UserPersistor.class).toInstance(mockUserPersistor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
However I don't want to create an instance myself but want the once guice is creating. How can I do that, or what am I currently doing wrong?
EDIT: My main issue is that the usersession seems to be different to the one that is generated. Here a simple example:
Injector injector = Guice.createInjector(new DependencyInjection());
UserSession session = injector.createInstance(UserSession.class);
InterfaceA methodCaller = injector.createInstance(InterfaceA.class);
if(session.loginUser("a","b")){
System.out.println(session.getUserLevel().toString()); //Returns Admin
}
methodCaller.callMethodWithAnnotation();
Now when I check the session.getUserLevel in the interceptor I get "Default"
EDIT2: My endgoal is to have the same session instance in my interceptor and anywhere I used UserSession
Related
I am making a shopping cart using a stateful session bean approach of Java EE Application. My plan is that after a user clicks on 'Checkout' button the order will be added to the database. However, the order is not updated in the database.
ShoppingCartFacade.java
#Stateful
public class ShoppingCartFacade implements ShoppingCartFacadeLocal {
#PersistenceContext(unitName = "DProject-ejbPU", type = PersistenceContextType.EXTENDED)
private EntityManager em;
private void create(Tickettable tickettable) {
em.persist(tickettable);
}
private ArrayList<Tickettable> ticketCart;
#PostConstruct
private void initializeBean(){
ticketCart = new ArrayList<>();
}
#Override
public boolean add(Tickettable tickettable) {
boolean result = false;
//Set the correct user and showtime table
tickettable.setUserid(this.getUsertableFrom(tickettable.getUserid().getUserid()));
tickettable.setShowtimeid(this.getShowtimetableFrom(tickettable.getShowtimeid().getShowtimeid()));
try {
//Already have ticket for this showtime
for (Tickettable ticket : ticketCart) {
if (ticket.getShowtimeid().getShowtimeid().equals(tickettable.getShowtimeid().getShowtimeid())) {
ticket.setQuantity(ticket.getQuantity() + tickettable.getQuantity());
result = true;
}
}
//New ticket
if (!result) {
ticketCart.add(tickettable);
result = true;
}
} catch (Exception ex) {
}
return result;
}
#Override
public ArrayList<Tickettable> getCart() {
return ticketCart;
}
#Override
public boolean checkOut() {
try {
for (Tickettable ticket : ticketCart) {
create(ticket);
}
ticketCart.clear();
return true;
} catch (Exception e) {
}
return false;
}
private Usertable getUsertableFrom(String userId) {
Usertable u = em.getReference(Usertable.class, userId);
return u;
}
private Showtimetable getShowtimetableFrom(String showtimeId) {
Showtimetable s = em.getReference(Showtimetable.class, showtimeId);
return s;
}
#Remove
public void remove() {
ticketCart = null;
}
}
ShoppingCartManagement.java
#Stateful
public class ShoppingCartManagement implements ShoppingCartManagementRemote {
#EJB
private ShoppingCartFacadeLocal shoppingCartFacade;
#Override
#PermitAll
public boolean add(TicketDTO ticketDTO) {
if (ticketDTO == null) {
// just in case
return false;
}
// convert to entity
Tickettable ticket = Utility.ticketDTO2Entity(ticketDTO);
// add one
return shoppingCartFacade.add(ticket);
}
#Override
#PermitAll
public ArrayList<TicketDTO> getCart() {
try {
ArrayList<Tickettable> alst = shoppingCartFacade.getCart();
if (alst.isEmpty()) {
//not found
return null;
} else {
ArrayList<TicketDTO> alsDTO = new ArrayList<>(alst.size());
for (Tickettable stt : alst) {
TicketDTO stDTO = Utility.ticketEntity2DTO(stt);
alsDTO.add(stDTO);
}
return alsDTO;
}
} catch (NullPointerException e) {
throw e;
}
}
#Override
#PermitAll
public boolean checkOut() {
return shoppingCartFacade.checkOut();
}
}
ShoppingCartManagedBean.java in War
#Named(value = "shoppingCartManagedBean")
#RequestScoped
public class ShoppingCartManagedBean implements Serializable{
.....
#EJB
private ShoppingCartManagementRemote shoppingCartManagement;
public String addTicket(){
this.quantity += 1;
UserDTO u = new UserDTO(userId,"","","","","");
ShowtimeDTO s = new ShowtimeDTO(showtimeId,"","","","","");
TicketDTO t = new TicketDTO("111111",u,s,Integer.toString(this.quantity));
//carts = shoppingCartManagement.getCart();
boolean result = shoppingCartManagement.add(t);
if(result){
return "success";
}
return "failure";
}
public String checkout(){
/*return shoppingCartManagement.checkOut();*/
boolean result = shoppingCartManagement.checkOut();
if(result) return "success";
return "failure";
}
}
*********************** UPDATE **********************
I just made the test. The cartList in ShoppingCartFacade.java is empty.
You need to be aware of the lifecycle management of the various beans that you're using.
#Stateful beans are not implicitly associated with the servlet/JSF session.
A new instance of ShoppingCartManagedBean will be created for each incoming request as it is #RequestScoped. This instance will automatically get a reference to a new instance of ShoppingCartManagement which will in turn get a reference to a new instance of ShoppingCartFacade.
You need to either:
Change ShoppingCartManagedBean to be #SessionScoped, or
Create an #SessionScoped facade which delegates to the ShoppingCartManagement reference and inject that in place of the EJB.
Either of these methods will associate your stateful session bean with the servlet/JSF session.
I do someexample from GWTP
http://blog.arcbees.com/2015/10/27/gwtp-beginners-tutorial-toaster-launcher-part-2/#Gatekeeper
#DefaultGatekeeper
public class LoggedInGatekeeper implements Gatekeeper {
private CurrentUser currentUser;
#Inject
public LoggedInGatekeeper(CurrentUser currentUser) {
this.currentUser = currentUser;
}
#Override
public boolean canReveal() {
return currentUser.isLoggedIn();
}
}
Here we give access if user is login.
Is it possible to find out which page (NameToken) wants to go by? And whether to give him a right, depending on the permissions
Sure, just inject a PlaceManager into your LoggedInGatekeeper and call getCurrentPlaceRequest and then compare it your NameToken. Something along these lines:
#DefaultGatekeeper
public class LoggedInGatekeeper implements Gatekeeper {
private CurrentUser currentUser;
private PlaceManager placeManager;
#Inject
public LoggedInGatekeeper(CurrentUser currentUser, PlaceManager placeManager) {
this.currentUser = currentUser;
this.placeManager = placeManager;
}
#Override
public boolean canReveal() {
PlaceRequest request = placeManager.getCurrentPlaceRequest();
if (request.hasSameNameToken('someNameToken') {
return currentUser.isLoggedIn();
}
return true;
}
}
Consider the following JMX code:
public class UserJMXBeanExpose {
private UserJMXBeanImpl userJMXBean;
#Required
public void setUserJMXBean(UserJMXBeanImpl userJMXBean) {
this.userJMXBean = userJMXBean;
}
public void init() throws MBeanRegistrationException, InstanceAlreadyExistsException, NotCompliantMBeanException, MalformedObjectNameException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("MineStar:type=UserJMXBeanExpose,name=Statistics");
MineStarMBean impl = new MineStarMBean();
impl.addProperty(new PropertyAdapter("User", "User List", "java.lang.String") {
public Object getValue() {
if (userJMXBean == null) return 0;
return userJMXBean.getUserAttributes();
}
});
server.registerMBean(impl, objectName);
}
}
And this code:
public class UserJMXBeanImpl implements UserJMXBean {
private List<User> userList = new ArrayList<>();
public void addUser(User user){
userList.add(user);
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public String[] getUserAttributes(){
for(User user : this.getUserList()){
return new String[]{user.getUserId(),user.getRoles()};
}
return null;
}
}
How can I add a listener to JMX so that it updates the values of getUserAttributes() with the newly added user by UserJMXBeanImpl class?
I need to update my jmx information when each new user is added to the impl class. Or how can we add listener so that it can notify the UserJMXBeanExpose to expose its data whenever a new user is added to impl class?
I made a DAO class with factory method and the specific DAO returns singleton, a single instance of the DAO. But I been tracing it and its being created but I try to call on it and it always null.
Just to explain the storage factory
I call on DAOFactory to get RAMDAOFactory to get to RAMUserDAO
If there is better way to handle RAM, Serialization and SQL type DAOs or CRUD please let me know.
class that I'm calling the storage from.
public class Registration
{
private UserDAO userStorage;
private static Logger log = LogClass.getLog();
Registration(DAOFactoryType typeDataStorage)
{
userStorage = DAOFactory.getDAOFactory(typeDataStorage).getUserDAO();
log.trace("insdie Reg");
}
void addUser(String userName, String password, UserType... args)
throws Exception
{
List<UserType> userTypes = new ArrayList<UserType>(args.length);
for (UserType userType : args)
{
log.trace("userType " + userType);
userTypes.add(userType);
}
User newUser = new DefaultUser(userName, password, userTypes);
log.trace("newUser " + newUser);
if (userStorage != null)
{
userStorage.insert(newUser);
}
else
{
log.trace("userStorage null");
}
}
}
This is my DAOFactory
public abstract class DAOFactory
{
private static Logger log = LogClass.getLog();
public abstract TradeDAO getTradeDAO();
public abstract UserDAO getUserDAO();
public abstract LogDAO getLogDAO();
public static DAOFactory getDAOFactory(DAOFactoryType factoryType)
{
switch (factoryType)
{
case SQL:
return new SQLDAOFactory();
case RAM:
log.trace("insdie RAM");
return new RAMDAOFactory();
case SERIAL:
return new SerialDAOFactory();
default:
return null;
}
}
}
RAMDAOFactory
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
private TradeDAO ramTradeDAO;
private UserDAO ramUserDAO;
private LogDAO ramLogDAO;
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
#Override
public TradeDAO getTradeDAO()
{
return ramTradeDAO;
}
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
#Override
public LogDAO getLogDAO()
{
return ramLogDAO;
}
}
This is my UserDAO
public class RAMUserDAO implements UserDAO
{
/*
* Map<Integer, List<byte[]>> userHash; List<byte[]> arrayHashSalt;
*/
private static RAMUserDAO userDAO = null;
private Map<String, User> userList;
private static Logger log = LogClass.getLog();
private RAMUserDAO()
{
userList = new HashMap<String, User>();
log.trace("insdie RAMUserDAO constructor");
}
public static RAMUserDAO getRAMUserDAO()
{
log.trace("insdie getRAMUserDAO");
if(userDAO == null) {
log.trace("insdie new RAMUserDAO()");
userDAO = new RAMUserDAO();
}
/*if (userDAO == null)
{
synchronized (RAMUserDAO.class)
{
if (userDAO == null)
{
userDAO = new RAMUserDAO();
}
}
}*/
return userDAO;
}
#Override
public void insert(User user) throws Exception
{
log.trace("insdie insert");
userList.put(user.getUserName(), user);
}
}
The oversight was in RAMDAOFactory and fix was:
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
#Override
public TradeDAO getTradeDAO()
{
return RAMTradeDAO.getRAMTradeDAO();
}
#Override
public UserDAO getUserDAO()
{
return RAMUserDAO.getRAMUserDAO();
}
#Override
public LogDAO getLogDAO()
{
return RAMLogDAO.getRAMLogDAO();
}
}
You've called the methods
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
but you haven't assigned their value to anything
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
Either always call
RAMUserDao.getRAMUserDAO();
when you want to return the UserDAO or assign it to ramUserDAO and return that.
Been stuck on a problem for a while now and searched every possible post but can't find why jersey is ignoring my security annotation?
Basically my Resource Config looks like so
#ApplicationPath("/*")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig()
{
packages("com.property");
register(org.springframework.web.context.request.RequestContextListener.class);
register(org.glassfish.jersey.servlet.ServletContainer.class);
register(org.glassfish.jersey.server.spring.SpringLifecycleListener.class);
register(org.glassfish.jersey.server.validation.ValidationFeature.class);
register(org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature.class);
}
}
My Secuirity Context is defined as so;
#Provider
public class Authorizer implements javax.ws.rs.core.SecurityContext {
private final Account account;
private final Session session;
private final Principal principal;
public Authorizer() {
super();
this.account = null;
this.session = null;
this.principal = null;
}
public Authorizer(Account account, Session session) {
this.account = account;
this.session = session;
this.principal = new Principal() {
public String getName() {
return account.getAlias();
}
};
}
#Override
public String getAuthenticationScheme() {
return Authorizer.BASIC_AUTH;
}
#Override
public Principal getUserPrincipal() {
return principal;
}
#Override
public boolean isSecure() {
//return "https".equals(uriInfo.get().getRequestUri().getScheme());
return true;
}
#Override
public boolean isUserInRole(String role) {
if ((role == null) || (session == null) || (!session.isValidSession()) || (this.session.getType() == null) || (account == null))
return false;
return this.session.getType().toString().equals(role);
}
}
Security Filter looks like so
#Provider
#PreMatching
public class SecurityFilter implements ContainerRequestFilter {
#Inject
javax.inject.Provider<UriInfo> uriInfo;
#Autowired
private HibernateSessionFacotry sessionFactory;
#Override
public void filter(ContainerRequestContext request) {
try
{
String sessionKey = request.getHeaderString("Authorization");
Integer uid = request.getHeaderString("From") == null ? null : Integer.parseInt(request.getHeaderString("From"));
if ((sessionKey == null) || (uid == null))
return;
Session session = null;
Account account = null;
session = sessionFactory.getSessionDAO().verifySession(uid, sessionKey);
if (session != null)
account = session.getAccount();
if (
(session != null)
&& (account != null)
&& (session.getSessionKey().equals(sessionKey))
&& (session.getAccountId() == uid)
&& (session.isValidSession())
)
request.setSecurityContext(new Authorizer(account, session));
else
request.setSecurityContext(new Authorizer());
}
catch (Exception ex)
{
//TODO:: ONLY PRINT IN DEBUG MODE
ex.printStackTrace();
return;
}
}
}
My Resources
#Path("/account")
public class AccountImpl implements Account{
#POST
#DenyAll
#Audit
#NotNull #ValidAccount
public com.property.db.entities.account.Account createAccount
(
#NotNull #ValidPostAccount final com.property.db.entities.account.Account account,
#Context HttpServletRequest request
) throws NoSuchAlgorithmException, MandrillApiError, IOException;
}
But for some reason the security annotation #DenyAll gets ignored and I get a 200 response. Any reason why this is happening as I am completely baffled right now.
EDIT::
Just noticed that the security annotation are only ignored from my grizzly servlet any idea why this is happening?
public class WebTest extends JerseyTest {
protected static SimpleDateFormat sdf = null;
protected static GensonProvider gesonProvider = null;
protected static HibernateSessionFacotry sessionFactory = null;
#Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return new ApplicationResourceConfig();
}
#Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new TestContainerFactory() {
#Override
public TestContainer create(final URI baseUri, ApplicationHandler application)
throws IllegalArgumentException {
return new TestContainer() {
private HttpServer server;
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return baseUri;
}
#Override
public void start() {
try {
this.server =
GrizzlyWebContainerFactory.create(baseUri);
WebappContext context = new WebappContext("WebappContext", "");
context.addContextInitParameter("contextConfigLocation", "classpath:applicationContext.xml");
context.addListener(org.springframework.web.context.ContextLoaderListener.class);
ServletRegistration registration = context.addServlet("ServletContainer", org.glassfish.jersey.servlet.ServletContainer.class);
registration.addMapping("/*");
registration.setInitParameter("jersey.config.server.provider.packages", "com.property.filters.auditing;com.property.filters.security;com.property.filters.versioning;com.property.resources");
registration.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
context.deploy(server);
} catch (ProcessingException e) {
throw new TestContainerException(e);
} catch (IOException e) {
throw new TestContainerException(e);
}
}
#Override
public void stop() {
this.server.stop();
}
};
}
};
}
public void setUp() throws Exception {
super.setUp();
sdf = new SimpleDateFormat("dd/MM/yyyy");
assertNotNull(sdf);
gesonProvider = new GensonProvider();
assertNotNull(gesonProvider);
sessionFactory = new HibernateSessionFacotry();
assertNotNull(sessionFactory);
}
public void tearDown() throws Exception {
super.tearDown();
}
}