Grails Spring Security get assigned roles to a method - security

I would like to have a test that goes through all methods available in a controller and retrieves roles associated with these methods. I understand that it should be a functional test (as opposed to a unit test), but I still do not know how to request the list of roles associated with a method.
Let's say I have this controller:
#Secured("hasAnyRole('ROLE_1')"
class MyController {
def methodA() {}
#Secured("hasAnyRole('ROLE_2')"
def methodB() {}
}
In my test I would like to have something like this:
assertEquals(['ROLE_1'],getRoles(MyController.class, "methodA"))
assertEquals(['ROLE_1', 'ROLE_2'],getRoles(MyController.class, "methodB"))
Any suggestions?
Thanks.

You can do this with the Reflection API. Something like:
Method m = MyController.class.getMethod("methodB");
Annotation[] annos = m.getAnnotations();
But I don't think that's a good validation for your method, since it only ensure that you write the role name correctly. I think it's better you try to call the action and check if the process redirect to denied.
#TestFor(MyController)
class MyControllerTests {
#Test
void shouldRedirectToDenied() {
SpringSecurityUtils.doWithAuth('username') {
controller.methodB()
assert controller.response.redirectedUrl == '/login/denied'
}
}
}
The doWithAuth closure will mock an authentication for the username, so it's the same to say: "do this code as if the username was logged in successfully".
It seems that you will need to use functional tests indeed. See Burt's comment. I'm still think that's not a valid effort create a test only to validate if the method have the annotation.

Related

How to decorate the final class DocumentGenerator

I am having problems to decorate the final class "DocumentGenerator" (in vendor/shopware/core/Checkout/Document/Service/DocumentGenerator.php) and overwrite the "generate" function inside of it.
I tried to decorate it the usual way, but an error is thrown because the "DocumentController" class excepts the original class and not my decorated one?
Argument 2 passed to Shopware\Core\Checkout\Document\DocumentGeneratorController::__construct() must be an instance of Shopware\Core\Checkout\Document\Service\DocumentGenerator
Its also not possible to extend from the class in my decorated class, because the "DocumentGenerator" is a final class.
My goal is to execute additional code, after an order document is generated. Previously I successfully used to decorate the "DocumentService" Class, but its marked as deprecated and shouldnt be used anymore. Also the "DocumentGenerator" class is used for the new "bulkedit" function for documents as of Version 6.4.14.0
I'm grateful for every tip.
As #j_elfering already wrote it's by design that you should not extend that class and therefore also shouldn't decorate it.
To offer a potential alternative:
Depending on what you want to do after a document has been generated it might be enough to add a subscriber to listen to document.written, check if it was a new document created and then work with the data from the payload for fetching/persisting data depending on that.
public static function getSubscribedEvents()
{
return [
'document.written' => 'onDocumentWritten',
];
}
public function onDocumentWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if ($result->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
// skip if the it's not a new document created
continue;
}
$payload = $result->getPayload();
// do something with the payload
}
}
Probably not what you want to hear but: The service is final in purpose as it is not intended to be decorated.
So the simple answer is you can't. Depending on your use case there may be other ways that don't rely on decoration.

Mockito how can simule record doesn't exist

.exception.INSSTaxNotFoundException: INSS Tax not found with ID 1
Could someone help me?
I want mokite "inssTaxService.findById", I don't know how do.
I get this error: INSSTaxNotFoundException: INSS Tax not found with ID 1.
But I could like found the record and go on.
Can I do that in Service or Not?
#Test
void whenINSSTaxIdInformedThenReturnThisINSSTax() throws INSSTaxNotFoundException {
INSSTaxDTO expectedSavedInssTaxDTO = INSSTaxBuilder.builder().build().toINSSTaxDTO();
INSSTax expectedSavedInssTax = inssTaxMapper.toModel(expectedSavedInssTaxDTO);
when(inssTaxService.findById(expectedSavedInssTaxDTO.getId())).
thenReturn(expectedSavedInssTaxDTO);
assertEquals(expectedSavedInssTax.getId(), expectedSavedInssTaxDTO.getId());
assertEquals(expectedSavedInssTax.getDescription(), expectedSavedInssTaxDTO.getDescription());
assertEquals(expectedSavedInssTax.getSocialSecurityRatePercent(), expectedSavedInssTaxDTO.getSocialSecurityRatePercent());
}
What you might be missing is actually injecting the mock of inssTaxService inside your class which you are testing,
Your code would be something like this. Considering its a pure java code(not spring boot etc, you can change the code accordingly in that case).
Mock the service(Which i feel you have done else Mockito would have thrown and error)
InssTaxService mockedInssTaxService = Mockito.mock(InssTaxService.class);
//other impl on this mock for this e.g
when(mockedInssTaxService.findById(expectedSavedInssTaxDTO.getId())).
thenReturn(expectedSavedInssTaxDTO);
Inject the mocked object to the ClassToTest.
ClassToTest classToTest = new ClassToTest(mockedInssTaxService);
If you are using spring boot test you can use #MockBean or #Mock and #InjectMocks instead of new keyword

