Allowing foreign applications to access specific endpoints.
diff --git a/component-test/src/main/java/TestSystemTokenOnSpringEndpoints.java b/component-test/src/main/java/TestSystemToken.java
similarity index 63%
rename from component-test/src/main/java/TestSystemTokenOnSpringEndpoints.java
rename to component-test/src/main/java/TestSystemToken.java
index 07cdc5c..66d2f5b 100644
--- a/component-test/src/main/java/TestSystemTokenOnSpringEndpoints.java
+++ b/component-test/src/main/java/TestSystemToken.java
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import io.mifos.anubis.example.simple.Example;
 import io.mifos.anubis.example.simple.ExampleConfiguration;
 import io.mifos.anubis.example.simple.Metrics;
 import io.mifos.anubis.example.simple.MetricsFeignClient;
+import io.mifos.anubis.test.v1.SystemSecurityEnvironment;
 import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
 import io.mifos.core.api.context.AutoUserContext;
+import io.mifos.core.api.util.NotFoundException;
 import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
 import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
@@ -44,7 +47,7 @@
  */
 @RunWith(SpringRunner.class)
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
-public class TestSystemTokenOnSpringEndpoints {
+public class TestSystemToken {
   private static final String APP_NAME = "anubis-v1";
 
   @Configuration
@@ -78,14 +81,40 @@
 
   @SuppressWarnings({"SpringAutowiredFieldsWarningInspection", "SpringJavaAutowiringInspection", "SpringJavaAutowiredMembersInspection"})
   @Autowired
-  protected MetricsFeignClient example;
+  protected MetricsFeignClient metricsFeignClient;
+
+  @SuppressWarnings({"SpringAutowiredFieldsWarningInspection", "SpringJavaAutowiredMembersInspection"})
+  @Autowired
+  Example example;
 
 
   @Test
-  public void shouldBeAbleToGetMetrics() throws Exception {
+  public void shouldBeAbleToGetContactSpringEndpoint() throws Exception {
     try (final AutoUserContext ignored = tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
-      final Metrics metrics = example.getMetrics();
+      final Metrics metrics = metricsFeignClient.getMetrics();
       Assert.assertTrue(metrics.getThreads() > 0);
     }
   }
+
+  @Test
+  public void shouldBeAbleToGetForForeignApplication() throws Exception {
+    final TenantApplicationSecurityEnvironmentTestRule tenantForeignApplicationSecurityEnvironment
+            = new TenantApplicationSecurityEnvironmentTestRule("foreign-v1", testEnvironment.serverURI(),
+            new SystemSecurityEnvironment(testEnvironment.getSystemKeyTimestamp(), testEnvironment.getSystemPublicKey(), testEnvironment.getSystemPrivateKey()));
+    try (final AutoUserContext ignored = tenantForeignApplicationSecurityEnvironment.createAutoSeshatContext()) {
+      final boolean ret = example.forApplication("foreign-v1");
+      Assert.assertTrue(ret);
+    }
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void shouldNotBeAbleToGetForForeignApplicationWhenForeignApplicationNotEnabled() throws Exception {
+    final TenantApplicationSecurityEnvironmentTestRule tenantForeignApplicationSecurityEnvironment
+            = new TenantApplicationSecurityEnvironmentTestRule("foreign-v1", testEnvironment.serverURI(),
+            new SystemSecurityEnvironment(testEnvironment.getSystemKeyTimestamp(), testEnvironment.getSystemPublicKey(), testEnvironment.getSystemPrivateKey()));
+    try (final AutoUserContext ignored = tenantForeignApplicationSecurityEnvironment.createAutoSeshatContext()) {
+      example.notForApplication("foreign-v1");
+      Assert.fail("Shouldn't be able to access for a foreign token in this case.");
+    }
+  }
 }
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/anubis/example/simple/Example.java b/component-test/src/main/java/io/mifos/anubis/example/simple/Example.java
index 4a3f29c..db8c503 100644
--- a/component-test/src/main/java/io/mifos/anubis/example/simple/Example.java
+++ b/component-test/src/main/java/io/mifos/anubis/example/simple/Example.java
@@ -17,6 +17,7 @@
 
 import io.mifos.core.api.util.CustomFeignClientsConfiguration;
 import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
@@ -33,4 +34,10 @@
 
   @RequestMapping(value = "foo", method = RequestMethod.GET)
   boolean foo();
+
+  @RequestMapping(value = "{applicationidentifier}/forapplication", method = RequestMethod.GET)
+  boolean forApplication(@PathVariable("applicationidentifier") final String applicationIdentifier);
+
+  @RequestMapping(value = "{applicationidentifier}/notforapplication", method = RequestMethod.GET)
+  boolean notForApplication(@PathVariable("applicationidentifier") final String applicationIdentifier);
 }
diff --git a/component-test/src/main/java/io/mifos/anubis/example/simple/ExampleRestController.java b/component-test/src/main/java/io/mifos/anubis/example/simple/ExampleRestController.java
index d988f27..a05fb41 100644
--- a/component-test/src/main/java/io/mifos/anubis/example/simple/ExampleRestController.java
+++ b/component-test/src/main/java/io/mifos/anubis/example/simple/ExampleRestController.java
@@ -19,6 +19,7 @@
 import io.mifos.anubis.annotation.Permittable;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
@@ -60,4 +61,17 @@
   public ResponseEntity<Boolean> foo() {
     return ResponseEntity.ok(false);
   }
+
+  @RequestMapping(value = "/{applicationidentifier}/forapplication", method = RequestMethod.GET)
+  @Permittable(value = AcceptedTokenType.SYSTEM, permittedEndpoint = "/{applicationidentifier}/forapplication", acceptTokenIntendedForForeignApplication = true)
+  public ResponseEntity<Boolean> forApplication(@PathVariable("applicationidentifier") final String applicationIdentifier) {
+    return ResponseEntity.ok(true);
+  }
+
+  @SuppressWarnings("DefaultAnnotationParam")
+  @RequestMapping(value = "/{applicationidentifier}/notforapplication", method = RequestMethod.GET)
+  @Permittable(value = AcceptedTokenType.SYSTEM, permittedEndpoint = "/{applicationidentifier}/forapplication", acceptTokenIntendedForForeignApplication = false)
+  public ResponseEntity<Boolean> notForApplication(@PathVariable("applicationidentifier") final String applicationIdentifier) {
+    return ResponseEntity.ok(true);
+  }
 }
diff --git a/library/src/main/java/io/mifos/anubis/config/AnubisSecurityConfigurerAdapter.java b/library/src/main/java/io/mifos/anubis/config/AnubisSecurityConfigurerAdapter.java
index 541c0fc..2553dbb 100644
--- a/library/src/main/java/io/mifos/anubis/config/AnubisSecurityConfigurerAdapter.java
+++ b/library/src/main/java/io/mifos/anubis/config/AnubisSecurityConfigurerAdapter.java
@@ -20,6 +20,7 @@
 import io.mifos.anubis.security.ApplicationPermission;
 import io.mifos.anubis.security.IsisAuthenticatedAuthenticationProvider;
 import io.mifos.anubis.security.UrlPermissionChecker;
+import io.mifos.core.lang.ApplicationName;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -54,9 +55,12 @@
 @EnableWebSecurity
 public class AnubisSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
   final private Logger logger;
+  final private ApplicationName applicationName;
 
-  public AnubisSecurityConfigurerAdapter(final @Qualifier(LOGGER_NAME) Logger logger) {
+  public AnubisSecurityConfigurerAdapter(final @Qualifier(LOGGER_NAME) Logger logger,
+                                         final ApplicationName applicationName) {
     this.logger = logger;
+    this.applicationName = applicationName;
   }
 
   @PostConstruct
@@ -92,7 +96,7 @@
 
   private AccessDecisionManager defaultAccessDecisionManager() {
     final List<AccessDecisionVoter<?>> voters = new ArrayList<>();
-    voters.add(new UrlPermissionChecker(logger));
+    voters.add(new UrlPermissionChecker(logger, applicationName));
     return new UnanimousBased(voters);
   }
 
diff --git a/library/src/main/java/io/mifos/anubis/security/AnubisAuthentication.java b/library/src/main/java/io/mifos/anubis/security/AnubisAuthentication.java
index add7eb6..ab7385f 100644
--- a/library/src/main/java/io/mifos/anubis/security/AnubisAuthentication.java
+++ b/library/src/main/java/io/mifos/anubis/security/AnubisAuthentication.java
@@ -32,16 +32,16 @@
 
   private final String token;
   private final String userIdentifier;
-  private final String callingApplicationIdentifier;
+  private final String forApplicationName;
   private final Set<ApplicationPermission> applicationPermissions;
 
-  AnubisAuthentication(final String token, final String userIdentifier, final String callingApplicationIdentifier,
+  AnubisAuthentication(final String token, final String userIdentifier, final String forApplicationName,
       final Set<ApplicationPermission> applicationPermissions) {
     authenticated = true;
 
     this.token = token;
     this.userIdentifier = userIdentifier;
-    this.callingApplicationIdentifier = callingApplicationIdentifier;
+    this.forApplicationName = forApplicationName;
     this.applicationPermissions = Collections.unmodifiableSet(new HashSet<>(applicationPermissions));
   }
 
@@ -62,7 +62,7 @@
 
   @Override
   public AnubisPrincipal getPrincipal() {
-    return new AnubisPrincipal(userIdentifier, callingApplicationIdentifier);
+    return new AnubisPrincipal(userIdentifier, forApplicationName);
   }
 
   @Override
diff --git a/library/src/main/java/io/mifos/anubis/security/ApplicationPermission.java b/library/src/main/java/io/mifos/anubis/security/ApplicationPermission.java
index 147d233..ee3e2d9 100644
--- a/library/src/main/java/io/mifos/anubis/security/ApplicationPermission.java
+++ b/library/src/main/java/io/mifos/anubis/security/ApplicationPermission.java
@@ -18,6 +18,7 @@
 import io.mifos.anubis.api.v1.domain.AllowedOperation;
 import io.mifos.anubis.service.PermissionSegmentMatcher;
 import io.mifos.core.api.util.ApiConstants;
+import io.mifos.core.lang.ApplicationName;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.web.FilterInvocation;
 
@@ -60,11 +61,17 @@
     return URL_AUTHORITY;
   }
 
-  boolean matches(final FilterInvocation filterInvocation, final AnubisPrincipal principal) {
-    return matches(filterInvocation.getRequest(), principal);
+  boolean matches(final FilterInvocation filterInvocation,
+                  final ApplicationName applicationName,
+                  final AnubisPrincipal principal) {
+    return matches(filterInvocation.getRequest(), applicationName, principal);
   }
 
-  boolean matches(final HttpServletRequest request, final AnubisPrincipal principal) {
+  boolean matches(final HttpServletRequest request,
+                  final ApplicationName applicationName,
+                  final AnubisPrincipal principal) {
+    if (!acceptTokenIntendedForForeignApplication && !applicationName.toString().equals(principal.getForApplicationName()))
+      return false;
     boolean isSu = principal.getUser().equals(ApiConstants.SYSTEM_SU);
     return matchesHelper(
         request.getServletPath(),
diff --git a/library/src/main/java/io/mifos/anubis/security/GuestAuthenticator.java b/library/src/main/java/io/mifos/anubis/security/GuestAuthenticator.java
index a5301b9..12b2ce4 100644
--- a/library/src/main/java/io/mifos/anubis/security/GuestAuthenticator.java
+++ b/library/src/main/java/io/mifos/anubis/security/GuestAuthenticator.java
@@ -18,6 +18,7 @@
 import io.mifos.anubis.annotation.AcceptedTokenType;
 import io.mifos.anubis.api.v1.RoleConstants;
 import io.mifos.anubis.service.PermittableService;
+import io.mifos.core.lang.ApplicationName;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -34,12 +35,15 @@
 public class GuestAuthenticator {
   private Set<ApplicationPermission> permissions;
   private final Logger logger;
+  private final ApplicationName applicationName;
 
   @Autowired
   public GuestAuthenticator(final PermittableService permittableService,
-                            final @Qualifier(LOGGER_NAME) Logger logger) {
+                            final @Qualifier(LOGGER_NAME) Logger logger,
+                            final ApplicationName applicationName) {
     this.permissions = permittableService.getPermittableEndpointsAsPermissions(AcceptedTokenType.GUEST);
     this.logger = logger;
+    this.applicationName = applicationName;
   }
 
   AnubisAuthentication authenticate(final String user) {
@@ -48,6 +52,6 @@
 
     logger.info("Guest access \"authenticated\" successfully.", user);
 
-    return new AnubisAuthentication(null, RoleConstants.GUEST_USER_IDENTIFIER, null, permissions);
+    return new AnubisAuthentication(null, RoleConstants.GUEST_USER_IDENTIFIER, applicationName.toString(), permissions);
   }
 }
diff --git a/library/src/main/java/io/mifos/anubis/security/SystemAuthenticator.java b/library/src/main/java/io/mifos/anubis/security/SystemAuthenticator.java
index 88651e7..46c01e3 100644
--- a/library/src/main/java/io/mifos/anubis/security/SystemAuthenticator.java
+++ b/library/src/main/java/io/mifos/anubis/security/SystemAuthenticator.java
@@ -23,7 +23,6 @@
 import io.mifos.anubis.service.PermittableService;
 import io.mifos.anubis.token.TokenType;
 import io.mifos.core.api.util.ApiConstants;
-import io.mifos.core.lang.ApplicationName;
 import io.mifos.core.lang.TenantContextHolder;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -40,18 +39,15 @@
 @Component
 public class SystemAuthenticator {
   private final SystemRsaKeyProvider systemRsaKeyProvider;
-  private final ApplicationName applicationName;
   private final Set<ApplicationPermission> permissions;
   private final Logger logger;
 
   @Autowired
   public SystemAuthenticator(
           final SystemRsaKeyProvider systemRsaKeyProvider,
-          final ApplicationName applicationName,
           final PermittableService permittableService,
           final @Qualifier(LOGGER_NAME) Logger logger) {
     this.systemRsaKeyProvider = systemRsaKeyProvider;
-    this.applicationName = applicationName;
     this.permissions = permittableService.getPermittableEndpointsAsPermissions(AcceptedTokenType.SYSTEM);
     this.logger = logger;
   }
@@ -75,9 +71,8 @@
       //noinspection unchecked
       final Jwt<Header, Claims> result = jwtParser.parse(token);
       if (result.getBody() == null ||
-              result.getBody().getAudience() == null ||
-              !result.getBody().getAudience().equals(applicationName.toString())) {
-        logger.info("System token for user {}, with key timestamp {} failed to authenticate. Audience was set wrong or was not set.", user, keyTimestamp);
+              result.getBody().getAudience() == null) {
+        logger.info("System token for user {}, with key timestamp {} failed to authenticate. Audience was not set.", user, keyTimestamp);
         throw AmitAuthenticationException.invalidToken();
       }
 
diff --git a/library/src/main/java/io/mifos/anubis/security/TenantAuthenticator.java b/library/src/main/java/io/mifos/anubis/security/TenantAuthenticator.java
index 1ec5a7b..bd53f33 100644
--- a/library/src/main/java/io/mifos/anubis/security/TenantAuthenticator.java
+++ b/library/src/main/java/io/mifos/anubis/security/TenantAuthenticator.java
@@ -88,7 +88,7 @@
       logger.info("Tenant token for user {}, with key timestamp {} authenticated successfully.", user, keyTimestamp);
 
       return new AnubisAuthentication(TokenConstants.PREFIX + token,
-          jwt.getBody().getSubject(), null, permissions
+          jwt.getBody().getSubject(), applicationNameWithVersion, permissions
       );
     }
     catch (final JwtException e) {
diff --git a/library/src/main/java/io/mifos/anubis/security/UrlPermissionChecker.java b/library/src/main/java/io/mifos/anubis/security/UrlPermissionChecker.java
index 22c185d..2c55cd1 100644
--- a/library/src/main/java/io/mifos/anubis/security/UrlPermissionChecker.java
+++ b/library/src/main/java/io/mifos/anubis/security/UrlPermissionChecker.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.anubis.security;
 
+import io.mifos.core.lang.ApplicationName;
 import org.slf4j.Logger;
 import org.springframework.security.access.AccessDecisionVoter;
 import org.springframework.security.access.ConfigAttribute;
@@ -30,9 +31,11 @@
  */
 public class UrlPermissionChecker implements AccessDecisionVoter<FilterInvocation> {
   private final Logger logger;
+  private final ApplicationName applicationName;
 
-  public UrlPermissionChecker(final Logger logger) {
+  public UrlPermissionChecker(final Logger logger, final ApplicationName applicationName) {
     this.logger = logger;
+    this.applicationName = applicationName;
   }
 
   @Override public boolean supports(final ConfigAttribute attribute) {
@@ -58,7 +61,7 @@
     final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
     final Optional<ApplicationPermission> matchedPermission = authorities.stream()
             .map(x -> (ApplicationPermission) x)
-            .filter(x -> x.matches(filterInvocation, authentication.getPrincipal()))
+            .filter(x -> x.matches(filterInvocation, applicationName, authentication.getPrincipal()))
             .findAny();
 
     matchedPermission.ifPresent(x -> logger.debug("Authorizing access to {} based on permission: {}"
diff --git a/library/src/test/java/io/mifos/anubis/security/ApplicationPermissionTest.java b/library/src/test/java/io/mifos/anubis/security/ApplicationPermissionTest.java
index 19e7452..0e1c3dc 100644
--- a/library/src/test/java/io/mifos/anubis/security/ApplicationPermissionTest.java
+++ b/library/src/test/java/io/mifos/anubis/security/ApplicationPermissionTest.java
@@ -17,6 +17,7 @@
 
 import io.mifos.anubis.api.v1.domain.AllowedOperation;
 import io.mifos.core.api.util.ApiConstants;
+import io.mifos.core.lang.ApplicationName;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -41,11 +42,11 @@
     private String permittedPath = "/heart";
     private AllowedOperation allowedOperation = AllowedOperation.READ;
     private boolean acceptTokenIntendedForForeignApplication = false;
-    private String calledApplication = "grainCounter";
+    private String calledApplication = "graincounter-v1";
     private String requestedPath = "/heart";
     private String requestedOperation = "GET";
     private String user = "Nebamun";
-    private String forApplication = "grainCounter";
+    private String forApplication = "graincounter-v1";
     private boolean expectedResult = true;
 
     private TestCase(final String caseName) {
@@ -79,8 +80,8 @@
       return this;
     }
 
-    String getCalledApplication() {
-      return calledApplication;
+    ApplicationName getCalledApplication() {
+      return ApplicationName.fromSpringApplicationName(calledApplication);
     }
 
     TestCase calledApplication(final String newVal)
@@ -187,24 +188,31 @@
             .permittedPath("/x/y/z/*").requestedPath("/m/n/o/")
             .expectedResult(false));
     ret.add(new TestCase("{applicationidentifier} but permission doesn't allow foreign forApplication")
-            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/b/o/")
+            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/bcde-v1/o/")
             .acceptTokenIntendedForForeignApplication(false)
-            .calledApplication("a").forApplication("b")
+            .calledApplication("abcd-v1").forApplication("bcde-v1")
             .expectedResult(false));
     ret.add(new TestCase("{applicationidentifier} and permission does allow foreign forApplication")
-            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/b/o/")
+            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/bcde-v1/o/")
             .acceptTokenIntendedForForeignApplication(true)
-            .calledApplication("a").forApplication("b")
+            .calledApplication("abcd-v1").forApplication("bcde-v1")
             .expectedResult(true));
     ret.add(new TestCase("No {applicationidentifier} even though permission does allow foreign forApplication")
-            .permittedPath("/m/n/o").requestedPath("/m/b/o/")
+            .permittedPath("/m/n/o").requestedPath("/m/bcde-v1/o/")
             .acceptTokenIntendedForForeignApplication(true)
-            .calledApplication("a").forApplication("b")
+            .calledApplication("abcd-v1").forApplication("bcde-v1")
             .expectedResult(false));
     ret.add(new TestCase("{applicationidentifier} and permission does allow foreign forApplication, but application isn't foreign.")
-            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/a/o/")
+            .permittedPath("/m/{applicationidentifier}/o").requestedPath("/m/abcd-v1/o/")
             .acceptTokenIntendedForForeignApplication(true)
-            .calledApplication("a").forApplication("a")
+            .calledApplication("abcd-v1").forApplication("abcd-v1")
+            .expectedResult(true));
+    ret.add(new TestCase("initialize")
+            .permittedPath("/initialize").requestedPath("/initialize")
+            .acceptTokenIntendedForForeignApplication(false)
+            .calledApplication("abcd-v1").forApplication("abcd-v1")
+            .allowedOperation(AllowedOperation.CHANGE)
+            .requestedOperation("POST")
             .expectedResult(true));
 
     return ret;
@@ -218,7 +226,7 @@
     when(requestMock.getServletPath()).thenReturn(testCase.getRequestedPath());
     when(requestMock.getMethod()).thenReturn(testCase.getRequestedOperation());
 
-    final boolean matches = testSubject.matches(requestMock, testCase.getPrincipal());
+    final boolean matches = testSubject.matches(requestMock, testCase.getCalledApplication(), testCase.getPrincipal());
 
     Assert.assertEquals("Testcase gave wrong result: '" + testCase.toString() + "'",
         testCase.getExpectedResult(), matches);
diff --git a/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java b/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
index b08e459..faed373 100644
--- a/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
+++ b/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
@@ -34,7 +34,6 @@
 import io.mifos.core.api.context.AutoUserContext;
 import io.mifos.core.api.util.ApiConstants;
 import io.mifos.core.api.util.UserContextHolder;
-import io.mifos.core.lang.ApplicationName;
 import io.mifos.core.lang.TenantContextHolder;
 import io.mifos.core.lang.security.RsaKeyPairFactory;
 import org.mockito.Mockito;
@@ -204,7 +203,6 @@
 
     final SystemAuthenticator systemAuthenticator = new SystemAuthenticator(
             systemRsaKeyProvider,
-            ApplicationName.appNameWithVersion(forService, forServiceVersion),
             permittableService,
             logger);
     try {