I am trying to override default sendredirect funtionality in AEM.
I would like to redirect to https urls from my server.
FOr the same I have implemented a sling filter. Implemented SlingHttpServletResponseWrapper class and overridden sendredirect function.
However, in filter when I try to
final SlingHttpServletResponse slingResponse = (ModifyLocResponse) response;
At runtime I get
org.apache.sling.security.impl.ContentDispositionFilter$RewriterResponse cannot be cast to com.adobe.acs.samples.filters.wrappers.ModifyLocResponse
Instead of casting, try instantiating it by something like this:
final SlingHttpServletResponse slingResponse = new ModifyLocResponse(response);
Of course you'll need to make sure the constructor for that class has this pattern too:
class ModifyLocResponse extends SlingHttpServletResponseWrapper {
public ModifyLocResponse(SlingHttpServletResponse response) {
super(response);
}
...
}
Related
I'm new to spring graphql and I was trying to implement my own DataFetcherExceptionHandler so I can wrap all exceptions with my custom one.
I've implemented my custom class that implements DataFetcherExceptionHandler but it seems like it still uses the default one, the SimpleDataFetcherExceptionHandler.
How can I make my custom DataFetcherExceptionHandler the default one for the graphql exceptions?
My class:
#Slf4j
#AllArgsConstructor
#Component
public class GraphqlExceptionHandler implements DataFetcherExceptionHandler {
public DataFetcherExceptionHandlerResult onException(DataFetcherExceptionHandlerParameters handlerParameters) {
Throwable exception = handlerParameters.getException();
SourceLocation sourceLocation = handlerParameters.getSourceLocation();
ResultPath path = handlerParameters.getPath();
MyCustomException error = exposedException(exception, sourceLocation, path);
return DataFetcherExceptionHandlerResult.newResult().error(error).build();
}
#Override
public CompletableFuture<DataFetcherExceptionHandlerResult> handleException(DataFetcherExceptionHandlerParameters handlerParameters) {
return CompletableFuture.completedFuture(this.onException(handlerParameters));
}
Note: I'm not sure if I can use my custom exception like that, but I'm not able to test it while I can't make the exception handler the default one.
With Spring for GraphQL you can implement a DataFetcherExceptionResolver or more specifically a DataFetcherExceptionResolverAdapter that you can for example annotate with #Component to register it automatically.
The DataFetcherExceptionHandler from graphql-java is used by Spring for GraphQL internally to delegate to your DataFetcherExceptionResolver classes.
Inside your own DataFetcherExceptionResolverAdapter, you can get the informations that are available as DataFetcherExceptionHandlerParameters (Path, SourceLocation and so on) in a DataFetcherExceptionHandler from the DataFetchingEnvironment that is passed to DataFetcherExceptionResolverAdapter resolveToSingleError and resolveToMultipleErrors methods.
See here for more informations: https://docs.spring.io/spring-graphql/docs/current/reference/html/#execution-exceptions
You can find an example implementation here: https://github.com/nilshartmann/spring-graphql-training/blob/main/app/publy-backend/src/main/java/nh/publy/backend/graphql/runtime/PublyGraphQLExceptionResolver.java
Is there a way to add validation to feign clients on the request parameters.
For example:
#FeignClient
public interface ZipCodeClient {
#GetMapping("/zipcodes/{zipCode}")
Optional<ZipCodeView> findByZipCode(#PathVariable("zipCode") String zipCode);
}
It would be nice to verify that zipcode is not empty and is of certain length etc, before sending the HTTP call to the server.
If your validations are simple, apply to only headers and query string parameters, you can use a RequestInterceptor for this, as it provides you the opportunity to review the RequestTemplate before it is sent to the Client.
public class ValidatingRequestInterceptor implements RequestInterceptor {
public void apply(RequestTemplate requestTemplate) {
// use the methods on the request template to check the query and values.
// throw an exception if the request is not valid.
}
}
If you need to validate the request body, you can use a custom Encoder
public class ValidatingEncoder implements Encoder {
public void encode(Object object, Type type, RequestTemplate template) {
// validate the object
// throw an exception if the request is not valid.
}
}
Lastly, if you want to validate individual parameters, you can provide a custom Expander for the parameter and validate it there. You can look at this answer for a complete explanation on how to create a custom expander that can work with Spring Cloud.
How to custom #FeignClient Expander to convert param?
For completeness, I've included an example for how to do this with vanilla Feign.
public class ZipCodeExpander implements Expander {
public String expand(Object value) {
// validate the object
// throw an exception if the request is not valid.
}
}
public interface ZipCodeClient {
#RequestLine("GET /zipcodes/{zipCode}")
Optional<ZipCodeView> findByZipCode(#Param(expander = ZipCodeExpander.class) ("zipCode") String zipCode);
}
As pointed out in this comment, a solution using the Bean Validation API would be nice. And indeed, I found in a Spring Boot project that merely placing #org.springframework.validation.annotation.Validated on the interface is sufficient for enabling Bean Validation.
So for example:
#FeignClient
#Validated
public interface ZipCodeClient {
#GetMapping("/zipcodes/{zipCode}")
Optional<ZipCodeView> findByZipCode(#PathVariable("zipCode") #NotEmpty String zipCode);
}
triggering a ConstraintViolationException in the case of violations.
Any standard Bean Validation feature should work here.
UDPATE Note that there seems to be a potential issue with this solution that might require setting a Hibernate Validator configuration property like this: hibernate.validator.allow_parallel_method_parameter_constraint=true
Actually my code look like that:
#PreAuthorize("hasAuthority('admin')")
#RequestMapping(value = "/xxxx", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<> method(#RequestBody RequestClass request) {
}
As you can see the allowed authorities are hard-coded in java code.
Is there a way to override the behaviour of PreAuthorize or to load the proper endpoint configuration at startup from an external source(database or configuration file)?
I suppose you might give something like this a try (might need some tweaking) but it's ugly and I would not do it myself...
Setup your method to role mappings in your configuration. For example:
permissions.method1: admin
permissions.method2: admin
permissions.method3: user
Then use an #ConfigurationProperties class to load in your map into a Map.
#ConfigurationProperties("")
public class SecurityMappingProperties {
private final Map<String, String> permissions = new HashMap<>();
public Map<String, String> getPermissions() {
return permissions;
}
}
Then setup a service to handle the lookup.
#Service
public class MethodPermissionService {
#Autowired
private SecurityMappingProperties mappingProperties;
//lookup the mapped role and see if you user has it..
public Boolean lookupPermissionForMethod(String method){
return doesUserHaveRole(mappingProperties.get(method));
}
private Boolean doesUserHaveRole(String role){
//implement whatever logic you want to look up the requesting user's role...
}
}
Then in your controllers, invoke the methodPermissionService and pass in the method name, like so...
#PreAuthorize("#methodPermissionService('method1')")
This, of course, would require you to have every secured method in all of your controllers to have an #Preauthorize with the matching method name as the argument to the methodPermissionService('xxx').
Since we are already in this rabbit hole, if you really wanted to, you could also just have a single place to declare all of them in some sort of MethodRoleHolder class where you can make them static Strings like the following:
public static final String METHOD1_SECURITY = "#methodPermissionService('method1')";
public static final String METHOD2_SECURITY = "#methodPermissionService('method2')";
then use them in your controllers...
#PreAuthorize(MethodRoleHolder.METHOD1_SECURITY)
Upfront caveat: I haven't actually tried this myself exactly as I laid out here but I have implemented a security scheme similar to this, just without the dynamic role mapping look up part.
This feels like it should be a simple thing, but I'm still pretty new to SpringBoot, and the whole Servlet ecosystem, so it's not readily apparent. I would love an interface similar to HandlerInterceptor that allows me to modify the request and response object once I'm done in a controller. Even better would be to decorate mapping annotation, so I can specify which controllers need the operation.
The problem I'm solving right now, though I anticipate expanding this in the future, is that I have an encrypted header coming into my application that I would like to decrypt for use in the controller and then encrypt again on the way out.
EDIT: For clarity.
I have a rest controller, something like:
#RestController
public class PojoService {
#GetMapping(value = "/path/to/resource")
public ResponseEntity<SomeClass> getLocationData(
#RequestHeader(value = "EncryptedHeader", required = false) String ecryptedHeaderValue) {
DecryptionObject decryptedHeader = new DecryptionObject(pageHeaderValue);
SomePojo result = getResult();
return decryptedHeader.decorateResponseWithEncryptedHeader(result);
}
}
I would love to not have the DecryptionObject on every mapping, but rather, before I even get to the mapping, I decrypt the header via some filter or hook and then re-encrypt the header on the way out. Then my code would look something like:
#RestController
public class PojoService {
#GetMapping(value = "/path/to/resource", decryptHeader="EncryptedHeader")
public ResponseEntity<SomeClass> getLocationData(
#RequestHeader(value = "EncryptedHeader", required = false) String decryptedHeaderValue) {
SomePojo result = getResult();
return result;
}
}
I found that the HandlerInterceptor doesn't work because I cannot modify the request or response in the interceptor. Hope that clarifies the issue.
You can still use HandlerInterceptor. Create your class implementing HandlerInterceptor, and then register it using another class which extends WebMvcConfigurer.
#EnableWebMvc
#Configuration
#ComponentScan
public class MyWebConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new [...]); //Apply to all controllers
registry.addInterceptor(new [...]).addPathPatterns("path1","path2"); //Apply to specific paths to restrict to some controllers.
}
}
You also could do it using a Filter - create your Filter class and register it by declaring a #Bean of type FilterRegistrationBean - this also allows you to restrict to some paths.
UPDATE: You could do this with request attributes which can be set by interceptors (request.setAttribute("decryptedHeaderValue",<decrypted>). Or if you're specific about using headers, a filter would be more suitable for your purpose. Create a new wrapped request type that wraps the incoming request and does whatever you want, and pass this wrapper to the next filter in chain.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
[...]
HttpServletRequestWrapper decryptedRequest = new HttpServletRequestWrapper((HttpServletRequest) request) {
public String getHeader(String name) {
if (name.equals("DecryptedHeader")) {
String encrypted = super.getHeader("EncryptedHeader");
String decrypted = decrypt(encrypted);
return decrypted;
}
return super.getHeader(name); //Default behavior
}
}
chain.doFilter(decryptedRequest, response); //Pass on the custom request down
}
Then any class down the line (other filters, controllers etc) can just call request.getHeader("DecryptedHeader") to retrieve the decrypted header. This is just one of many similar approaches. You can restrict the paths for which this filter executes when registering it.
For response, there is a similar class HttpServletResponseWrapper which you can use for customization.
We can do this via addingAttribute in the interceptor
httpServletRequest.setAttribute(,);
When using #before, it is only used in one class. How do I apply a global filter in playframework? So that one filter is used for all controller classes.
A simple solution is to extend a base controller for all of your controllers and have the #Before in the base controller.
The other option (and the better solution, as it is more flexible) is to use the #With annotation. The example on the play documentation is
Example:
public class Secure extends Controller {
#Before
static void checkAuthenticated() {
if(!session.containsKey("user")) {
unAuthorized();
}
}
}
And on another Controller:
#With(Secure.class)
public class Admin extends Application {
...
}
This means the Admin controller will process all the interceptors (#Before, #After, #Finally) contained within the Secure controller.
I did this very thing by handling incoming requests globally in the GlobalSettings class:
This describes the class:
http://www.playframework.org/documentation/2.0/JavaGlobal
This describes the method you'd want to override.
http://www.playframework.org/documentation/2.0/JavaInterceptors
Here's an example of how I used it in my own project (of course, this is a simplified version of what you're looking for):
#Override
public play.mvc.Action onRequest(play.mvc.Http.Request request, java.lang.reflect.Method method) {
if (request.path().startsWith("/secret/locked")) {
return new Action.Simple() {
#Override
public Result call(play.mvc.Http.Context ctx) throws Throwable {
return redirect(routes.Application.forbidden());
}
};
}
return super.onRequest(request, method);
}
You can simply use PlayPlugin for this issue. See here for more details.
It's not a good solution to extend a base controller for all of your controllers and have the #Before in the base controller.
You can extends the filter or essensialfilter .e.g.
class filter1 extends Filter {}
and apply filter1 to Global