Defining Spock mock behaviors

I am writing my first Spock test and read the docs on mocking interactions, but am still not seeing the "forest through the trees" on a few items.
I have a class, MyRealm, that performs authentication for my app. It has two dependencies, AuthService and ShiroAdapter. The former I'd like to mock and the latter I want to leave as-is (if at all possible). This is because the AuthService actually makes a backend connection to LDAP, so I want to mock it. But the ShiroAdapter just defines several utility methods that convert my objects into Apache Shiro security objects (principals, permissions, etc.). So it can be left un-mocked (methinks).
class MyRealmSpec extends Specification {
MyRealm realm
def setup() {
AuthService authService = Mock(AuthService)
// configure 'authService' mock <-- ?????
ShiroAdapter shiroAdapter = new ShiroAdapter()
realm = new MyRealm(authService: authService,
shiroAdapter: shiroAdapter)
}
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
Throwable throwable = thrown()
ShiroException.isAssignableFrom(throwable)
}
}
I believe I'm very close, but am struggling to configure the mock to behave the way I want it to for the test. The Spock docs (linked above) only seem to document how to verify the number of times a mock method is called. I'm not interested in that here.
Here, MyRealm#authenticate(String,String) calls AuthService#doAuth(String,String) under the hood. So I need my mock AuthService instance to simply either return false (indicating failed auth) or to throw an ServiceFaulException if something unexpected happened.
Any ideas how I can accomplish this?
You are very close, an easy, short-hand way to check a thrown exception type is to put the Exception class in parenthesis. Ex:
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
thrown(ShiroException)
}
You also need to mock the LDAP service call itself and simulate an exception or a failed login. The mock operations go in the then clause of your test.
def "authenticate throws ShiroException whenever auth fails"() {
setup:
String invalidUserName = 'invalid_username'
String invalidPassword = 'invalid_password'
when:
realm.authenticate(invalidUserName, invalidPassword)
then:
1 * authService.doAuth(invalidUserName, invalidPassword) >> returnClosure
thrown(ShiroException)
where:
returnClosure << [{throw new ShiroException()}, { false }]
}
Note that you will need to have the arguments on the mock statements match or use wild card matching.
To match on any String you can use the underscore syntax:
1 * authService.doAuth(_, _) >> false
There are a few different behavior objects you might be interested in.
Stub - You only define what gets returned
MyObject obj = Stub{method >> null}
Mocks - You define what gets returned and/or how many times a method is called
MyObject obj = Mock {1..3 methodCall >> false}
Spies - It creates your object but you can override specific methods as a mock (and your overrides can still make calls to the original code)
MyObject obj = Spy {methodCall >> false}
obj.otherMethodCall() // Calls code like normal
obj.methodCall() // Returns false like we told it to
It sounds like you need a stub, but you could use a mock without any issue. I mention spy, because it's a life-saver if your object ever is self dependent (in the future).
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> expectedError
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
when:
realm.authenticate("just enough to get", "to the doAuth method")
then:
thrown(ShiroException)
where:
expectedError << [ShiroException, /*other exceptions this method has to test*/]
}
The data/logic separation isn't needed, but it's a good approach for making tests more flexible and maintainable. Although in this case it's not really needed since you only have one exception to throw.
I would actually separate your failed authentication and exception-ed authentication tests. They're looking at fundamentally different behaviors and the test logic to test both situations is somewhat different. In the interest of maintainability/flexibility, it's in your interest to avoid testing too much (or too little) with each test.
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> { args ->
return args[0] == good && args[1] == good
}
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
expect:
realm.authenticate(username, password) == expectedAuthentication
where:
userName | password | expectedAuthentication
bad | good | false
bad | bad | false
good | good | true
}
Note on the above test, this tests...
The mock's computation for a return value (testing the test)
Any code that happens between calling authenticate and doAuth()
Hopefully that's what you intend. If there's nothing in .authenticate()'s logic that could break (it has complexity on par with a getter or setter method), this test is mostly a waste of time. The only way that logic could break is if something went wrong in the JVM (which is completely outside the responsibility of this test), or someone made a change sometime in the future (ok, even under the huge assumption that .authenticate() contains unbreakably basic logic the test has some value). My rambling off-topic point (terribly sorry); make sure to keep the what & why of your tests in mind. It will help you prioritize test cases and while working out the best ways to organize/separate test logic.

