I am using swagger and Feign in one project, and the swagger will take #RequestMapping annotated methods and create the documentation. But this is weird to do so for classes and methods annotated by both #FeightClient and #RequestMapping. So how to ignore these apis in swagger? Which class of swagger
do the scan job so that I could learn and add some other class to ignore these apis annotated by #FeightClient?
#FeignClient(name = TodoItemRpcRepository.SERVICE_NAME)
#RequestMapping("/api/todos")
public interface TodoItemRpcRepository {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
TodoItem findById(#RequestHeader("X-Auth-Token") final String token, //
#PathVariable("id") final Long id);
}
In your docket select you can specify a predicate. You could use the withClassAnnotation method to specify #FeignClient as the annotation. You'd need to combine it with the Predicates.not to ignore in your case.
I removed the #RequestMapping over the #FeignClient annotated class and add a path attribute in the #FeignClient. This time, issue was resolved perfectly. I guess #RequestMapping is not permitted to #FeignClient annotated class.
#FeignClient(name = TodoItemRpcRepository.SERVICE_NAME, name="/api/todos")
public interface TodoItemRpcRepository {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
TodoItem findById(#RequestHeader("X-Auth-Token") final String token, //
#PathVariable("id") final Long id);
}
Related
I'm getting my feet wet with C# IoC frameworks. I chose StructureMap.Webapi2 to integrate into an existing api.
I have the following scenario which I am not sure what the best way to implement is.
public class MyController : ApiController
{
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = new ClientManager().GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
var myService = new WorkerService(someData);
myService.DoSomething();
return Ok();
}
}
A peek a the WorkerService:
public WorkerService(SomeData someData)
{
_someData = someData;
_someCollection = GetSomeData(); // GetSomeData uses _someData
}
public DoSomething()
{
// some code that uses _someData and _someCollection
}
Approach 1:
Make WorkerService's constructor parameterless and add a public SomeData property that can be initialized inside MyController MyAction.
Then both ClientManager and WorkerService can be injected by the IoC into a constructor to be added to the controller.
The Action would then look like:
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = _clientManager.GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
_myService.SomeData = someData;
_myService.DoSomething();
return Ok();
}
Approach 2 (the one I'm not sure how to implement)
Keep WorkerService constructor as is (with a parameter). Inject the service into the Controller's constructor (requires building and pass the service's argument (SomeData) at runtime, instead of having the MyAction build SomeData).
Somehow build SomeData (maybe using a factory) before for each request is handled by the controller. This would mean that ClientManager would have to be injected to that somehow/factory. The output of the somehow/factory would be used by the IoC when building the WorkerService to be injected into the controller, per request.
To me, Approach 1 seems quicker and simple, but Approach 2 seems to be more attractive, more challenging and with more learnings.
I ended up finding a solution for the problem:
Create a passive attribute and add to the action
Create an ActionFilter, which checks for the attribute and when found, gets data from the request.
Since I didn't like the approach of reading the request body in the ActionFilter, I changed the request and moved the data I needed from the body (server and data base names) to the url of the request. Then I created a POCO for that data that I inject into the ActionFilter and populate with the data from the url. That POCO isntance is now available in every service down the dependency chain that needs it.
For the rest of the data I needed in my SomeData object, I followed approach 1, made WorkerService's constructor parameterless and passed the data like:
_myService.DoSomething(someData);
One final trick was adding the ActionFilter to config.Filters, because my filter has it's own dependencies, I couldn't just do:
config.Filters.add(new MyActionFilter(What_About_The_Parametes_???))
I had to get the structureMap's container instance and have it return a instance of my filter which will the cause all the dependencies to be injected into it, and then I can add the filter instance to config.Filters:
var container = StructuremapMvc.StructureMapDependencyScope.Container;
config.Filters.Add(container.GetInstance<IMyActionFilter>());
I have a really nasty StackOverflowException in my spring backend, that I need help with. This is not going to be solved easily. I really hope to find some help here.
Most parts of my backend work. I can query my REST interface for models, they are nicely returned by spring-hateoas, GET, PUT and POST operations work. But one exception: When I try to update an existing DelegationModel, then I run into an endless StackOverflowException.
Here is my DelegetionModel.java class. Please mark, that delegation model actually doesn't have any property annotated with #CreatedBy!
#Entity
#Data
#NoArgsConstructor
#RequiredArgsConstructor(suppressConstructorProperties = true) //BUGFIX: https://jira.spring.io/browse/DATAREST-884
#EntityListeners(AuditingEntityListener.class) // this is necessary so that UpdatedAt and CreatedAt are handled.
#Table(name = "delegations")
public class DelegationModel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
/** Area that this delegation is in */
#NonNull
#NotNull
#ManyToOne
public AreaModel area;
/** reference to delegee that delegated his vote */
#NonNull
#NotNull
#ManyToOne
public UserModel fromUser;
/** reference to proxy that receives the delegation */
#NonNull
#NotNull
#ManyToOne
public UserModel toProxy;
#CreatedDate
#NotNull
public Date createdAt = new Date();
#LastModifiedDate
#NotNull
public Date updatedAt = new Date();
}
As described in the Spring-data-jpa doc I implemented the necessary AuditorAware interface, which loads the UserModel from the SQL DB. I would have expected that this AuditorAware interface is only called for models that have a field annotated with #CreatedBy.
#Component
public class LiquidoAuditorAware implements AuditorAware<UserModel> {
Logger log = LoggerFactory.getLogger(this.getClass()); // Simple Logging Facade 4 Java
#Autowired
UserRepo userRepo;
#Override
public UserModel getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
log.warn("Cannot getCurrentAuditor. No one is currently authenticated");
return null;
}
User principal = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
UserModel currentlyLoggedInUser = userRepo.findByEmail(principal.getUsername()); // <<<<======= (!)
return currentlyLoggedInUser;
} catch (Exception e) {
log.error("Cannot getCurrentAuditor: "+e);
return null;
}
}
}
Now I update a DelegationModel in my UserRestController. The functional "Scrum User Story" here is:
As a user I want to be able to store a delegation so that I can forward my right to vote to my proxy.
#RestController
#RequestMapping("/liquido/v2/users")
public class UserRestController {
[...]
#RequestMapping(value = "/saveProxy", method = PUT, consumes="application/json")
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody String saveProxy(
#RequestBody Resource<DelegationModel> delegationResource,
//PersistentEntityResourceAssembler resourceAssembler,
Principal principal) throws BindException
{
[...]
DelegationModel result = delegationRepo.save(existingDelegation);
[...]
}
[...]
}
For some reason, that I cannot see, this actualy calls the AuditorAware implementation above. The problem is now, that my LqiuidoAuditorAware implementation is called again and again in and endless loop. It seems that the query for the UserModel inside LiquidoAuditorAware.java calls the LiquidoAuditorAware again. (Which is unusual, because that is only a read operation from the DB.)
Here is the full ThreadDump as a Gist
All the code can by found in this github repo
I'd really apriciate any help here. I am searching in the dark :-)
The reason for the behavior you see is that the AuditorAware implementation is called from within a JPA #PrePersist/#PreUpdate callback. You now issue a query by calling findByEmail(…), which triggers the dirty-detection again, which in turn causes the flushing to be triggered and thus the invocation of the callbacks.
The recommended workaround is to keep an instance of the UserModel inside the Spring Security User implementation (by looking it up when the UserDetailsService looks up the instance on authentication), so that you don't need an extra database query.
Another (less recommended) workaround could be to inject an EntityManager into the AuditorAware implementation, call setFlushMode(FlushModeType.COMMIT) before the query execution and reset it to FlushModeType.AUTO after that, so that the flush will not be triggered for the query execution.
I'm using Spring Data Rest to expose a repository. I'm using #PreAuthorize and #PostFilter to restrict the access to the REST end points to exclusively admin users and filter the results.
#PreAuthorize("hasRole('ROLE_ADMIN')")
#PostFilter("hasPermission(filterObject, 'read')
public interface SomeRepository extends CrudRepository<SomeEntity, Long> {
}
At the same time I have another Controller that doesn't require any authentication but is using the repository.
#Controller
public class SomeController {
#Autowired
SomeRepository repository;
#RequestMapping(value = "/test")
public ResponseEntity test () {
// Do something
repository.findAll();
// Do something else
}
}
This doesn't work because the user that send the request to "/test" is not admin so it doesn't have access to the repository.
My question is, it is possible to add security exclusively to the REST interface of the repository and not when the repository is used internally in the application?
Thanks
Please evaluate these possibilities:
Security checks in REST event handlers
Adding custom repository methods for internal use
Using RunAsManager (or temporarily switching SecurityContext to perform a privileged operation)
Securing modifying requests using REST event handlers:
#Service
#RepositoryEventHandler
public class FooService {
/**
* Handles before-* events.
*/
#HandleBeforeCreate
#HandleBeforeSave
#HandleBeforeDelete
#PreAuthorize("hasRole('ADMIN')")
public void onBeforeModify(final Foo entity){
// noop
}
/**
* Handles before-* events.
*/
#HandleBeforeLinkSave
#HandleBeforeLinkDelete
#PreAuthorize("hasRole('ADMIN')")
public void onBeforeModifyLink(final Foo entity, final Object linked){
// noop
}
}
Securing standard CRUD methods while adding non-secure custom methods on repository for internal use:
public interface FooDao extends CrudRepository<Foo, Long> {
#Override
#PreAuthorize("hasRole('ADMIN')")
<S extends Foo> S save(final S entity);
/**
* Saves entity without security checks.
*/
#Transactional
#Modifying
default <S extends Foo> S saveInternal(final S entity) {
return save(entity);
}
}
One solution would be to remove the #PreAuthorize annotation from your repository interface, and in a configuration class, extend WebSecurityConfigAdaptor and override the configure(HttpSecurity security) method. From here you can use AntMatchers to impose access restrictions to the REST endpoints as required. For example:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/someEntities/**").hasRole('ADMIN')
.anyRequest().permitAll();
}
See http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-httpsecurity for more details.
I ran into the same problem and came up with a workaround that doesn't feel completely right but does its job for the time being.
I basically created a security utils bean which can be used to check if a method was called internally or externally using the Spring Data REST API (remark: my repositories are prefixed /api/, if you have another prefix you need to change the regex accordingly).
#Component("securityUtils")
public class SecurityUtils {
public boolean isRestRequest(){
HttpServletRequest r = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
return Pattern.matches("^/api/", UrlUtils.buildRequestUrl(r));
}
}
To make this work, you need to add the following line to your listeners in the web.xml:
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
And use the method in your expression based access control like so (where the last line in the expression allows you to use the save method from any controller methods that are mapped against URLs which do not start with /api/:
#Override
#PreAuthorize("hasRole('ROLE_ADMINISTRATOR') " +
"or hasPermission(#user, 'WRITE') " +
"or !#securityUtils.isRestRequest()")
<S extends User> S save(#P("user") S user);
Caveats:
You cannot use this when you want to expose custom functionality over the /api route as this is merely a simple regex check against the route
The check has to be explicitly added to each repository or repository method for which you want to omit the authorization check internally (might be an advantage as well)
In my opinion the right solution would be to have two Repositories, one that is called EntityRepository and one SecuredEntityRepository.
Example:
#RestResource(exported = false)
public abstract interface CustomerRepository extends JpaRepository<Customer, Long> {
}
and the secured version:
#RestResource(exported = true)
public abstract interface SecuredCustomerRepository extends CustomerRepository {
#Override
#PreAuthorize("#id == principal.customer.id or hasAuthority('ADMIN_CUSTOMER_ONE')")
public Customer findOne(#Param("id") Long id);
#Override
#Query("SELECT o FROM #{#entityName} o WHERE o.id = ?#{principal.customer.id} or 1 = ?#{ hasAuthority('ADMIN_CUSTOMER_LIST') ? 1 : 0 }")
public Page<Customer> findAll(Pageable pageable);
#Override
#SuppressWarnings("unchecked")
#PreAuthorize("#customer.id == principal.customer.id or hasAuthority('ADMIN_CUSTOMER_SAVE')")
public Customer save(#P("customer") Customer customer);
#Override
#PreAuthorize("hasAuthority('ADMIN_CUSTOMER_DELETE')")
public void delete(#Param("id") Long id);
#Override
#PreAuthorize("hasAuthority('ADMIN_CUSTOMER_DELETE')")
public void delete(Customer customer);
}
This is currently not possible due to an issue with the auto-wiring mechanism in SD REST: https://jira.spring.io/browse/DATAREST-923
Sure. Just change the location of the #PreAuthorize annotation. This annotation can be placed in classes or single methods.
For example
#Controller
public class SomeController {
#Autowired
SomeRepository repository;
#RequestMapping(value = "/test")
#PreAuthorize(....)
public ResponseEntity test () {
// Do something
repository.findAll();
// Do something else
}
}
is perfectly legit (note the annotation on the test() method.
I decorated the repository class with this:
#PreAuthorize("hasRole('admin')")
It locked down everything.
Then whatever I wanted to enable for internal use but not rest, I decorated like this:
#Transactional
#Modifying
#PreAuthorize("hasRole('user')")
#RestResource(exported = false)
default <S extends SomeEntity> S saveInternal(final S entity) {
return save(entity);
}
And whatever I wanted to expose via the Rest interface (handpicked few) I exposed with something like this:
#PreAuthorize("(hasRole('user')) and
(#entity.user.username == principal.name)")
#Override
<S extends SomeEntity> S save(#Param("entity") S entity);
Note that this also validates that you are saving a record you are authorized to save.
I solved this problem by adding my own check
I created my AbstractHttpConfigurer class with global security. I have declared methods that can be public.
public class CommonSpringKeycloakTutorialsSecurityAdapter extends AbstractHttpConfigurer<CommonSpringKeycloakTutorialsSecurityAdapter, HttpSecurity> {
public static String[] PERMIT_ALL_URL = {"/api/user/createUser"};
#Override
public void init(HttpSecurity http) throws Exception {
// any method that adds another configurer
// must be done in the init method
http
// disable csrf because of API mode
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// manage routes securisation here
.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
// manage routes securisation here
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/swagger-ui.html*", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.antMatchers(PERMIT_ALL_URL).permitAll()
.anyRequest().authenticated();
}
Then I created my own check based on global permissions.
#Component("securityUtils")
public class SecurityUtils {
public boolean isPermitRestRequest(){
HttpServletRequest r = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String currentUrl = UrlUtils.buildRequestUrl(r);
for(String url: CommonSpringKeycloakTutorialsSecurityAdapter.PERMIT_ALL_URL) {
if(currentUrl.equals(url)) {
return true;
}
}
return false;
}
}
For native validation to work, include a listener
#WebListener
public class MyRequestContextListener extends RequestContextListener {
}
In my team we evaluated several of the answers in this post and they didn't fit to our scenario.
A variation of Johannes Hiemer answer worked for us. We configured Spring Data REST to only expose annotated repositories:
data.rest:
detection-strategy: annotated
Then we defined 2 repositories without hierarchical relationship.
One of the repos will be exposed by adding the #RepositoryRestResource annotation to it. For this one, we deny access to every method by default so auth will have to be specified on a method level to reduce the chances of exposing methods by mistake. For example, initially we extended CrudRepository and didn't want to expose the deletion operation:
#RepositoryRestResource
#PreAuthorize("denyAll()")
interface SomeRestResourceRepository : Repository<SomeEntity, Long> {
}
The repository to be used for internal calls is defined as a regular Spring Data Repository:
interface SomeRepository : Repository<SomeEntity, Long> {
}
We are using spring-boot-starter-data-rest 2.6.3.
I want to select an Action of my Controller based on the Media Type requested in the Accept header.
For example, I have a resource called a subject. Its assigned route is:
GET /subjects/{subjectId:int}
Normally, the browser is requesting text/html, which is fine. The default Media Formatter handles this great.
Now, I have custom logic I want to perform when this same route is accessed with an accept header specifying application/pdf as the accepted Media Type.
I could create a custom Media Formatter, but, to my understanding, this would mean that any route that is requested with the Accept header set to application/pdf would also run through this Media Formatter. This is unacceptable.
In Java, there is an annotation called #Produces:
The #Produces annotation is used to specify the MIME media types or
representations a resource can produce and send back to the client. If
#Produces is applied at the class level, all the methods in a resource
can produce the specified MIME types by default. If applied at the
method level, the annotation overrides any #Produces annotations
applied at the class level.
This would allow me to do the following:
namespace MyNamespace
{
[RoutePrefix("subjects")]
public class SubjectsController : Controller
{
[Route("{subjectId:int}")]
[HttpGet]
public ActionResult GetSubject(int subjectId)
{
}
[Route("{subjectId:int}")]
[HttpGet]
[Produces("application/pdf")]
public ActionResult GetSubjectAsPdf(int subjectId)
{
//Run my custom logic here to generate a PDF.
}
}
}
There is no Produces Attribute in .NET that I can find, of course, so this doesn't work. I haven't been able to find a similar attribute, either.
I could of course manually check the header within the body of the action, and redirect it to another action, but that seems hackish at best.
Is there a mechanism in .NET 4.5 that I may use to pull this off that I'm overlooking or missing?
(I'm using MVC 5.2.2 from NuGet repository)
After searching around the Internet for awhile, I came up with the idea that this would be best accomplished by creating an ActionMethodSelectorAttribute.
The following is a very naive, first-pass implementation of a ProducesAttribute that I wrote with the eventual intent of mimicking Java's Produces annotation:
namespace YourNamespace
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Mime;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ProducesAttribute : ActionMethodSelectorAttribute
{
private readonly ISet<ContentType> acceptableMimeTypes;
public ProducesAttribute(params string[] acceptableMimeTypes)
{
this.acceptableMimeTypes = new HashSet<ContentType>();
foreach (string acceptableMimeType in acceptableMimeTypes)
this.acceptableMimeTypes.Add(new ContentType(acceptableMimeType));
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
string acceptHeader = controllerContext.RequestContext.HttpContext.Request.Headers[HttpRequestHeader.Accept.ToString()];
string[] headerMimeTypes = acceptHeader.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
foreach (var headerMimeType in headerMimeTypes)
{
if (this.acceptableMimeTypes.Contains(new ContentType(headerMimeType)))
return true;
}
return false;
}
}
}
It is meant to be used with Attribute Routing, and can be applied as follows:
public sealed class MyController : Controller
{
[Route("subjects/{subjectId:int}")] //My route
[Produces("application/pdf")]
public ActionResult GetSubjectAsPdf(int subjectId)
{
//Here you would return the PDF representation.
}
[Route("subjects/{subjectId:int}")]
public ActionResult GetSubject(int subjectId)
{
//Would handle all other routes.
}
}
I'm relatively new to Struts2.
I've started using ModelDriven to reduce overhead in development.
I wanted to write an interface to modify a property before it gets to the action but I don't see how you can access the properties of a class that implements ModelDriven for the Model.
I can see how things like validate() can work as they are in the actual action class.
I changed the design to encapsulate the logic behind the service anyways but still would like to know if this is possible.
We're doing everything by ajax/json so I find modeldriven helps quite a lot - not sure if there is a better alternative though!
Edit - code example:
Trying to replace a message with a message in a template to use in an email body.
public class EmailActionImpl implements EmailAction {
private Email email=new Email();
private EmailService emailService;
public Email getModel(){
return email;
}
[... getters and setters ...]
public String execute(){
logger.info("Email action is sendind an email...");
try{
emailService.sendNewMail(email);
}catch(Exception e){
logger.error("Email not sent: " + e.getMessage());
return "failure";
}
return "success";
}
}
Email model something like this
#Entity
#Table(name="email")
public class Email {
private Long id;
private String from;
private String to;
private String message;
private String templateType;
[...]
}
I would like an interceptor preprocessor to replace email.message.
Should look something like this but action.getMessage/setMessage aren't available.
public class SimpleInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation) throws Exception {
EmailAction action = (EmailAction)invocation.getAction();
action.setMessage(MessageTemplateFactoryImpl(action.getMessage(), action.getTemplateType());
return invocation.invoke();
}
}
If you still want to implement an interceptor to work on a particular set of models then you will check if the Action implements ModelDriven. Via reflection (or Apache bean utils) you can derive the particular model in question, to determine if your interceptor applies and then act on it accordingly.