Field level access Control using Aspects/ Custom Annotation (Spring boot , Microservice) - authorization

Currently i am trying to implement authorization on fields , please find the cases from the below
example :
Based on some specific roles which are available in the ThreadLocal , we should be able to determine whether the user is allowed to pass the field in the payload. if the received role is not allowed to pass the attribute to do any Creation or updation we should throw 403
While providing response in the GET API , we should hide few fields which all are annotated with role:"ADMIN" as an example .
For the above example i am trying to use custom annotation Target as Fieldex :
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface CustomScopeFilter {
String[] scopesAllowed() default {"END_USER"};
}
But the custom annotation with FIELD is not working actually , because the implementation class which annotated with #Aspect is not getting called
The above annotation i have used in my DTO on field level
ex :
#Getter
#Setter
class TestDTO {
#CustomScopeFilter(scopesAllowed={"ADMIN"})
private String userRole;
}
Any ideas or suggestion would be very much helpful !! Thanks in advance
tried using Pointcut , joinpoint ,Aspectj, AOP. but those didnot worked on field-level
So i am expecting some suggestions how i can make it work .. or any alternative approach to achieve the same.

Related

Id Encryption in spring-hateoas or Spring Rest Data

I have a question about a standard pattern or mechanism in spring-hateoas or Spring Rest Data about encrypting the IDs of the Resources/Entities.
The reason I am asking, a requirement to our project is that we don't deliver the id's of our objects to the outside world and they should not be used in GET Requests as Parameters.
I know, Spring Rest Data and spring-hateoas does not give the ids of the objects unless they are configured so but even that case I can see the ids in links.
I know I can use PropertyEditors or Converters to encrypt/decrypt ids before and after Json serialisation/deseritalisation but I just like to know is there a more standard way?
Thx for answers...
If you have the unique 'business id' property of your resource you can configure SDR to use it instead of the entity ID.
First you have to create lookup method of your entity with this unique property:
public interface MyEntityRepo extends JpaRepository<MyEntity, Long> {
#RestResource(exported = false)
Optional<CatalogResource> findByMyUniqueProperty(String myUniqueProperty);
}
Then use it to configure SDR:
#Component
public class DataRestConfig extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withCustomEntityLookup()
.forRepository(MyEntityRepo.class, MyEntity::getMyUniqueProperty, MyEntityRepo::findByMyUniqueProperty);
super.configureRepositoryRestConfiguration(config);
}
}
After this customization you will have resource URI like this:
http://localhost:8080/myEntities/myUniquePropertyValue1

findBy URI not working in Spring Data Rest

By default, in Spring Data Rest the #Id of the entity is not exposed. In line with the REST rules, we're supposed to use the URI of the resource to refer to it. Given this assumption, the findBy queries should work if you pass a URI to them, but they don't.
For example, say I have a one-to-many relationship between Teacher and Student. I want to find students by teacher.
List<Student> findByTeacher(Teacher teacher)
http://localhost:8080/repositories/students/search/findByTeacher?teacher=http://localhost:8080/repositories/teachers/1
This doesn't work because the framework is attempting to convert the teacher URI to a Long.
I get this error that says "Failed to convert from type java.lang.String to type java.lang.Long".
Am I missing something?
You could expose #Id s by configuring web intializer
//Web intializer
#Configuration
public static class RespositoryConfig extends
RepositoryRestMvcConfiguration {
#Override
protected void configureRepositoryRestConfiguration(
RepositoryRestConfiguration config) {
config.exposeIdsFor(Teacher.class);
}
}
Its good to change List to Page
List findByTeacher(Teacher teacher)
to
Page<Student> findByTeacher(#Param("teacher) Teacher teacher, Pageable pageable);
Also note #Param annotation is required along with Pageable. The latter is required because return type "Page"
3.Latest snapshots, not milestones work fine
See https://jira.spring.io/browse/DATAREST-502
Depending of your version of Spring Data, it would work as you want or not. If you are with Spring Data 2.4, you need to pass the URI. If you are with a previous version, you need to pass the id.

wcf data services - expose properties of the same type in data model

I'm new to WCF data services. I have a quite simple data model. Some of its properties have the same type, like this:
public IQueryable<IntegerSum> HouseholdGoodsSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rHouseholdGoodsPrice", IntegerSumConverter);
}
}
public IQueryable<IntegerSum> StructureSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rStructurePrice", IntegerSumConverter);
}
}
The IntegerSum is a very very simple class:
[DataServiceKey("Amount")]
public class IntegerSum
{
public int Amount { get; set; }
}
When I navigate to my service in a web browser, I see the following error message:
The server encountered an error processing the request. The exception message is 'Property 'HouseholdGoodsSums' and 'StructureSums' are IQueryable of types 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and type 'IntegrationServices.PropertyIntegrationServices.IntegerSum' is an ancestor for type 'IntegrationServices.PropertyIntegrationServices.IntegerSum'. Please make sure that there is only one IQueryable property for each type hierarchy.'.
When I get rid of one of these two properties, the service starts working.
I searched for this error message in google, but haven't found a solution.
Is it really not allowed to have two properties with the same type in a data model? If so, why?
Comrade,
To address the error first, you're running into a limitation in the Reflection provider. Specifically, the Reflection provider doesn't support MEST.
That said, there are better approaches to achieve what you're trying to achieve. You should probably not make IntegerSum an entity type (an entity type is a uniquely identifiable entity, which doesn't really fit your scenario). While you can't expose that directly, you can expose it as a service operation. That seems much closer to what you're trying to achieve.
A couple of ways to distinguish between whether or not something should be an entity:
If it has a key already, such as a PK in a database, it should probably be an entity type
If you need to create/update/delete the object independently, it must be an entity type
HTH,
Mark