Use 'owner' property in Groovy DSL

Let's consider a simple Groovy DSL
execute {
sendNotification owner
sendNotification payee
}
The implementation of execute is
public static void execute(Closure dslCode) {
Closure clonedCode = dslCode.clone()
def dslDelegate = new MyDslDelegate(owner: 'IncCorp', payee: 'TheBoss')
clonedCode.delegate = dslDelegate
clonedCode.call()
}
and custom Delegate is
public static class MyDslDelegate {
def owner
def payee
void sendNotification(to) {
println "Notification sent to $to"
}
}
The expected result of running execute block is
Notification sent to IncCorp
Notification sent to TheBoss
the actual one is
Notification sent to class package.OwnerClassName
Notification sent to TheBoss
The problem is owner is a reserved property in the Groovy Closure itself and no resolveStrategy options help to replace owner value with custom value from delegate due to Groovy getProperty implementation for Closure
public Object getProperty(final String property) {
if ("delegate".equals(property)) {
return getDelegate();
} else if ("owner".equals(property)) {
return getOwner();
...
} else {
switch(resolveStrategy) {
case DELEGATE_FIRST:
...
}
My question is how some one can outcome this limitation and use owner property name in a custom DSL?
This is a bit of a hack, but this should get you what you want, without altering Groovy source:
public static void execute(Closure dslCode) {
Closure clonedCode = dslCode.clone()
def dslDelegate = new MyDslDelegate(owner: 'IncCorp', payee: 'TheBoss')
clonedCode.#owner = dslDelegate.owner
clonedCode.resolveStrategy = Closure.DELEGATE_ONLY
clonedCode.delegate = dslDelegate
clonedCode.call()
}
Ref: Is it possible to change the owner of a closure?
The simple answer is no, you can't. 'owner' is a reserved keyword in Groovy, and therefore by definition cannot be used as an arbitrary symbol. Even if there is a way to hack around this, you're far better off just using a name that doesn't conflict with the implementation of the language- this is especially true in Groovy, which keeps promising to redesign its MOP completely, meaning that any hack you implement may well stop working in future versions.
Perhaps the question would make more sense if you explained why you are willing to offer a bounty and search for a way of hacking around this problem, rather than just changing the name to something different and avoiding the problem entirely. Reserved symbols are a pretty fundamental limitation of a language, and ever attempting to work around them seems very unwise.

How can I intercept execution of all the methods in a Java application using Groovy?

Is it possible to intercept all the methods called in a application? I'd like to do something with them, and then let them execute. I tried to override this behaviour in Object.metaClass.invokeMethod, but it doesn't seem to work.
Is this doable?
Have you looked at Groovy AOP? There's very little documentation, but it allows you to define pointcuts and advice in a conceptually similar way as for AspectJ. Have a look at the unit tests for some more examples
The example below will match all calls to all woven types and apply the advice before proceeding:
// aspect MyAspect
class MyAspect {
static aspect = {
//match all calls to all calls to all types in all packages
def pc = pcall("*.*.*")
//apply around advice to the matched calls
around(pc) { ctx ->
println ctx.args[0]
println ctx.args.length
return proceed(ctx.args)
}
}
}
// class T
class T {
def test() {
println "hello"
}
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class
First of all, overriding Object.metaClass.invokeMethod doesn't work because when Groovy tries to resolve a method call for a type X, it checks the metaClass of X, but not the metaClass of its parent class(es). For example, the following code will print "method intValue intercepted"
Integer.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Integer.metaClass = null
But this code will not:
Object.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Object.metaClass = null
Your question was "Is it possible to intercept all the methods called in a application?", but could you be a bit more precise about whether you want to:
Intercept calls to Groovy methods, Java methods, or both
Intercept calls to only your Groovy/Java methods or also intercept calls to Groovy/Java library classes
For example, if you only want to intercept calls to your Groovy classes, you could change your classes to implement GroovyInterceptable. This ensures that invokeMethod() is invoked for every method called on those classes. If the nature of the interception (i.e. the stuff you want to do before/after invoking the called method) is the same for all classes, you could define invokeMethod() in a separate class and use #Mixin to apply it to all your classes.
Alternatively, if you also want to intercept calls to Java classes, you should check out the DelegatingMetaClass.

Resources