<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: davidcyp</title>
    <description>The latest articles on DEV Community by davidcyp (@davidcyp_52).</description>
    <link>https://dev.to/davidcyp_52</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F23480%2F7974b05b-04d7-46db-ac9a-23f30a1bc1ec.png</url>
      <title>DEV Community: davidcyp</title>
      <link>https://dev.to/davidcyp_52</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davidcyp_52"/>
    <language>en</language>
    <item>
      <title>Guaranteeing and enforcing your architecture (with ArchUnit) </title>
      <dc:creator>davidcyp</dc:creator>
      <pubDate>Mon, 23 Jul 2018 21:17:22 +0000</pubDate>
      <link>https://dev.to/davidcyp_52/guaranteeing-and-enforcing-your-architecture-with-archunit--4nf5</link>
      <guid>https://dev.to/davidcyp_52/guaranteeing-and-enforcing-your-architecture-with-archunit--4nf5</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NZR2Qpa5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frh5t6skv17nzv8mpx1v.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NZR2Qpa5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frh5t6skv17nzv8mpx1v.jpeg" alt="Guaranteeing and enforcing your architecture (with ArchUnit)" title="Guaranteeing and enforcing your architecture (with ArchUnit)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I was working on an application which relied heavily on a variety of data sources. Our application actually combines, interpretes and visualizes the data.&lt;/p&gt;

&lt;p&gt;Not everyone is allowed to see all the data. We needed a simple way to protect access to our resources, though not solely based on the typical users and roles. Access to data should be protected on a more granularized level. However, while on the one hand access rules are defined by a set of mutually excluding parameters, we also wanted to keep the code as clean and maintainable as possible.&lt;/p&gt;

&lt;p&gt;Since our application already relied on Spring Boot, our choice fell on spring-security and to be more precise it's @PreAuthorize annotation.&lt;/p&gt;

&lt;p&gt;We could have chosen to copy/paste/adapt the enclosed SPeL expression, though this would quickly introduce maintenance issues, eg. given we only have 2 distinct parameters which are used to grant access to a piece of data, we would still be copying the SPeL expressions throughout the code, introducing maintenance issues whenever the access rules change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   @Component
   public class SomeSecuredResource {

    @PreAuthorize("hasAccess(#foo)")
    public SensitiveData showMe(Foo foo){
        return new SensitiveData();
    }

    @PreAuthorize("isAllowedToSee(#bar)")
    public SensitiveData showMeToo(Bar bar){
        return new SensitiveData();
    }
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we created a simple annotation for that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@PreAuthorize(Sensitive.EXPRESSION)

public @interface Sensitive {

    String EXPRESSION = "#foo != null ? hasAccess(#foo) : (#bar != null ? isAllowedToSee(#bar) : false)";

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which we can now apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
public class SomeSecuredResource {

    @Sensitivepublic SensitiveData showMe(Foo foo){
        return new SensitiveData();
    }

    @Sensitivepublic SensitiveData showMeToo(Bar bar){
        return new SensitiveData();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine. Problem solved, one would think...&lt;/p&gt;

&lt;p&gt;That's only partially true. Okay, we isolated the logic which grants access to a method given a specific method parameter but we introduced other less visible issues.&lt;/p&gt;

&lt;p&gt;Suppose a new developer joins the team. And he sees these @Sensitive annotations protecting access to resources. And he applies them on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
public class NewDevsClass {

    @Sensitivepublic SensitiveData doSomething(long someParameter){
       return new SensitiveData(); 
    }

    @Sensitivepublic SensitiveData doOtherStuff(String foo){
        return new SensitiveData();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He is breaking the implicit rules here. As we have seen, the implementation of our @Sensitive annotation relies on a parameter of type Foo or Bar.&lt;/p&gt;

&lt;p&gt;Actually he is breaking our architectural rule, which is:&lt;/p&gt;

&lt;p&gt;Methods annotated with the @Sensitive annotation must have a parameter of type Foo or Bar.&lt;/p&gt;

&lt;p&gt;So, how do we solve this? Keep an extensive list of rules on the wiki and let everyone sift through it? Configure a Sonar rule and collect the reports every night? No, what about ... embedding those rules in a fast-executing unit test and get immediate feedback?&lt;/p&gt;

&lt;p&gt;Please welcome &lt;a href="https://github.com/TNG/ArchUnit"&gt;ArchUnit&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;ArchUnit: A Java architecture test library, to specify and assert architecture rules in plain Java&lt;br&gt;
So let's dig in, and write a test which ensures correct usage of our annotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SensitiveAnnotationUsageTest {

    DescribedPredicate&amp;lt;JavaClass&amp;gt; haveAFieldAnnotatedWithSensitive =
            new DescribedPredicate&amp;lt;JavaClass&amp;gt;("have a field annotated with @Sensitive"){
                @Overridepublic boolean apply(JavaClass input) {
                    // note : simplified version which inspects all classesreturn true;
                }
            };

    ArchCondition&amp;lt;JavaClass&amp;gt; mustContainAParameterOfTypeFooOrBar =
            new ArchCondition&amp;lt;JavaClass&amp;gt;("must have parameter of type 'com.example.post.Foo' or 'com.example.post.Bar'") {
                @Overridepublic void check(JavaClass item, ConditionEvents events) {
                    List&amp;lt;JavaMethod&amp;gt; collect = item.getMethods().stream()
                            .filter(method -&amp;gt; method.isAnnotatedWith(Sensitive.class)).collect(Collectors.toList());

                    for(JavaMethod method: collect){

                        List&amp;lt;String&amp;gt; names = method.getParameters().getNames();

                        if(!names.contains("com.example.post.Foo") &amp;amp;&amp;amp; !names.contains("com.example.post.Bar"))  {
                            String message = String.format(
                                    "Method %s bevat geen parameter met type 'Foo' of 'Bar", method.getFullName());
                            events.add(SimpleConditionEvent.violated(method, message));
                        }
                    }
                }
            };

    @Testpublic void checkArchitecturalRules(){
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example.post");

        ArchRule rule = ArchRuleDefinition.classes()
                .that(haveAFieldAnnotatedWithSensitive)
                .should(mustContainAParameterOfTypeFooOrBar);


        rule.check(importedClasses);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executing this test on our 2 classes results in the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that have a field annotated with @Sensitive should must have parameter of type 'com.example.post.Foo' was violated (2 times):
Method com.example.post.NewDevsClass.doOtherStuff(java.lang.String) bevat geen parameter met type 'Foo' of 'Bar
Method com.example.post.NewDevsClass.doSomething(long) bevat geen parameter met type 'Foo' of 'Bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et voila! We have a test in place which enforces a correct application of our architectural rules.&lt;/p&gt;

&lt;p&gt;Curious to find out more about ArchUnit? Make sure to check out their &lt;a href="http://archunit.org/"&gt;user guide&lt;/a&gt; and &lt;a href="https://github.com/TNG/ArchUnit"&gt;examples&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