RavenDB does not set all the properties on store

I have a really weird scenario where I try to store domain events (I'm trying to learn CQRS and RavenDB at the same time). The basic structure of the documents I try to store are:
public interface IDomainEvent { ... }
public abstract class BaseDomainEvent : IDomainEvent { ... }
public class DomainEventA : BaseDomainEvent { ... }
public class DomainEventB : BaseDomainEvent { ... }
Given that I want to store DomainEventA and DomainEventB in the same collection in RavenDB and I have managed to do so. But the problem is that in the collection I am missing the properties of DomainEventB, and not all properties are set even though I have checked that the properties are set before I commit the transaction where I store the objects. The following gist shows a working example of what I want to do: https://gist.github.com/2830093, and the test code that fails me is found in this test: https://github.com/mastoj/TJ.CQRS/blob/ravenfail/TJ.CQRS.RavenEvent.Tests/RavenEventStoreTests.cs that is using this RavenDB code: https://github.com/mastoj/TJ.CQRS/blob/ravenfail/TJ.CQRS.RavenEvent/RavenEventStore.cs.
I really can't get my head around this one.
EDIT 1: I can add that in the failing scenario the metadata of the stored object says it is one type but the properties for that type is not stored.
I planned to delete or vote for close but I think more than me might experience this problem at some point. I found the solution in my case and it was that the objects I added to RavenDB had a faulty equals method so RavenDB thought that all my objects were the same one. When I added one more property to check in the equals method everything start working as expected.

C# WCF data contract partial class - new field in 2nd partial class not being picked up

I have a WCF service in which I have some data contracts. I'm using web service software factory, which uses a designer to create all the message and data and other contracts, and it creates them as partial classes. When the code is regenerated the classes are recreated.
using WcfSerialization = global::System.Runtime.Serialization;
[WcfSerialization::CollectionDataContract(Namespace = "urn:CAEService.DataContracts", ItemName = "SecurityItemCollection")]
public partial class SecurityItemCollection : System.Collections.Generic.List<SecurityItem>
{
}
The data contract is a generic List of a custom class which was working fine. However I now want to add a property to this class, so I added this partial class in the same namespace:
public partial class SecurityItemCollection
{
public int TotalRecords { get; set; }
}
This seems to work fine on the service side, but when I compile and then update the service reference from the client, the class doesn't have the new property i.e. when it serialises it and recreates it on the client side, it's missing the new property. Anyone know why this is?
TIA
EDIT:
Ok this is officially driving me nuts. The only thing I can see is that it is using the CollectionDataContract attribute instead of DataContract. Does this somehow not allow data members in the class to be serialised? Why would that be? It is working fine on the service side - I can see and populate the values no problem. However when I update the service refernce on my client there's nothing, just the colelction class without the data member.
Try to add the DataMember attribute to the TotalRecords property
Ok after much searching I finally found out that this isn't allowed i.e. classes marked as CollectionDataContract can't have data members. Why this is I have no idea but it cost me several hours and a major headache. See link below:
WCF CollectionDataContract and DataMember
I know this is old but it kept coming up when I searched on this subject.
I was able to get this working by adding a "DataMemberAttribute" attribute to the property. Below is a code example.
public partial class SecurityItemCollection
{
[global::System.Runtime.Serialization.DataMemberAttribute()]
public int TotalRecords { get; set; }
}