Basically I was trying to unit test on #Secured feature in my application. Below is the code snippet on the secure implementation:
#Service
public class ReportService {
#Secured(value={"ROLE_EMPLOYEE_A"})
public void funcA() {
System.out.println("This only accessible for Employee A.");
}
}
Now I have a series of Employee users define in Spring Security just for my unit test purpose:
<security:global-method-security secured-annotations="enabled"/>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="plaintext"/>
<security:user-service>
<security:user name="empl1" password="pass1" authorities="ROLE_EMPLOYEE_A" />
<security:user name="empl2" password="pass2" authorities="ROLE_EMPLOYEE_B" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
In my unit test code, I have the following being define:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:applicationcontext.xml",
"classpath:securitycontext.xml"
})
public class ReportServiceTest {
#Autowired
private ReportService reportService;
#Test(expected = AccessDeniedException.class)
public void testA() {
assertNotNull(userService);
UserDetails ud = userService.loadUserByUsername("empl2");
assertNotNull(ud);
Authentication auth = new UsernamePasswordAuthenticationToken(ud.getUsername(), ud.getPassword(), ud.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
reportService.funcA();
}
In this test, I am expecting AccessDeniedException being thrown, but somehow the test were pass and "This only accessible for Employee A." were printed in console output. I'm sure the real execution is working fine, but I'm so curious to know why it doesn't work in unit test?
Related
I am using Asp.Net MVC 5 and am trying to wire up my dependencies for a web api controller but it doesnt work and says the controller needs a parameter less constructor.
I have updated unity container to v4 which meant updating some other references, namely unity.abstractions is also v4.
I am using unity.mvc not unity.mvc5.
In UnityConfig I have
public static class UnityConfig
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(InitialiseContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static IUnityContainer ConfiguredContainer()
{
return Container.Value;
}
private static IUnityContainer InitialiseContainer()
{
var container = new UnityContainer();
//DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
//GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
// Auth
container.RegisterType<IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType<ApplicationUserManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()));
container.RegisterType<IUserStore<LiApplicationUser>> (new InjectionFactory(c => new UserStore<LiApplicationUser>(new ApplicationIdentityDbContext())));
// Repository
container.RegisterType<LeisureInsureEntities>(new InjectionFactory(c => ContextFactory.Context()));
container.RegisterType<ICar, Volvo>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
}
I commented out the unity.mvc5 code is no longer needed, so its removed. That seemed to require unity.abstractions v2, and doesn't accept 4.
As I am trying to inject into a webapi controller do I also need Unity.WebAPI? that gives the same problem as Unity.Mvc5 and is developed by the same person, ie it doesnt like my later version of unity.abstractions.
In my webapi controller I am seeing if I can wire up Volvo as a test
public class StripeController : ApiController
{
private readonly IEndpointInstance _endpoint;
private readonly ICar car;
//public StripeController(IEndpointInstance endpoint)
//{
// _endpoint = endpoint;
//}
public StripeController(ICar newcar)
{
car = newcar;
}
Thanks
You will need the Unity.AspNet.WebApi adapter to configure your ApiControllers.
Careful you don't mix up packages. Some of those are not by the same project owner (Unity.Mvc5, Unity.WebAPI). I haven't used those so I can't comment on its suitability.
I have a example https://github.com/jasenhk/MovieStar from another answer that uses Unity v5.10 and Unity.MVC as well as Unity.AspNet.WebApi.
Here is the packages.config
<package id="Unity" version="5.10.2" targetFramework="net461" />
<package id="Unity.Abstractions" version="4.1.2" targetFramework="net461" />
<package id="Unity.AspNet.WebApi" version="5.10.0" targetFramework="net461" />
<package id="Unity.Container" version="5.10.2" targetFramework="net461" />
<package id="Unity.Mvc" version="5.10.0" targetFramework="net461" />
I have the following account controller
public class AccountController : Controller
{
public IMembershipService MembershipService { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
}
public AccountController(IMembershipService membership)
{
MembershipService = membership;
}
[HttpPost]
public ActionResult Login(LoginModel model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.EmailorUserName, model.Password))
{
.....
}
}
}
from my unit testing project I want to simulate a login
public class AccountControllerTest2
{
[Test]
public void Login_UserCanLogin()
{
string returnUrl = "/Home/Index";
string userName = "user1";
string password = "password1";
Mock<AccountMembershipService> Membership = new Mock<AccountMembershipService>();
AccountController Controller = new AccountController(Membership.Object);
var model = new LoginModel
{
EmailorUserName = userName,
Password = password
};
var result = Controller.Login(model, returnUrl) as RedirectResult;
Assert.NotNull(result);
Assert.AreEqual(returnUrl, result.Url);
}
}
my web config in my main application uses custommembership provider
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear />
<add name="CustomMembershipProvider" type="QUBBasketballMVC.Infrastructure.CustomMembershipProvider" connectionStringName="UsersContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
I keep getting this error
QUBBasketballMVC.Tests.Controllers.AccountControllerTest.Login_UserCanLogin:
System.Web.Management.SqlExecutionException : An error occurred during the execution of the SQL file 'InstallCommon.sql'. The SQL error number is 5123 and the SqlException message is: CREATE FILE encountered operating system error 5(Access is denied.) while attempting to open or create the physical file 'C:\PROGRAM FILES (X86)\NUNIT 2.6.3\BIN\APP_DATA\ASPNETDB_TMP.MDF'.
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
Creating the ASPNETDB_7b94db5a0b5b4fbbbe22fa8e91e4cc68 database...
It seems that you are still initializing the real membership database, meaning that the MembershipService hasn't been completely mocked out. You shouldn't need to add the membership config to your unit tests, given that you intend mocking it out completely.
You almost certainly want to mock the Interface to your service abstraction IMembershipService, viz:
Mock<IMembershipService> Membership = new Mock<IMembershipService>();
As an aside, the lazy initialization code
if (MembershipService == null)
MembershipService = new AccountMembershipService();
isn't ideal from a testing point of view, given that it means that the controller has 2 modes of operation, whereby it can either create the MembershipService itself, or accept one as a constructor dependency.
As an alternative, you might consider an IoC framework here to manage dependency lifespans, and this way there is only one set of code to be tested.
I wonder if i can replace "success" with a Constants value from a JSF library.
Backing Bean Method:
#Override
public String save() {
LOG.info("Called");
return "success";
}
For your issue, you'll find Omnifaces' <o:importConstants /> so useful (that's what I use in my own projects). That way you can import your constants file in your JSF page (I use my master page template for that).
<o:importConstants
type="com.mycompany.NavigationResults" />
This way you can access your NavigationResults values both from Java code and JSF tags (EL scope).
public abstract class NavigationResults {
public static final String SUCCESS = "success";
public static final String HOME = "home";
}
Use it in your managed beans:
public String save() {
LOG.info("Called");
return NavigationResults.SUCCESS;
}
In your buttons or links:
<h:button value="Go home" outcome="#{NavigationResults.HOME}" />
According to this article description custom-membership-provider-with-repository-injection
I implement the custom Membership provide with inject.
Custom Membership provider
using Ninject;
public class CustomMembershipProvider : MembershipProvider
{
[Inject]
public IUserRepository UserRepository { get; set; }
[...]
Custom Role Provider
using Ninject;
public class CustomRoleProvider : RoleProvider
{
[Inject]
public IUserRoleRepository UserRoleRepository { get; set; }
[...]
within Web.Config
<membership defaultProvider="CustomsMembershipProvider">
<providers>
<clear/>
<add name="CustomsMembershipProvider" type="namespace.CustomsMembershipProvider"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="customRoleProvider">
<providers>
<clear/>
<add name="customRoleProvider" type="namespace.customRoleProvider"/>
</providers>
</roleManager>
Now within NinjectWebCommon
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
[...]
kernel.Bind<IUserRepository>().To<UserRepository>();
kernel.Bind<IUserRoleRepository>().To<UserRoleRepository>();
// Inject user & role repository into our custom membership & role providers.
kernel.Inject(Membership.Provider);
kernel.Inject(Roles.Provider);
}
when I run application I got error
This method cannot be called during the application's pre-start
initialization stage.
from kernel.Inject(Membership.Provider); this line
But If I Kernel setting put within Application_Start
I got bellow Error
Error activating IUserRepository No matching bindings are available,
and the type is not self-bindable. Activation path: 2) Injection of
dependency IUserRepository into property UserRepository of type
CustomMembershipProvider 1) Request for CustomeMembershipProvider
How to solve that. ??
The result is always null. why? because asp.net has it's own static property for membership.
which is membership.provider. and this instance is not part of instance ninject management.
to workaround it , you need to use kernel.inject . but on the generate aspnetmvc.cs you would see that it's injection on PreApplicationStart event and won't let you.
here is the soloution by cipto that solve the problem for me. add this to your NinjectWebCommon
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
}
Link to article: Ninject and customMembership asp.net mvc 3
I had a lot of trouble trying this and ended up adding a method that gets me a repository
using System.Web.Mvc; //Used to access dependency resolver
private IUserRepository GetUserRepository()
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
I then call this in the methods that require it
I was able to get the repository to become injected using constructor injection but as soon as I went to use the repository the object had been disposed. I found the above to be the simplest alternative.
However, I guess you could also use the Initialize() method
IUserRepository userRepository;
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
this.userRepository = DependencyResolver.Current.GetService<IUserRepository>();
}
Or another way would be to use a property
public IUserRepository UserRepository
{
get
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
}
Since a custom RoleProvider often comes along with the custom MembershipProvider, in that case it is useful to add an injection for the Role Provider class. I used the ramon22's solution with an additional line.
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
bootstrapper.Kernel.Inject(Roles.Provider);
}
I have already one session scoped CDI bean, which keeps currently logged in user data.
Now, from another, request scoped I would like to access to this bean to get some data. I have some operation to do, which is dependent on user login. That's the only information I need.
How to access it?
AccountBean.java:
#Named("accountBean")
#SessionScoped
public class AccountBean implements Serializable {
private static final long serialVersionUID = 16472027766900196L;
#Inject
AccountService accountService;
private String login;
private String password;
// getters and setters ommited
}
Part of login.xhtml:
<h:form>
<h:panelGrid columns="2">
#{msgs.loginPrompt}
<h:inputText id="login" value="#{accountBean.login}" />
#{msgs.passwordPrompt}
<h:inputSecret id="password" value="#{accountBean.password}" />
<h:commandButton value="#{msgs.loginButtonText}"
action="#{accountBean.login}" />
</h:panelGrid>
</h:form>
SearchBean.java:
#Named("searchBean")
#RequestScoped
public class SearchBean {
#Inject AccountBean accountBean;
// some other stuff
}
Just #Inject it.
#Inject
private Bean bean;
Note that this isn't available in the constructor of the receiving bean (it's not possible to inject something in an unconstructed instance, you see). The earliest access point is a #PostConstruct method.
#PostConstruct
public void init() {
bean.doSomething();
}