From adf7e6616c2a8d6f60207059288423f693509928 Mon Sep 17 00:00:00 2001
From: DUVAL Thomas <thomas.duval@orange.com>
Date: Thu, 16 Jun 2016 14:50:31 +0200
Subject: Add new version of aaa

Change-Id: I94d72011e6019e66c98f46d11436a5cb33ff295d
---
 odl-aaa-moon/aaa/.gitignore                        |   26 +
 odl-aaa-moon/aaa/README.md                         |   62 +
 odl-aaa-moon/aaa/aaa-authn-api/pom.xml             |   38 +
 .../aaa/aaa-authn-api/src/main/docs/Makefile       |   29 +
 .../aaa-authn-api/src/main/docs/class_diagram.png  |  Bin 0 -> 30016 bytes
 .../aaa-authn-api/src/main/docs/class_diagram.ucls |  127 ++
 .../src/main/docs/credential_auth_sequence.png     |  Bin 0 -> 29197 bytes
 .../src/main/docs/credential_auth_sequence.wsd     |   18 +
 .../src/main/docs/federated_auth_sequence.png      |  Bin 0 -> 40566 bytes
 .../src/main/docs/federated_auth_sequence.wsd      |   24 +
 .../aaa/aaa-authn-api/src/main/docs/mapping.rst    | 1609 +++++++++++++++++++
 .../src/main/docs/resource_access_sequence.png     |  Bin 0 -> 38693 bytes
 .../src/main/docs/resource_access_sequence.wsd     |   25 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_01.diag   |    6 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_01.svg    |   32 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_02.diag   |   18 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_02.svg    |   79 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_03.diag   |   31 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_03.svg    |  143 ++
 .../aaa/aaa-authn-api/src/main/docs/sssd_04.diag   |   25 +
 .../aaa/aaa-authn-api/src/main/docs/sssd_04.svg    |  100 ++
 .../aaa/aaa-authn-api/src/main/docs/sssd_05.svg    |  613 +++++++
 .../src/main/docs/sssd_auth_sequence.png           |  Bin 0 -> 39322 bytes
 .../src/main/docs/sssd_auth_sequence.wsd           |   23 +
 .../src/main/docs/sssd_configuration.rst           | 1687 ++++++++++++++++++++
 .../org/opendaylight/aaa/api/Authentication.java   |   26 +
 .../aaa/api/AuthenticationException.java           |   31 +
 .../aaa/api/AuthenticationService.java             |   42 +
 .../main/java/org/opendaylight/aaa/api/Claim.java  |   56 +
 .../java/org/opendaylight/aaa/api/ClaimAuth.java   |   37 +
 .../org/opendaylight/aaa/api/ClientService.java    |   20 +
 .../org/opendaylight/aaa/api/CredentialAuth.java   |   28 +
 .../java/org/opendaylight/aaa/api/Credentials.java |   15 +
 .../opendaylight/aaa/api/IDMStoreException.java    |   24 +
 .../org/opendaylight/aaa/api/IDMStoreUtil.java     |   40 +
 .../java/org/opendaylight/aaa/api/IIDMStore.java   |   72 +
 .../java/org/opendaylight/aaa/api/IdMService.java  |   39 +
 .../opendaylight/aaa/api/PasswordCredentials.java  |   20 +
 .../org/opendaylight/aaa/api/SHA256Calculator.java |   74 +
 .../java/org/opendaylight/aaa/api/TokenAuth.java   |   37 +
 .../java/org/opendaylight/aaa/api/TokenStore.java  |   25 +
 .../java/org/opendaylight/aaa/api/model/Claim.java |   60 +
 .../org/opendaylight/aaa/api/model/Domain.java     |   86 +
 .../org/opendaylight/aaa/api/model/Domains.java    |   34 +
 .../java/org/opendaylight/aaa/api/model/Grant.java |   86 +
 .../org/opendaylight/aaa/api/model/Grants.java     |   35 +
 .../org/opendaylight/aaa/api/model/IDMError.java   |   61 +
 .../java/org/opendaylight/aaa/api/model/Role.java  |   86 +
 .../java/org/opendaylight/aaa/api/model/Roles.java |   34 +
 .../java/org/opendaylight/aaa/api/model/User.java  |  126 ++
 .../org/opendaylight/aaa/api/model/UserPwd.java    |   40 +
 .../java/org/opendaylight/aaa/api/model/Users.java |   34 +
 .../org/opendaylight/aaa/api/model/Version.java    |   49 +
 odl-aaa-moon/aaa/aaa-authn-basic/pom.xml           |   76 +
 .../java/org/opendaylight/aaa/basic/Activator.java |   31 +
 .../org/opendaylight/aaa/basic/HttpBasicAuth.java  |  129 ++
 .../opendaylight/aaa/basic/HttpBasicAuthTest.java  |  102 ++
 odl-aaa-moon/aaa/aaa-authn-federation/pom.xml      |  132 ++
 .../org/opendaylight/aaa/federation/Activator.java |   51 +
 .../aaa/federation/ClaimAuthFilter.java            |  249 +++
 .../aaa/federation/FederationConfiguration.java    |   95 ++
 .../aaa/federation/FederationEndpoint.java         |  149 ++
 .../aaa/federation/ServiceLocator.java             |   83 +
 .../opendaylight/aaa/federation/SssdFilter.java    |  151 ++
 .../OSGI-INF/metatype/metatype.properties          |   11 +
 .../main/resources/OSGI-INF/metatype/metatype.xml  |   19 +
 .../src/main/resources/WEB-INF/web.xml             |   34 +
 .../src/main/resources/federation.cfg              |    3 +
 .../aaa/federation/FederationEndpointTest.java     |  121 ++
 odl-aaa-moon/aaa/aaa-authn-keystone/pom.xml        |  106 ++
 .../org/opendaylight/aaa/keystone/Activator.java   |   34 +
 .../aaa/keystone/KeystoneTokenAuth.java            |   39 +
 .../aaa-authn-mdsal-api/pom.xml                    |   99 ++
 .../src/main/yang/aaa-authn-model.yang             |  154 ++
 .../aaa-authn-mdsal-config/pom.xml                 |   40 +
 .../src/main/resources/initial/08-authn-config.xml |   43 +
 .../aaa-authn-mdsal-store-impl/pom.xml             |  169 ++
 .../aaa/authn/mdsal/store/AuthNStore.java          |  263 +++
 .../aaa/authn/mdsal/store/DataEncrypter.java       |  101 ++
 .../aaa/authn/mdsal/store/IDMMDSALStore.java       |  483 ++++++
 .../aaa/authn/mdsal/store/IDMObject2MDSAL.java     |  224 +++
 .../aaa/authn/mdsal/store/IDMStore.java            |  182 +++
 .../aaa/authn/mdsal/store/util/AuthNStoreUtil.java |  140 ++
 .../mdsal/store/rev141031/AuthNStoreModule.java    |   90 ++
 .../store/rev141031/AuthNStoreModuleFactory.java   |   46 +
 .../src/main/yang/aaa-authn-mdsal-store-cfg.yang   |   77 +
 .../authn/mdsal/store/DataBrokerReadMocker.java    |  112 ++
 .../aaa/authn/mdsal/store/DataEncrypterTest.java   |   38 +
 .../aaa/authn/mdsal/store/IDMStoreTest.java        |  175 ++
 .../aaa/authn/mdsal/store/IDMStoreTestUtil.java    |  181 +++
 .../aaa/authn/mdsal/store/MDSALConvertTest.java    |   78 +
 .../authn/mdsal/store/util/AuthNStoreUtilTest.java |   88 +
 odl-aaa-moon/aaa/aaa-authn-mdsal-store/pom.xml     |   22 +
 odl-aaa-moon/aaa/aaa-authn-sssd/pom.xml            |   88 +
 .../java/org/opendaylight/aaa/sssd/Activator.java  |   28 +
 .../org/opendaylight/aaa/sssd/SssdClaimAuth.java   |  220 +++
 odl-aaa-moon/aaa/aaa-authn-store/pom.xml           |  100 ++
 .../java/org/opendaylight/aaa/store/Activator.java |   45 +
 .../opendaylight/aaa/store/DefaultTokenStore.java  |  154 ++
 .../OSGI-INF/metatype/metatype.properties          |   14 +
 .../main/resources/OSGI-INF/metatype/metatype.xml  |   22 +
 .../aaa-authn-store/src/main/resources/tokens.cfg  |    4 +
 .../aaa/store/DefaultTokenStoreTest.java           |   66 +
 odl-aaa-moon/aaa/aaa-authn-sts/pom.xml             |  112 ++
 .../java/org/opendaylight/aaa/sts/Activator.java   |  207 +++
 .../aaa/sts/AnonymousPasswordValidator.java        |   30 +
 .../aaa/sts/AnonymousRefreshTokenValidator.java    |   29 +
 .../org/opendaylight/aaa/sts/OAuthRequest.java     |   42 +
 .../org/opendaylight/aaa/sts/ServiceLocator.java   |  141 ++
 .../org/opendaylight/aaa/sts/TokenAuthFilter.java  |  148 ++
 .../org/opendaylight/aaa/sts/TokenEndpoint.java    |  242 +++
 .../src/main/resources/WEB-INF/web.xml             |   23 +
 .../java/org/opendaylight/aaa/sts/RestFixture.java |   34 +
 .../org/opendaylight/aaa/sts/TokenAuthTest.java    |   94 ++
 .../opendaylight/aaa/sts/TokenEndpointTest.java    |  164 ++
 odl-aaa-moon/aaa/aaa-authn/pom.xml                 |  103 ++
 .../main/java/org/opendaylight/aaa/Activator.java  |   51 +
 .../opendaylight/aaa/AuthenticationBuilder.java    |  122 ++
 .../opendaylight/aaa/AuthenticationManager.java    |   77 +
 .../java/org/opendaylight/aaa/ClaimBuilder.java    |  160 ++
 .../java/org/opendaylight/aaa/ClientManager.java   |   88 +
 .../main/java/org/opendaylight/aaa/EqualUtil.java  |   42 +
 .../java/org/opendaylight/aaa/HashCodeUtil.java    |  104 ++
 .../aaa/PasswordCredentialBuilder.java             |   87 +
 .../org/opendaylight/aaa/SecureBlockingQueue.java  |  258 +++
 .../OSGI-INF/metatype/metatype.properties          |   12 +
 .../main/resources/OSGI-INF/metatype/metatype.xml  |   16 +
 .../aaa/aaa-authn/src/main/resources/authn.cfg     |    2 +
 .../aaa/AuthenticationBuilderTest.java             |  129 ++
 .../aaa/AuthenticationManagerTest.java             |  133 ++
 .../org/opendaylight/aaa/ClaimBuilderTest.java     |  208 +++
 .../org/opendaylight/aaa/ClientManagerTest.java    |   70 +
 .../opendaylight/aaa/PasswordCredentialTest.java   |   39 +
 .../opendaylight/aaa/SecureBlockingQueueTest.java  |  191 +++
 .../aaa/aaa-authz/aaa-authz-config/pom.xml         |   43 +
 .../src/main/resources/initial/08-authz-config.xml |   60 +
 odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/pom.xml |   95 ++
 .../src/main/yang/authorization-schema.yang        |  190 +++
 .../aaa-authz/aaa-authz-restconf-config/pom.xml    |   43 +
 .../main/resources/initial/09-rest-connector.xml   |   42 +
 .../aaa/aaa-authz/aaa-authz-service/pom.xml        |  152 ++
 .../aaa/authz/srv/AuthzBrokerImpl.java             |  150 ++
 .../aaa/authz/srv/AuthzConsumerContextImpl.java    |   46 +
 .../authz/srv/AuthzDataReadWriteTransaction.java   |  129 ++
 .../aaa/authz/srv/AuthzDomDataBroker.java          |  100 ++
 .../aaa/authz/srv/AuthzProviderContextImpl.java    |   47 +
 .../aaa/authz/srv/AuthzReadOnlyTransaction.java    |   69 +
 .../aaa/authz/srv/AuthzServiceImpl.java            |  121 ++
 .../aaa/authz/srv/AuthzWriteOnlyTransaction.java   |  103 ++
 .../yang/config/aaa_authz/srv/AuthzSrvModule.java  |   76 +
 .../aaa_authz/srv/AuthzSrvModuleFactory.java       |   53 +
 .../src/main/yang/aaa-authz-service-impl.yang      |  115 ++
 .../authz/srv/AuthzConsumerContextImplTest.java    |   46 +
 odl-aaa-moon/aaa/aaa-authz/pom.xml                 |   23 +
 odl-aaa-moon/aaa/aaa-credential-store-api/pom.xml  |   22 +
 .../src/main/yang/credential-model.yang            |   47 +
 odl-aaa-moon/aaa/aaa-h2-store/.gitignore           |    2 +
 odl-aaa-moon/aaa/aaa-h2-store/pom.xml              |  160 ++
 .../opendaylight/aaa/h2/config/IdmLightConfig.java |  133 ++
 .../aaa/h2/persistence/AbstractStore.java          |  187 +++
 .../aaa/h2/persistence/DomainStore.java            |  166 ++
 .../aaa/h2/persistence/GrantStore.java             |  158 ++
 .../opendaylight/aaa/h2/persistence/H2Store.java   |  316 ++++
 .../opendaylight/aaa/h2/persistence/RoleStore.java |  151 ++
 .../aaa/h2/persistence/StoreException.java         |   29 +
 .../opendaylight/aaa/h2/persistence/UserStore.java |  202 +++
 .../authn/h2/store/rev151128/AAAH2StoreModule.java |   49 +
 .../store/rev151128/AAAH2StoreModuleFactory.java   |   29 +
 .../resources/initial/08-aaa-h2-store-config.xml   |   26 +
 .../aaa-h2-store/src/main/yang/aaa-h2-store.yang   |   28 +
 .../aaa/h2/persistence/DomainStoreTest.java        |   76 +
 .../aaa/h2/persistence/GrantStoreTest.java         |   76 +
 .../aaa/h2/persistence/H2StoreTest.java            |  187 +++
 .../aaa/h2/persistence/RoleStoreTest.java          |   76 +
 .../aaa/h2/persistence/UserStoreTest.java          |   79 +
 odl-aaa-moon/aaa/aaa-idmlight/pom.xml              |  229 +++
 .../opendaylight/aaa/idm/IdmLightApplication.java  |   57 +
 .../org/opendaylight/aaa/idm/IdmLightProxy.java    |  208 +++
 .../org/opendaylight/aaa/idm/StoreBuilder.java     |  118 ++
 .../opendaylight/aaa/idm/rest/DomainHandler.java   |  591 +++++++
 .../org/opendaylight/aaa/idm/rest/RoleHandler.java |  228 +++
 .../org/opendaylight/aaa/idm/rest/UserHandler.java |  420 +++++
 .../opendaylight/aaa/idm/rest/VersionHandler.java  |   46 +
 .../idmlight/rev151204/AAAIDMLightModule.java      |   90 ++
 .../rev151204/AAAIDMLightModuleFactory.java        |   29 +
 .../src/main/resources/WEB-INF/web.xml             |   77 +
 .../aaa/aaa-idmlight/src/main/resources/idmtool.py |  255 +++
 .../resources/initial/08-aaa-idmlight-config.xml   |   26 +
 .../aaa-idmlight/src/main/yang/aaa-idmlight.yang   |   28 +
 .../aaa/idm/persistence/PasswordHashTest.java      |   93 ++
 .../aaa/idm/rest/test/DomainHandlerTest.java       |  130 ++
 .../aaa/idm/rest/test/HandlerTest.java             |   38 +
 .../aaa/idm/rest/test/IDMTestStore.java            |  271 ++++
 .../aaa/idm/rest/test/RoleHandlerTest.java         |   95 ++
 .../aaa/idm/rest/test/UserHandlerTest.java         |   96 ++
 odl-aaa-moon/aaa/aaa-idmlight/tests/cleardb.sh     |    5 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/domain.json    |    5 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/domain2.json   |    5 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/grant.json     |    4 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/grant2.json    |    4 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/result.json    |    1 +
 .../aaa/aaa-idmlight/tests/role-admin.json         |    4 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/role-user.json |    4 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/test.sh        |  308 ++++
 odl-aaa-moon/aaa/aaa-idmlight/tests/user.json      |    7 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/user2.json     |    7 +
 odl-aaa-moon/aaa/aaa-idmlight/tests/userpwd.json   |    4 +
 odl-aaa-moon/aaa/aaa-idp-mapping/pom.xml           |   84 +
 .../org/opendaylight/aaa/idpmapping/Activator.java |   25 +
 .../org/opendaylight/aaa/idpmapping/IdpJson.java   |  248 +++
 .../aaa/idpmapping/InvalidRuleException.java       |   35 +
 .../aaa/idpmapping/InvalidTypeException.java       |   35 +
 .../aaa/idpmapping/InvalidValueException.java      |   35 +
 .../opendaylight/aaa/idpmapping/RuleProcessor.java | 1368 ++++++++++++++++
 .../aaa/idpmapping/StatementErrorException.java    |   35 +
 .../org/opendaylight/aaa/idpmapping/Token.java     |  401 +++++
 .../aaa/idpmapping/UndefinedValueException.java    |   34 +
 .../aaa/idpmapping/RuleProcessorTest.java          |  130 ++
 .../org/opendaylight/aaa/idpmapping/TokenTest.java |   66 +
 odl-aaa-moon/aaa/aaa-shiro-act/pom.xml             |   84 +
 .../org/opendaylight/aaa/shiroact/Activator.java   |   51 +
 .../opendaylight/aaa/shiroact/ActivatorTest.java   |   25 +
 odl-aaa-moon/aaa/aaa-shiro/pom.xml                 |  169 ++
 .../java/org/opendaylight/aaa/shiro/Activator.java |   45 +
 .../org/opendaylight/aaa/shiro/ServiceProxy.java   |   94 ++
 .../aaa/shiro/accounting/Accounter.java            |   38 +
 .../aaa/shiro/authorization/DefaultRBACRules.java  |   78 +
 .../aaa/shiro/authorization/RBACRule.java          |  170 ++
 .../opendaylight/aaa/shiro/filters/AAAFilter.java  |   72 +
 .../aaa/shiro/filters/AAAShiroFilter.java          |   51 +
 .../aaa/shiro/filters/AuthenticationListener.java  |   52 +
 .../shiro/filters/AuthenticationTokenUtils.java    |  129 ++
 .../aaa/shiro/filters/MoonOAuthFilter.java         |  186 +++
 .../shiro/filters/ODLHttpAuthenticationFilter.java |   78 +
 .../opendaylight/aaa/shiro/moon/MoonPrincipal.java |  160 ++
 .../aaa/shiro/moon/MoonTokenEndpoint.java          |   30 +
 .../opendaylight/aaa/shiro/realm/MoonRealm.java    |   99 ++
 .../aaa/shiro/realm/ODLJndiLdapRealm.java          |  315 ++++
 .../aaa/shiro/realm/ODLJndiLdapRealmAuthNOnly.java |  102 ++
 .../opendaylight/aaa/shiro/realm/RadiusRealm.java  |   37 +
 .../opendaylight/aaa/shiro/realm/TACACSRealm.java  |   38 +
 .../aaa/shiro/realm/TokenAuthRealm.java            |  369 +++++
 .../aaa/shiro/web/env/KarafIniWebEnvironment.java  |  125 ++
 .../aaa-shiro/src/main/resources/WEB-INF/web.xml   |   48 +
 .../aaa/aaa-shiro/src/main/resources/shiro.ini     |  106 ++
 .../opendaylight/aaa/shiro/ServiceProxyTest.java   |   45 +
 .../org/opendaylight/aaa/shiro/TestAppender.java   |   67 +
 .../shiro/authorization/DefaultRBACRulesTest.java  |   43 +
 .../aaa/shiro/authorization/RBACRuleTest.java      |  106 ++
 .../shiro/filters/AuthenticationListenerTest.java  |   72 +
 .../filters/AuthenticationTokenUtilsTest.java      |  124 ++
 .../aaa/shiro/realm/ODLJndiLdapRealmTest.java      |  246 +++
 .../aaa/shiro/realm/TokenAuthRealmTest.java        |  139 ++
 .../shiro/web/env/KarafIniWebEnvironmentTest.java  |   76 +
 .../aaa-shiro/src/test/resources/logback-test.xml  |   21 +
 odl-aaa-moon/aaa/artifacts/pom.xml                 |  231 +++
 odl-aaa-moon/aaa/commons/docs/AuthNusecases.vsd    |  Bin 0 -> 206336 bytes
 odl-aaa-moon/aaa/commons/docs/direct_authn.png     |  Bin 0 -> 22058 bytes
 odl-aaa-moon/aaa/commons/docs/federated_authn1.png |  Bin 0 -> 36542 bytes
 odl-aaa-moon/aaa/commons/docs/federated_authn2.png |  Bin 0 -> 35203 bytes
 odl-aaa-moon/aaa/commons/federation/README         |  271 ++++
 .../federation/idp_mapping_rules.json.example      |   30 +
 .../aaa/commons/federation/jetty.xml.example       |   85 +
 .../aaa/commons/federation/my_app.conf.example     |   31 +
 .../AAA_AuthZ_MDSAL.json.postman_collection        |   77 +
 odl-aaa-moon/aaa/distribution-karaf/pom.xml        |  291 ++++
 odl-aaa-moon/aaa/features/api/pom.xml              |   91 ++
 .../features/api/src/main/features/features.xml    |   21 +
 odl-aaa-moon/aaa/features/authn/pom.xml            |  300 ++++
 .../features/authn/src/main/features/features.xml  |  249 +++
 odl-aaa-moon/aaa/features/authz/pom.xml            |  101 ++
 .../features/authz/src/main/features/features.xml  |   31 +
 odl-aaa-moon/aaa/features/pom.xml                  |   19 +
 odl-aaa-moon/aaa/features/shiro/pom.xml            |  179 +++
 .../features/shiro/src/main/features/features.xml  |   41 +
 odl-aaa-moon/aaa/parent/pom.xml                    |  278 ++++
 odl-aaa-moon/aaa/pom.xml                           |   50 +
 277 files changed, 30298 insertions(+)
 create mode 100644 odl-aaa-moon/aaa/.gitignore
 create mode 100644 odl-aaa-moon/aaa/README.md
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/Makefile
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.png
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.ucls
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.png
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.wsd
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.png
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.wsd
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.png
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.wsd
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.diag
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.svg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.diag
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.svg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.diag
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.svg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.diag
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.svg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_05.svg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.png
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.wsd
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_configuration.rst
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Authentication.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationService.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Claim.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClaimAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClientService.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/CredentialAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Credentials.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreUtil.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IIDMStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IdMService.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/PasswordCredentials.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/SHA256Calculator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Claim.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domain.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domains.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grant.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grants.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/IDMError.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Role.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Roles.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/User.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/UserPwd.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Users.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Version.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-basic/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/HttpBasicAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-basic/src/test/java/org/opendaylight/aaa/basic/HttpBasicAuthTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ClaimAuthFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationConfiguration.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationEndpoint.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ServiceLocator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/SssdFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.properties
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/WEB-INF/web.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/federation.cfg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-federation/src/test/java/org/opendaylight/aaa/federation/FederationEndpointTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-keystone/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/KeystoneTokenAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/src/main/yang/aaa-authn-model.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/src/main/resources/initial/08-authn-config.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/AuthNStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMMDSALStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMObject2MDSAL.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtil.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModule.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModuleFactory.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/yang/aaa-authn-mdsal-store-cfg.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataBrokerReadMocker.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypterTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTestUtil.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/MDSALConvertTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtilTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-mdsal-store/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sssd/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/SssdClaimAuth.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/tokens.cfg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousPasswordValidator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousRefreshTokenValidator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/OAuthRequest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/ServiceLocator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/main/resources/WEB-INF/web.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/RestFixture.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenAuthTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenEndpointTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationBuilder.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationManager.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClaimBuilder.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClientManager.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/EqualUtil.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/HashCodeUtil.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/PasswordCredentialBuilder.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/SecureBlockingQueue.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.properties
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/main/resources/authn.cfg
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationBuilderTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationManagerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClaimBuilderTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClientManagerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/PasswordCredentialTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/SecureBlockingQueueTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/src/main/resources/initial/08-authz-config.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/src/main/yang/authorization-schema.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/src/main/resources/initial/09-rest-connector.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-authz/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-credential-store-api/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-credential-store-api/src/main/yang/credential-model.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/.gitignore
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/config/IdmLightConfig.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/DomainStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/GrantStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/H2Store.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/RoleStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/StoreException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/UserStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModule.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModuleFactory.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/resources/initial/08-aaa-h2-store-config.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/main/yang/aaa-h2-store.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/DomainStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/GrantStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/H2StoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/RoleStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/UserStoreTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightApplication.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightProxy.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/StoreBuilder.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/DomainHandler.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/RoleHandler.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/UserHandler.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/VersionHandler.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModule.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModuleFactory.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/WEB-INF/web.xml
 create mode 100755 odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/idmtool.py
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/initial/08-aaa-idmlight-config.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/main/yang/aaa-idmlight.yang
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/persistence/PasswordHashTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/DomainHandlerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/HandlerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/IDMTestStore.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/RoleHandlerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/UserHandlerTest.java
 create mode 100755 odl-aaa-moon/aaa/aaa-idmlight/tests/cleardb.sh
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/domain.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/domain2.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/grant.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/grant2.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/result.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/role-admin.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/role-user.json
 create mode 100755 odl-aaa-moon/aaa/aaa-idmlight/tests/test.sh
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/user.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/user2.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idmlight/tests/userpwd.json
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/IdpJson.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidRuleException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidTypeException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidValueException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/RuleProcessor.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/StatementErrorException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Token.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/UndefinedValueException.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/RuleProcessorTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/TokenTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro-act/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/pom.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/Activator.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/accounting/Accounter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRules.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/RBACRule.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonPrincipal.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonTokenEndpoint.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/MoonRealm.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealm.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmAuthNOnly.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/RadiusRealm.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TACACSRealm.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironment.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/resources/WEB-INF/web.xml
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/main/resources/shiro.ini
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/TestAppender.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRulesTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/RBACRuleTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationListenerTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtilsTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealmTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironmentTest.java
 create mode 100644 odl-aaa-moon/aaa/aaa-shiro/src/test/resources/logback-test.xml
 create mode 100644 odl-aaa-moon/aaa/artifacts/pom.xml
 create mode 100644 odl-aaa-moon/aaa/commons/docs/AuthNusecases.vsd
 create mode 100644 odl-aaa-moon/aaa/commons/docs/direct_authn.png
 create mode 100644 odl-aaa-moon/aaa/commons/docs/federated_authn1.png
 create mode 100644 odl-aaa-moon/aaa/commons/docs/federated_authn2.png
 create mode 100644 odl-aaa-moon/aaa/commons/federation/README
 create mode 100644 odl-aaa-moon/aaa/commons/federation/idp_mapping_rules.json.example
 create mode 100644 odl-aaa-moon/aaa/commons/federation/jetty.xml.example
 create mode 100644 odl-aaa-moon/aaa/commons/federation/my_app.conf.example
 create mode 100644 odl-aaa-moon/aaa/commons/postman_examples/AAA_AuthZ_MDSAL.json.postman_collection
 create mode 100644 odl-aaa-moon/aaa/distribution-karaf/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/api/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/api/src/main/features/features.xml
 create mode 100644 odl-aaa-moon/aaa/features/authn/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/authn/src/main/features/features.xml
 create mode 100644 odl-aaa-moon/aaa/features/authz/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/authz/src/main/features/features.xml
 create mode 100644 odl-aaa-moon/aaa/features/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/shiro/pom.xml
 create mode 100644 odl-aaa-moon/aaa/features/shiro/src/main/features/features.xml
 create mode 100644 odl-aaa-moon/aaa/parent/pom.xml
 create mode 100644 odl-aaa-moon/aaa/pom.xml

(limited to 'odl-aaa-moon')

diff --git a/odl-aaa-moon/aaa/.gitignore b/odl-aaa-moon/aaa/.gitignore
new file mode 100644
index 00000000..b8938691
--- /dev/null
+++ b/odl-aaa-moon/aaa/.gitignore
@@ -0,0 +1,26 @@
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# IDE Files
+.classpath
+.project
+.settings/
+.idea
+
+# Generated stuff
+target/
+META-INF/
+*.iml
+.DS_Store
+yang-gen-sal/
+yang-gen-config/
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
diff --git a/odl-aaa-moon/aaa/README.md b/odl-aaa-moon/aaa/README.md
new file mode 100644
index 00000000..dc748ef1
--- /dev/null
+++ b/odl-aaa-moon/aaa/README.md
@@ -0,0 +1,62 @@
+## Welcome to the OPNFV/Opendaylight AAA Project!
+
+This project is aimed at providing a flexible, pluggable framework with out-of-the-box capabilities for:
+
+* *Authentication*:  Means to authenticate the identity of both human and machine users (direct or federated).
+* *Authorization*:  Means to authorize human or machine user access to resources including RPCs, notification subscriptions, and subsets of the datatree.
+* *Accounting*:  Means to record and access the records of human or machine user access to resources including RPCs, notifications, and subsets of the datatree
+
+
+
+### Building
+
+*Prerequisite:*  The followings are required for building AAA:
+
+- Maven 3
+- Java 7
+
+Get the code:
+
+    clone the project with git
+
+Build it:
+
+    cd aaa && mvn clean install -DskipTests
+
+### Export Moon information
+
+export MOON_SERVER_ADDR=192.168.56.101
+export MOON_SERVER_PORT=5000
+
+
+### Installing
+
+AAA installs into an existing Opendaylight controller Karaf installation.  If you don't have an Opendaylight installation, please refer to this [page](https://wiki.opendaylight.org/view/OpenDaylight_Controller:Installation).
+
+Start the controller Karaf container:
+    cd distribution-karaf/target/assembly/
+	bin/karaf
+
+Install AAA AuthN features:
+
+	feature:install odl-aaa-shiro
+
+### Running
+
+Once the installation finishes, one can authenticates with the Opendaylight controller by presenting a username/password and a domain name (scope) to be logged into:
+
+    curl -s -d 'grant_type=password&username=admin&password=admin' http://<controller>:<port>/moon/token
+    
+    curl -s -d 'grant_type=password&username=admin&password=password' http://localhost:8080/moon/token
+
+Upon successful authentication, the controller returns an access token with a configurable expiration in seconds, something similar to the followings:
+
+    {"expires_in":3600,"token_type":"Bearer","access_token":"d772d85e-34c7-3099-bea5-cfafd3c747cb"}
+
+The access token can then be used to access protected resources on the controller by passing it along in the standard HTTP Authorization header with the resource request.  Example:
+
+    curl -s -H 'Authorization: Bearer d772d85e-34c7-3099-bea5-cfafd3c747cb' http://<controller>:<port>/restconf/operational/opendaylight-inventory:nodes
+
+Test HTTP Basic Authentication
+
+     curl -u admin:password http://localhost:8080/auth/v1/domains
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/pom.xml b/odl-aaa-moon/aaa/aaa-authn-api/pom.xml
new file mode 100644
index 00000000..97249ace
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-authn-api</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>com.sun.jersey</groupId>
+        <artifactId>jersey-server</artifactId>
+        <scope>provided</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/Makefile b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/Makefile
new file mode 100644
index 00000000..446795b4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/Makefile
@@ -0,0 +1,29 @@
+all: sssd_configuration.html sssd_configuration.pdf mapping.html
+
+
+images = sssd_01.png sssd_02.png sssd_03.png sssd_04.png sssd_05.png
+
+sssd_configuration.html: $(images)
+
+sssd_configuration.pdf: $(images)
+
+%.html: %.rst
+	rst2html $< $@
+
+%.pdf: %.rst
+	rst2pdf --footer='-###Page###-' $< -o $@
+
+%.png: %.svg
+	inkscape -z -e $@ -w 800 $<
+
+sssd_01.svg: sssd_01.diag
+	blockdiag -Tsvg $<
+
+sssd_02.svg: sssd_02.diag
+	blockdiag -Tsvg $<
+
+sssd_03.svg: sssd_03.diag
+	seqdiag -Tsvg $<
+
+sssd_04.svg: sssd_04.diag
+	blockdiag -Tsvg $<
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.png b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.png
new file mode 100644
index 00000000..999a41f9
Binary files /dev/null and b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.png differ
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.ucls b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.ucls
new file mode 100644
index 00000000..68345256
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/class_diagram.ucls
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<class-diagram version="1.1.6" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true" 
+  realizations="true" associations="true" dependencies="true" nesting-relationships="true">  
+  <interface id="1" language="java" name="org.opendaylight.aaa.api.TokenStore" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenStore.java" binary="false" corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="637" y="568"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="2" language="java" name="org.opendaylight.aaa.api.AuthenticationService" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationService.java" binary="false" 
+    corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="385" y="727"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="3" language="java" name="org.opendaylight.aaa.api.CredentialAuth" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/CredentialAuth.java" binary="false" 
+    corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="148" y="94"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="4" language="java" name="org.opendaylight.aaa.api.TokenAuth" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenAuth.java" binary="false" corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="139" y="568"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="5" language="java" name="org.opendaylight.aaa.api.PasswordCredentials" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/PasswordCredentials.java" binary="false" 
+    corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="383" y="218"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="6" language="java" name="org.opendaylight.aaa.api.Credentials" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Credentials.java" binary="false" corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="385" y="93"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="7" language="java" name="org.opendaylight.aaa.api.Authentication" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Authentication.java" binary="false" 
+    corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="386" y="567"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="8" language="java" name="org.opendaylight.aaa.api.ClaimAuth" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClaimAuth.java" binary="false" corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="138" y="386"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <interface id="9" language="java" name="org.opendaylight.aaa.api.Claim" project="aaa-authn-api" 
+    file="/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Claim.java" binary="false" corner="BOTTOM_RIGHT">    
+    <position height="-1" width="-1" x="386" y="386"/>    
+    <display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" accessors="true" 
+      visibility="true">      
+      <attributes public="true" package="true" protected="true" private="false" static="true"/>      
+      <operations public="true" package="true" protected="true" private="false" static="true"/>    
+    </display>  
+  </interface>  
+  <dependency id="10">    
+    <end type="SOURCE" refId="3"/>    
+    <end type="TARGET" refId="6"/>  
+  </dependency>  
+  <dependency id="11">    
+    <end type="SOURCE" refId="2"/>    
+    <end type="TARGET" refId="7"/>  
+  </dependency>  
+  <generalization id="12">    
+    <end type="SOURCE" refId="5"/>    
+    <end type="TARGET" refId="6"/>  
+  </generalization>  
+  <dependency id="13">    
+    <end type="SOURCE" refId="3"/>    
+    <end type="TARGET" refId="9"/>  
+  </dependency>  
+  <generalization id="14">    
+    <end type="SOURCE" refId="7"/>    
+    <end type="TARGET" refId="9"/>  
+  </generalization>  
+  <dependency id="15">    
+    <end type="SOURCE" refId="1"/>    
+    <end type="TARGET" refId="7"/>  
+  </dependency>  
+  <dependency id="16">    
+    <end type="SOURCE" refId="8"/>    
+    <end type="TARGET" refId="9"/>  
+  </dependency>  
+  <dependency id="17">    
+    <end type="SOURCE" refId="4"/>    
+    <end type="TARGET" refId="7"/>  
+  </dependency>  
+  <classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true" 
+    accessors="true" visibility="true">    
+    <attributes public="true" package="true" protected="true" private="false" static="true"/>    
+    <operations public="true" package="true" protected="true" private="false" static="true"/>  
+  </classifier-display>  
+  <association-display labels="true" multiplicity="true"/>
+</class-diagram>
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.png b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.png
new file mode 100644
index 00000000..52d63650
Binary files /dev/null and b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.png differ
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.wsd b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.wsd
new file mode 100644
index 00000000..383d4031
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/credential_auth_sequence.wsd
@@ -0,0 +1,18 @@
+title Credential Authentication Sequence
+
+# This walks through the credential authentication use case where a credential 
+# (typically username/password) is used to authenticate directly with the ODL 
+# controller. 
+
+Client -> ServletContainer: request access token
+note right of Client
+(credentials, scope=domain)
+end note
+ServletContainer -> TokenEndpoint: credentials, domain
+TokenEndpoint -> CredentialAuth: authenticate(Credentials, domain)
+CredentialAuth -> TokenEndpoint: Claim
+note left of CredentialAuth
+(user/domain/roles)
+end note
+TokenEndpoint -> TokenEndpoint: createToken
+TokenEndpoint -> Client: access token
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.png b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.png
new file mode 100644
index 00000000..799cc909
Binary files /dev/null and b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.png differ
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.wsd b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.wsd
new file mode 100644
index 00000000..22d1d916
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/federated_auth_sequence.wsd
@@ -0,0 +1,24 @@
+title Federated Authentication Sequence (w/ Claim Transformation)
+
+# This walks through the federated authentication sequence where a claim from a
+# third-party IdP system is posted to the ODL token endpoint in exchange for an 
+# access token. The claim information is assumed to be in format specific to the 
+# third-party IdP system and assumed to be captured via either Apache environment
+# variables (Servlet attributes) or HTTP headers. 
+
+Client -> ServletContainer: request access token
+note right of Client
+(claim as Apache env/HTTP headers)
+end note
+ServletContainer -> ClaimAuthFilter: Servlet attributes/headers
+loop foreach ClaimAuth
+    ClaimAuthFilter -> ClaimAuth: transform(Map<String, Object> claim)
+    ClaimAuth -> ClaimAuth: transformClaim
+end
+ClaimAuth -> ClaimAuthFilter: Claim
+note left of ClaimAuth
+(user/domain/roles)
+end note
+ClaimAuthFilter --> TokenEndpoint: Claim
+TokenEndpoint -> TokenEndpoint: createToken
+TokenEndpoint -> Client: access token
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst
new file mode 100644
index 00000000..33635502
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst
@@ -0,0 +1,1609 @@
+Operation Model
+===============
+
+The assertions from an IdP are stored in an associative array. A
+sequence of rules are applied, the first rule which returns success is
+considered a match. During the execution of each rule values from the
+assertion can be tested and transformed with the results selectively
+stored in variables local to the rule. If the rule succeeds an
+associative array of mapped values is returned. The mapped values are
+taken from the local variables set during the rule execution. The
+definition of the rules and mapped results are expressed in JSON
+notation.
+
+A rule is somewhat akin to a function in a programming language. It
+starts execution with a set of predefined local variables. It executes
+statements which are grouped together in blocks. Execution continues
+until an `exit`_ statement returning a success/fail result is
+executed or until the last statement is reached which implies
+success. The remaining statements in a block may be skipped via a
+`continue`_ statement which tests a condition, this is equivalent to
+an "if" control flow of logic in a programming language.
+
+Rule execution continues until a rule returns success. Each rule has a
+`mapping`_ associative array bound to it which is a template for the
+transformed result. Upon success the `mapping`_ template for the
+rule is loaded and the local variables from the successful rule are
+used to populate the values in the `mapping`_ template yielding the
+final mapped result.
+
+If no rules returns success authentication fails.
+
+
+Pseudo Code Illustrating Operational Model
+------------------------------------------
+
+::
+
+    mapped = null
+    foreach rule in rules {
+        result = null
+        initialize rule.variables with pre-defined values
+
+        foreach block in rule.statement_blocks {
+            for statement in block.statements {
+                if statement.verb is exit {
+                    result = exit.status
+                    break
+                }
+                elif statement.verb is continue {
+                    break
+                }
+            }
+            if result {
+                break
+            }
+        if result == null {
+            result = success
+        }
+    if result == success {
+        mapped = rule.mapping(rule.variables)
+    }
+    return mapped
+
+
+
+Structure Of Rule Definitions
+=============================
+
+Rules are loaded by the rule processor via a JSON document called a
+rule definition. A definition has an *optional* set of mapping
+templates and a list of rules. Each rule has specifies a mapping
+template and has a list of statement blocks. Each statement block has
+a list of statements.
+
+In pseudo-JSON (JSON does not have comments, the ... ellipsis is a
+place holder):
+
+::
+
+    {
+        "mappings": {
+                        "template1": "{...}",
+                        "template2": "{...}"
+                    },
+        "rules": [
+                     {   # Rule 0. A rule has a mapping or a mapping name
+                         # and a list of statement blocks
+
+                         "mapping": {...},
+                         # -OR-
+                         "mapping_name": "template1",
+
+                         "statement_blocks": [
+                                                 [   # Block 0
+                                                     [statement 0]
+                                                     [statement 1]
+                                                 ],
+                                                 [   # Block 1
+                                                     [statement 0]
+                                                     [statement 1]
+                                                 ],
+
+                                              ]
+                     },
+                     {   # Rule 1 ...
+                     }
+                 ]
+
+    }
+
+Mapping
+-------
+
+A mapping template is used to produce the final associative array of
+name/value pairs. The template is a JSON Object. The value in a
+name/value pair can be a constant or a variable. If the template value
+is a variable the value of the variable is retrieved from the set of
+local variables bound to the rule thereby replacing it in the final
+result.
+
+For example given this mapping template and rule variables in JSON:
+
+template:
+
+::
+
+    {
+        "organization": "BigCorp.com",
+        "user: "$subject",
+        "roles": "$roles"
+    }
+
+local variables:
+
+::
+
+    {
+        "subject": "Sally",
+        "roles": ["user", "admin"]
+    }
+
+The final mapped results would be:
+
+::
+
+    {
+        "organization": "BigCorp.com",
+        "user: "Sally",
+        "roles": ["user", "admin"]
+    }
+
+
+Each rule must bind a mapping template to the rule. The mapping
+template may either be defined directly in the rule via the
+``mapping`` key or referenced by name via the ``mapping_name`` key.
+
+If the ``mapping_name`` is specified the mapping is looked up in a
+table of mapping templates bound to the Rule Processor. Using the name
+of a mapping template is useful when many rules generate the exact
+same template values.
+
+If both ``mapping`` and ``mapping_name`` are defined the locally bound
+``mapping`` takes precedence.
+
+Syntax
+------
+
+The logic for a rule consists of a sequence of statements grouped in
+blocks. A statement is similar to a function call in a programming
+language.
+
+A statement is a list of values the first of which is a verb which
+defines the operation the statement will perform. Think of the
+`verbs`_ as function names or operators. Following the verb are
+parameters which may be constants or variables. If the statement
+assigns a value to a variable left hand side of the assignment (lhs)
+is always the first parameter following the verb in the list of
+statement values.
+
+For example this statement in JSON:
+
+::
+
+    ["split", "$groups", "$assertion[Groups]", ":"]
+
+will assign an array to the variable ``$groups``. It looks up the
+string named ``Groups`` in the assertion which is a colon (:)
+separated list of group names splitting that string on the colon
+character.
+
+Statements **must** be grouped together in blocks. Therefore a rule is
+a sequence of blocks and block is a sequence of statements. The
+purpose of blocks is allow for crude flow of control logic. For
+example this JSON rule has 4 blocks.
+
+::
+
+    [
+        [
+            ["set", $user, ""],
+            ["set", $roles, []]
+        ],
+        [
+            ["in", "UserName", "$assertion"],
+            ["continue", "if_not_success"],
+            ["set", "$user", "$assertion[UserName"],
+        ],
+        [
+            ["in", "subject", "$assertion"],
+            ["continue", "if_not_success"],
+            ["set", "$user", "$assertion[subject]"],
+        ],
+        [
+            ["length", "$temp", "$user"],
+            ["compare", "$temp", ">", 0],
+            ["exit", "rule_fails", "if_not_success"]
+            ["append" "$roles", "unprivileged"]
+        ]
+    ]
+
+The rule will succeed if either ``UserName`` or ``subject`` is defined
+in the assertion and if so the local variable ``$user`` will be set to
+the value found in the assertion and the "unprivileged" role will be
+appended to the roles array.
+
+The first block performs initialization. The second block tests to see
+if the assertion has the key ``UserName`` if not execution continues
+at the next block otherwise the value of UserName in the assertion is
+copied into the variable ``$user``. The third block performs a similar
+operation looking for a ``subject`` in the assertion. The fourth block
+checks to see if the ``$user`` variable is empty, if it is empty the
+rule fails because it didn't find either a ``UserName`` nor a
+``subject`` in the assertion. If ``$user`` is not empty the
+"unprivileged" role is appended and the rule succeeds.
+
+Data Types
+----------
+
+There are 7 supported types which equate to the types available in
+JSON. At the time of this writing there are 2 implementations of this
+Mapping specification, one in Python and one in Java. This table
+illustrates how each data type is represented. The first two columns
+are definitions from an abstract specification. The JSON column
+enumerates the data type JSON supports.  The Mapping column lists the
+7 enumeration names used by the Mapping implemenation in each
+language. The following columns list the concrete data type used in
+that language.
+
++-----------+------------+--------------------+---------------------+
+|  JSON     |  Mapping   | Python             |       Java          |
++===========+============+====================+=====================+
+|  object   |  MAP       | dict               | Map<String, Object> |
++-----------+------------+--------------------+---------------------+
+|  array    |  ARRAY     | list               | List<Object>        |
++-----------+------------+--------------------+---------------------+
+|  string   |  STRING    | unicode (Python 2) | String              |
+|           |            +--------------------+                     |
+|           |            | str (Python 3)     |                     |
++-----------+------------+--------------------+---------------------+
+|           |  INTEGER   | int                | Long                |
+|  number   +------------+--------------------+---------------------+
+|           |  REAL      | float              | Double              |
++-----------+------------+--------------------+---------------------+
+|  true     |            |                    |                     |
++-----------+  BOOLEAN   | bool               | Boolean             |
+|  false    |            |                    |                     |
++-----------+------------+--------------------+---------------------+
+|  null     |  NULL      | None               | null                |
++-----------+------------+--------------------+---------------------+
+
+
+Rule Debugging and Documentation
+--------------------------------
+
+If the rule processor reports an error or if you're debugging your
+rules by enabling DEBUG log tracing then you must be able to correlate
+the reported statement to where it appears in your rule JSON source. A
+message will always identify a statement by the rule number, block
+number within that rule and the statement number within that
+block. However once your rules become moderately complex it will
+become increasingly difficult to identify a statement by counting
+rules, blocks and statements.
+
+A better approach is to tag rules and blocks with a name or other
+identifying string. You can set the `Reserved Variables`_
+``rule_name`` and ``block_name`` to a string of your choice. These
+strings will be reported in all messages along with the rule, block
+and statement numbers.
+
+JSON does not permit comments, as such you cannot include explanatory
+comments next to your rules, blocks and statements in the JSON
+source. The ``rule_name`` and ``block_name`` can serve a similar
+purpose. By putting assignments to these variables as the first
+statement in a block you'll both document your rules and be able to
+identify specific statements in log messages.
+
+During rule execution the ``rule_name`` and ``block_name`` are
+initialized to the empty string at the beginning of each rule and
+block respectively.
+
+The above example is augmented to include this information. The rule
+name is set in the first statement in the first block.
+
+::
+
+    [
+        [
+            ["set", "$rule_name", "Must have UserName or subject"],
+            ["set", "block_name", "Initialization"],
+            ["set", $user, ""],
+            ["set", $roles, []]
+        ],
+        [
+            ["set", "block_name", "Test for UserName, set $user"],
+            ["in", "UserName", "$assertion"],
+            ["continue", "if_not_success"],
+            ["set", "$user", "$assertion[UserName"],
+        ],
+        [
+            ["set", "block_name", "Test for subject, set $user"],
+            ["in", "subject", "$assertion"],
+            ["continue", "if_not_success"],
+            ["set", "$user", "$assertion[subject]"],
+        ],
+        [
+            ["set", "block_name", "If not $user fail, else append unprivileged to roles"],
+            ["length", "$temp", "$user"],
+            ["compare", "$temp", ">", 0],
+            ["exit", "rule_fails", "if_not_success"]
+            ["append" "$roles", "unprivileged"]
+        ]
+    ]
+
+
+
+
+Variables
+---------
+
+
+Variables always begin with a dollar sign ($) and are followed by an
+identifier which is any alpha character followed by zero or more
+alphanumeric or underscore characters. The variable may optionally be
+delimited with braces ({}) to separate the variable from surrounding
+text. Three types of variables are supported:
+
+* scalar
+* array (indexed by zero based integer)
+* associative array (indexed by string)
+
+Both arrays and associative arrays use square brackets ([]) to specify
+a member of the array. Examples of variable usage:
+
+::
+
+    $name
+    ${name}
+    $groups[0]
+    ${groups[0]}
+    $properties[key]
+    ${properties[key]}
+
+An array or an associative array may be referenced by it's base name
+(omitting the indexing brackets). For example the associative array
+array named "properties" is referenced using it's base name
+``$properties`` but if you want to access a member of the "properties"
+associative array named "duration" you would do this ``$properties[duration]``
+
+This is not a general purpose language with full expression
+syntax. Only one level of variable lookup is supported. Therefore
+compound references like this
+
+::
+
+    $properties[$groups[2]]
+
+will not work.
+
+
+Escaping
+^^^^^^^^
+
+If you need to include a dollar sign in a string (where it is
+immediately followed by either an identifier or a brace and identifier)
+and do not want to have it be interpreted as representing a variable
+you must escape the dollar sign with a backslash, for example
+"$amount" is interpreted as the variable ``amount`` but "\\$amount"
+is interpreted as the string "$amount" .
+
+
+Reserved Variables
+------------------
+
+A rule has the following reserved variables:
+
+assertion
+    The current assertion values from the federated IdP. It is a
+    dictionary of key/value pairs.
+
+regexp_array
+    The regular expression groups from the last successful regexp match
+    indexed by number. Group 0 is the entire match. Groups 1..n are
+    the corresponding parenthesized group counting from the left. For
+    example regexp_array[1] is the first group.
+
+regexp_map
+    The regular expression groups from the last successful regexp match
+    indexed by group name.
+
+rule_number
+    The zero based index of the currently executing rule.
+
+rule_name
+    The name of the currently executing rule. If the rule name has not
+    been set it will be the empty string.
+
+block_number
+    The zero based index of the currently executing block within the
+    currently executing rule.
+
+block_name
+    The name of the currently executing block. If the block name has not
+    been set it will be the empty string.
+
+
+statement_number
+    The zero based index of the currently executing statement within the
+    currently executing block.
+
+
+Examples
+========
+
+Split a fully qualified username into user and realm components
+---------------------------------------------------------------
+
+It's common for some IdP's to return a fully qualified username
+(e.g. principal or subject). The fully qualified username is the
+concatenation of the user name, separator and realm name. A common
+separator is the @ character. In this example lets say the fully
+qualified username is ``bob@example.com`` and you want to return the
+user and realm as independent values in your mapped result. The
+username appears in the assertion as the value ``Principal``.
+
+Our strategy will be to use a regular expression identify the user and
+realm components and then assign them to local variables which will
+then populate the mapped result.
+
+The mapping in JSON is:
+
+::
+
+    {
+        "user": "$username",
+        "realm": "$domain"
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "Principal": "bob@example.com"
+    }
+
+Our rule is:
+
+::
+
+    [
+        [
+            ["in", "Principal", "assertion"],
+            ["exit", "rule_fails", "if_not_success"],
+            ["regexp", "$assertion[Principal]", (?P<username>\\w+)@(?P<domain>.+)"],
+            ["set", "$username", "$regexp_map[username]"],
+            ["set", "$domain", "$regexp_map[domain]"],
+            ["exit, "rule_succeeds", "always"]
+        ]
+    ]
+
+Rule explanation:
+
+Block 0:
+
+0. Test if the assertion contains a Principal value.
+1. Abort the rule if the assertion does not contain a Principal
+   value.
+2. Apply a regular expression the the Principal value. Use named
+   groupings for the username and domain components for clarity.
+3. Assign the regexp group username to the $username local variable.
+4. Assign the regexp group domain to the $domain local variable.
+5. Exit the rule, apply the mapping, return the mapped values. Note, an
+   explicit `exit`_ is not required if there are no further statements
+   in the rule, as is the case here.
+
+The mapped result in JSON is:
+
+::
+
+    {
+        "user": "bob",
+        "realm": "example.com"
+    }
+
+Build a set of roles based on group membership
+----------------------------------------------
+
+Often one wants to grant roles to a user based on their membership in
+certain groups. In this example let's say the assertion contains a
+``Groups`` value which is a colon separated list of group names. Our
+strategy is to split the ``Groups`` assertion value into an array of
+group names. Then we'll test if a specific group is in the groups
+array, if it is we'll add a role. Finally if no roles have been mapped
+we fail. Users in the group "student" will get the role "unprivileged"
+and users in the group "helpdesk" will get the role "admin".
+
+The mapping in JSON is:
+
+::
+
+    {
+        "roles": "$roles",
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "Groups": "student:helpdesk"
+    }
+
+Our rule is:
+
+::
+
+    [
+        [
+            ["in", "Groups", "assertion"],
+            ["exit", "rule_fails", "if_not_success"],
+            ["set", "$roles", []],
+            ["split", "$groups", "$assertion[Groups]", ":"],
+        ],
+        [
+            ["in", "student", "$groups"],
+            ["continue", "if_not_success"],
+            ["append", "$roles", "unprivileged"]
+        ],
+        [
+            ["in", "helpdesk", "$groups"],
+            ["continue", "if_not_success"],
+            ["append", "$roles", "admin"]
+        ],
+        [
+            ["unique", "$roles", "$roles"],
+            ["length", "$temp", "roles"],
+            ["compare", $temp", ">", 0],
+            ["exit", "rule_fails", "if_not_success"]
+        ]
+
+    ]
+
+Rule explanation:
+
+Block 0
+
+0. Test if the assertion contains a Groups value.
+1. Abort the rule if the assertion does not contain a Groups
+   value.
+2. Initialize the $roles variable to an empty array.
+3. Split the colon separated list of group names into an array of
+   individual group names
+
+Block 1
+
+0. Test if "student" is in the $groups array
+1. Exit the block if it's not.
+2. Append "unprivileged" to the $roles array
+
+Block 2
+
+0. Test if "helpdesk" is in the $groups array
+1. Exit the block if it's not.
+2. Append "admin" to the $roles array
+
+Block 3
+
+0. Strip any duplicate roles that might have been appended to the
+   $roles array to assure each role is unique.
+1. Count how many members are in the $roles array, assign the
+   length to the $temp variable.
+2. Test to see if the $roles array had any members.
+3. Fail if no roles had been assigned.
+
+The mapped result in JSON is:
+
+::
+
+    {
+        "roles": ["unprivileged", "admin"]
+    }
+
+However, suppose whatever is receiving your mapped results is not
+expecting an array of roles. Instead it expects a comma separated list
+in a string. To accomplish this add the following statement as the
+last one in the final block:
+
+::
+
+            ["join", "$roles", "$roles", ","]
+
+Then the mapped result will be:
+
+::
+
+    {
+        "roles": "unprivileged,admin"]
+    }
+
+
+
+
+White list certain users and grant them specific roles
+------------------------------------------------------
+
+Suppose you have certain users you always want to unconditionally
+accept and authorize with specific roles. For example if the user is
+"head_of_IT" then assign her the "user" and "admin" roles. Otherwise
+keep processing. The list of white listed users is hard-coded into the
+rule.
+
+The mapping in JSON is:
+
+::
+
+    {
+        "user": $user,
+        "roles": "$roles",
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "UserName": "head_of_IT"
+    }
+
+Our rule in JSON is:
+
+::
+
+    [
+        [
+            ["in", "UserName", "assertion"],
+            ["exit", "rule_fails", "if_not_success"],
+            ["in", "$assertion[UserName]", ["head_of_IT", "head_of_Engineering"]],
+            ["continue", "if_not_success"],
+            ["set", "$user", "$assertion[UserName"]
+            ["set", "$roles", ["user", "admin"]],
+            ["exit", "rule_succeeds", "always"]
+        ],
+        [
+            ...
+        ]
+    ]
+
+Rule explanation:
+
+Block 0
+
+0. Test if the assertion contains a UserName value.
+1. Abort the rule if the assertion does not contain a UserName
+   value.
+2. Test if the user is in the hardcoded list of white listed users.
+3. If the user isn't in the white listed array then exit the block and
+   continue execution at the next block.
+4. Set the $user local variable to $assertion[UserName]
+5. Set the $roles local variable to the hardcoded array containing
+   "user" and "admin"
+6. We're done, unconditionally exit and return the mapped result.
+
+Block 1
+
+0. Further processing
+
+The mapped result in JSON is:
+
+::
+
+    {
+        "user": "head_of_IT",
+        "roles": ["users", "admin"]
+    }
+
+
+Black list certain users
+------------------------
+
+Suppose you have certain users you always want to unconditionally
+deny access to by placing them in a black list. In this example the
+user "BlackHat" will try to gain access. The black list includes the
+users "BlackHat" and "Spook".
+
+The mapping in JSON is:
+
+::
+
+    {
+        "user": $user,
+        "roles": "$roles",
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "UserName": "BlackHat"
+    }
+
+Our rule in JSON is:
+
+::
+
+    [
+        [
+            ["in", "UserName", "assertion"],
+            ["exit", "rule_fails", "if_not_success"],
+            ["in", "$assertion[UserName]", ["BlackHat", "Spook"]],
+            ["exit", "rule_fails", "if_success"]
+        ],
+        [
+            ...
+        ]
+    ]
+
+Rule explanation:
+
+Block 0
+
+0. Test if the assertion contains a UserName value.
+1. Abort the rule if the assertion does not contain a UserName
+   value.
+2. Test if the user is in the hard-coded list of black listed users.
+3. If the test succeeds then immediately abort and return failure.
+
+Block 1
+
+0. Further processing
+
+The mapped result in JSON is:
+
+::
+
+    Null
+
+Format Strings and/or Concatenate Strings
+-----------------------------------------
+
+You can replace variables in a format string using the `interpolate`_
+verb. String concatenation is trivially placing two variables adjacent
+to one another in a format string. Suppose you want to form an email
+address from the username and domain in an assertion.
+
+The mapping in JSON is:
+
+::
+
+    {
+        "email": $email,
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "UserName": "Bob",
+        "Domain": "example.com"
+    }
+
+Our rule in JSON is:
+
+::
+
+    [
+        [
+            ["interpolate", "$email", "$assertion[UserName]@$assertion[Domain]"],
+        ]
+    ]
+
+Rule explanation:
+
+Block 0
+
+0. Replace the variable $assertion[UserName] with it's value and
+   replace the variable $assertion[Domain] with it's value.
+
+The mapped result in JSON is:
+
+::
+
+    {
+        "email": "Bob@example.com",
+    }
+
+
+Note, sometimes it's necessary to utilize braces to separate variables
+from surrounding text by using the brace notation. This can also make
+the format string more readable. Using braces to delimit variables the
+above would be:
+
+::
+
+    [
+        [
+            ["interpolate", "$email", "${assertion[UserName]}@${assertion[Domain]}"],
+        ]
+    ]
+
+
+
+Make associative array lookups case insensitive
+-----------------------------------------------
+
+Many systems treat field names as case insensitive. By default
+associative array indexing is case sensitive. The solution is to lower
+case all the keys in an associative array and then only use lower case
+indices. Suppose you want the assertion associative array to be case
+insensitive.
+
+The mapping in JSON is:
+
+::
+
+    {
+        "user": $user,
+    }
+
+The assertion in JSON is:
+
+::
+
+    {
+        "UserName": "Bob"
+    }
+
+Our rule in JSON is:
+
+::
+
+    [
+        [
+            ["lower", "$assertion", "$assertion"],
+            ["in", "username", "assertion"],
+            ["exit", "rule_fails", "if_not_success"],
+            ["set", "$user", "$assertion[username"]
+        ]
+    ]
+
+Rule explanation:
+
+Block 0
+
+0. Lower case all the keys in the assertion associative array.
+1. Test if the assertion contains a username value.
+2. Abort the rule if the assertion does not contain a username
+   value.
+3. Assign the username value in the assertion to $user
+
+The mapped result in JSON is:
+
+::
+
+    {
+        "user": "Bob",
+    }
+
+
+Verbs
+=====
+
+The following verbs are supported:
+
+* `set`_
+* `length`_
+* `interpolate`_
+* `append`_
+* `unique`_
+* `regexp`_
+* `regexp_replace`_
+* `split`_
+* `join`_
+* `lower`_
+* `upper`_
+* `compare`_
+* `in`_
+* `not_in`_
+* `exit`_
+* `continue`_
+
+Some verbs have a side effects. A verb may set a boolean success/fail
+result which may then be tested with a subsequent verb. For example
+the ``fail`` verb can be used to indicate the rule fails if a prior
+result is either ``success`` or ``not_success``.  The ``regexp`` verb
+which performs a regular expression search on a string stores the
+regular expression sub-matches as a side effect in the variables
+``$regexp_array`` and ``$regexp_map``.
+
+
+Verb Definitions
+================
+
+set
+---
+
+``set $variable value``
+
+$variable
+    The variable being assigned (i.e. lhs)
+
+value
+    The value to assign to the variable (i.e. rhs). The value may be
+    another variable or a constant.
+
+**set** assigns a value to a variable, in other words it's an
+assignment statement.
+
+Examples:
+^^^^^^^^^
+
+Initialize a variable to an empty array.
+
+::
+
+    ["set", "$groups", []]
+
+Initialize a variable to an empty associative array.
+
+::
+
+    ["set", "$groups", {}]
+
+Assign a string.
+
+::
+
+    ["set", "$version", "1.2.3"]
+
+Copy the ``UserName`` value from the assertion to a temporary variable.
+
+::
+
+    ["set", "$temp", "$assertion[UserName]"],
+
+
+Get the 2nd item in an array (array indexing is zero based)
+
+::
+
+    ["set", "$group", "$groups[1]"]
+
+
+Set the associative array entry "IdP" to "kdc.example.com".
+
+::
+
+    ["set", "$metadata[IdP]", "kdc.example.com""]
+
+--------------------------------------------------------------------------------
+
+length
+------
+
+``length $variable value``
+
+$variable
+    The variable which receives the length value
+
+value
+    The value whose length is to be determined. May be one of array,
+    associative array, or string.
+
+**length** computes the number of items in the value. How this is done
+depends upon the type of value:
+
+array
+    The length is the number of items in the array.
+
+associative array
+    The length is the number of key/value pairs in the associative
+    array.
+
+string
+    The length is the number of *characters* (not octets) in the
+    string.
+
+Examples:
+^^^^^^^^^
+
+Count how many items are in the ``$groups`` array and assign that
+value to the ``$groups_length`` variable.
+
+::
+
+    ["length", "$groups_length", "$groups"]
+
+Count how many key/value pairs are in the ``$assertion`` associative
+array and assign that value to the ``$num_assertion_values`` variable.
+
+::
+
+    ["length", "$num_assertion_values", "$assertion"]
+
+Count how many characters are in the assertion's UserName and assign
+the value to ``$username_length``.
+
+::
+
+    ["length", "$user_name_length", "$assertion[UserName]"]
+
+
+--------------------------------------------------------------------------------
+
+interpolate
+-----------
+
+``interpolate $variable string``
+
+$variable
+    This variable is assigned the result of the interpolation.
+
+string
+    A string containing references to variables which will be replaced
+    in the string.
+
+**interpolate** replaces each occurrence of a variable in a string with
+it's value. The result is assigned to $variable.
+
+Examples:
+^^^^^^^^^
+
+Form an email address given the username and domain. If the username
+is "jane" and the domain is "example.com" then $email will be
+"jane@example.com"
+
+::
+
+    ["interpolate", "$email", "${username}@${domain}"]
+
+
+--------------------------------------------------------------------------------
+
+
+append
+------
+
+``append $variable value``
+
+$variable
+    This variable **must** be an array. It is modified in place by
+    appending ``value`` to the end of the array.
+
+value
+    The value to append to the end of the array.
+
+**append** adds a value to end of an array.
+
+Examples:
+^^^^^^^^^
+
+Append the role "qa_test" to the roles list.
+
+::
+
+    ["append", "$roles", "qa_test"]
+
+
+--------------------------------------------------------------------------------
+
+
+unique
+------
+
+``unique $variable value``
+
+$variable
+    This variable is assigned the unique values in the ``value``
+    array.
+
+value
+    An array of values. **must** be an array.
+
+**unique** builds an array of unique values in ``value`` by stripping
+out duplicates and assigns the array of unique values to
+``$variable``. The order of items in the ``value`` array are
+preserved.
+
+Examples:
+^^^^^^^^^
+
+$one_of_a_kind will be assigned ["a", "b"]
+
+::
+
+    ["unique", "$one_of_a_kind", ["a", "b", "a"]]
+
+
+--------------------------------------------------------------------------------
+
+regexp
+------
+
+``regexp string pattern``
+
+string
+    The string the regular expression pattern is applied to.
+
+pattern
+    The regular expression pattern.
+
+**regexp** performs a regular expression match against ``string``. The
+regular expression pattern syntax is defined by the regular expression
+implementation of the language this API is written in.
+
+Pattern groups are a convenient way to select sub-matches. Pattern
+groups may accessed by either group number or group name. After a
+successful regular expression match the groups are stored in the
+special variables ``$regexp_array`` and
+``$regexp_map``.
+
+``$regexp_array`` is used to access the groups by
+numerical index. Groups are numbered by counting the left parenthesis
+group delimiter starting at 1. Group 0 is the entire
+match. ``$regexp_array`` is valid irregardless of whether you used
+named groups or not.
+
+``$regexp_map`` is used to access the groups by
+name. ``$regexp_map`` is only valid if you used named groups in the
+pattern.
+
+Examples:
+^^^^^^^^^
+
+Many user names are of the form "user@domain", to split the username
+from the domain and to be able to work with those values independently
+use a regular expression and then assign the results to a variable. In
+this example there are two regular expression groups, the first group
+is the username and the second group is the domain. In the first
+example we use named groups and then access the match information in
+the special variable ``$regexp_map`` via the name of the group.
+
+::
+
+    ["regexp", "$assertion[UserName]", "(?P<username>\\w+)@(?P<domain>.+)"],
+    ["continue", "if_not_success"],
+    ["set", "$username", "$regexp_map[username]"],
+    ["set", "$domain", "$regexp_map[domain]"],
+
+
+This is exactly equivalent but uses numbered groups instead of named
+groups. In this instance the group matches are stored in the special
+variable ``$regexp_array`` and accessed by numerical index.
+
+::
+
+    ["regexp", "$assertion[UserName]", "(\\w+)@(.+)"],
+    ["continue", "if_not_success"],
+    ["set", "$username", "$regexp_array[1]"],
+    ["set", "$domain", "$regexp_array[2]"],
+
+
+
+--------------------------------------------------------------------------------
+
+regexp_replace
+--------------
+
+``regexp_replace $variable string pattern replacement``
+
+$variable
+    The variable which receives result of the replacement.
+
+string
+    The string to perform the replacement on.
+
+pattern
+    The regular expression pattern.
+
+replacement
+    The replacement specification.
+
+**regexp_replace** replaces each occurrence of ``pattern`` in
+``$string`` with ``replacement``. See `regexp`_ for details of using
+regular expressions.
+
+Examples:
+^^^^^^^^^
+
+Convert hyphens in a name to underscores.
+
+::
+
+    ["regexp_replace", "$name", "$name", "-", "_"]
+
+
+--------------------------------------------------------------------------------
+
+split
+-----
+
+``split $variable string pattern``
+
+$variable
+    This variable is assigned an array containing the split items.
+
+string
+    The string to split into separate items.
+
+pattern
+    The regular expression pattern used to split the string.
+
+**split** splits ``string`` into separate pieces and assigns the
+result to ``$variable`` as an array of pieces. The split occurs
+wherever the regular expression ``pattern`` occurs in ``string``. See
+`regexp`_ for details of using regular expressions.
+
+Examples:
+^^^^^^^^^
+
+Split a list of groups separated by a colon (:) into an array of
+individual group names. If $assertion[Groups] contained the string
+"user:admin" then $group_list will set to ["user", "admin"].
+
+::
+
+    ["split", "$group_list", "$assertion[Groups]", ":"]
+
+
+
+--------------------------------------------------------------------------------
+
+join
+----
+
+``join $variable array join_string``
+
+$variable
+    This variable is assigned the string result of the join operation.
+
+array
+    An array of string items to be joined together with
+    ``$join_string``.
+
+join_string
+    The string inserted between each element in ``array``.
+
+**join** accepts an array of strings and produces a single string
+where each element in the array is separated by ``join_string``.
+
+Examples:
+^^^^^^^^^
+
+Convert a list of group names into a single string where each group
+name is separated by a colon (:). If the array ``$group_list`` is
+["user", "admin"] and the ``join_string`` is ":" then the
+``$group_string`` variable will be set to "user:admin".
+
+::
+
+    ["join", "$group_string", "$groups", ":"]
+
+
+--------------------------------------------------------------------------------
+
+lower
+-----
+
+``lower $variable value``
+
+$variable
+    This variable is assigned the result of the lower operation.
+
+value
+    The value to lower case, may be either a string, array, or
+    associative array.
+
+**lower** lower cases the input value. The input value may be one of
+the following types:
+
+string
+    The string is lower cased.
+
+array
+    Each member of the array must be a string, the result is an array
+    with the items replaced by their lower case value.
+
+associative array
+    Each key in the associative array is lower cased. The values
+    associated with the key are **not** modified.
+
+Examples:
+^^^^^^^^^
+
+Lookup ``UserName`` in the assertion and set the variable
+``$username`` to it's lower case value.
+
+::
+
+    ["lower", "$username", "$assertion[UserName]"],
+
+Set each member of the ``$groups`` array to it's lower case value. If
+``$groups`` was ["User", "Admin"] then ``$groups`` will become
+["user", "admin"].
+
+::
+
+    ["lower", "$groups", "$groups"],
+
+To enable case insensitive lookup's in an associative array lower case
+each key in the associative array. If ``$assertion`` was {"UserName":
+"JoeUser"} then ``$assertion`` will become {"username": "JoeUser"}
+
+::
+
+    ["lower", "$assertion", $assertion"]
+
+--------------------------------------------------------------------------------
+
+upper
+-----
+
+``upper $variable value``
+
+$variable
+    This variable is assigned the result of the upper operation.
+
+value
+    The value to upper case, may be either a string, array, or
+    associative array.
+
+**upper** is exactly analogous to `lower`_ except the values are upper
+cased, see `lower`_ for details.
+
+
+--------------------------------------------------------------------------------
+
+in
+--
+
+``in member collection``
+
+member
+    The value whose membership is being tested.
+
+collection
+    A collection of members. May be string, array or associative array.
+
+**in** tests to see if ``member`` is a member of ``collection``. The
+membership test depends on the type of collection, the following are
+supported:
+
+array
+    If any item in the array is equal to ``member`` then the result is
+    success.
+
+associative array
+    If the associative array contains a key equal to ``member`` then
+    the result is success.
+
+string
+    If the string contains a sub-string equal to ``member`` then the
+    result is success.
+
+Examples:
+^^^^^^^^^
+
+Test to see if the assertion contains a UserName value.
+
+::
+
+    ["in", "UserName", "$assertion"]
+    ["continue", "if_not_success"]
+
+Test to see if a group is one of "user" or "admin".
+
+::
+
+    ["in", "$group", ["user", "admin"]]
+    ["continue", "if_not_success"]
+
+Test to see if the sub-string "BigCorp" is in
+the assertion's ``Provider`` value.
+
+::
+
+    ["in", "BigCorp", "$assertion[Provider]"]
+    ["continue", "if_not_success"]
+
+
+--------------------------------------------------------------------------------
+
+not_in
+------
+
+``in member collection``
+
+member
+    The value whose membership is being tested.
+
+collection
+    A collection of members. May be string, array or associative array.
+
+**not_in** is exactly analogous to `in`_ except the sense of the test
+is reversed. See `in`_ for details.
+
+--------------------------------------------------------------------------------
+
+compare
+-------
+
+``compare left operator right``
+
+left
+    The left hand value of the binary operator.
+
+operator
+    The binary operator used for comparing left to right.
+
+right
+    The right hand value of the binary operator.
+
+
+**compare** compares the left value to the right value according the
+operator and sets success if the comparison evaluates to True. The
+following relational operators are supported.
+
++----------+-----------------------+
+| Operator | Description           |
++==========+=======================+
+| ==       | equal                 |
++----------+-----------------------+
+| !=       | not equal             |
++----------+-----------------------+
+| <        | less than             |
++----------+-----------------------+
+| <=       | less than or equal    |
++----------+-----------------------+
+| >        | greater than          |
++----------+-----------------------+
+| >=       | greater than or equal |
++----------+-----------------------+
+
+
+The left and right hand sides of the comparison operator *must* be
+the same type, no type conversions are performed. Not all combinations
+of operator and type are supported. The table below illustrates the
+supported combinations. Essentially you can test for equality or
+inequality on any type. But only strings and numbers support the
+magnitude relational operators.
+
+
++----------+--------+---------+------+---------+-----+------+------+
+| Operator | STRING | INTEGER | REAL | BOOLEAN | MAP | LIST | NULL |
++==========+========+=========+======+=========+=====+======+======+
+| ==       |   X    |    X    |  X   |    X    |  X  |  X   |  X   |
++----------+--------+---------+------+---------+-----+------+------+
+| !=       |   X    |    X    |  X   |    X    |  X  |  X   |  X   |
++----------+--------+---------+------+---------+-----+------+------+
+| <        |   X    |    X    |  X   |         |     |      |      |
++----------+--------+---------+------+---------+-----+------+------+
+| <=       |   X    |    X    |  X   |         |     |      |      |
++----------+--------+---------+------+---------+-----+------+------+
+| >        |   X    |    X    |  X   |         |     |      |      |
++----------+--------+---------+------+---------+-----+------+------+
+| >=       |   X    |    X    |  X   |         |     |      |      |
++----------+--------+---------+------+---------+-----+------+------+
+
+
+Examples:
+^^^^^^^^^
+
+Test to see if the ``$groups`` array has at least 2 members
+
+::
+
+    ["length", "$group_length", "$groups"],
+    ["compare", "$group_length", ">=", 2]
+
+
+--------------------------------------------------------------------------------
+
+exit
+----
+
+``exit status criteria``
+
+status
+    The result for the rule.
+
+criteria
+    The criteria upon which will cause the rule will be immediately
+    exited with a failed status.
+
+**exit** causes the rule being executed to immediately exit and a rule
+result if the specified criteria is met. Statement verbs such as `in`_
+or `compare`_ set the result status which may be tested with the
+``success`` and ``not_success`` criteria.
+
+The exit ``status`` may be one of:
+
+rule_fails
+    The rule has failed and no mapping will occur.
+
+rule_succeeds
+    The rule succeeded and the mapping will be applied.
+
+The ``criteria`` may be one of:
+
+if_success
+    If current result status is success then exit with ``status``.
+
+if_not_success
+    If current result status is not success then exit with ``status``.
+
+always
+    Unconditionally exit with ``status``.
+
+never
+    Effectively a no-op. Useful for debugging.
+
+Examples:
+^^^^^^^^^
+
+The rule requires ``UserName`` to be in the assertion.
+
+::
+
+    ["in", "UserName", "$assertion"]
+    ["exit", "rule_fails", "if_not_success"]
+
+--------------------------------------------------------------------------------
+
+
+continue
+--------
+
+``continue criteria``
+
+criteria
+    The criteria which causes the remainder of the *block* to be
+    skipped.
+
+**continue** is used to control execution for statement blocks. It
+mirrors in a crude way the `if` expression in a procedural
+language. ``continue`` does *not* affect the success or failure of a
+rule, rather it controls whether subsequent statements in a block are
+executed or not. Control continues at the next statement block.
+
+Statement verbs such as `in`_ or `compare`_ set the result status
+which may be tested with the ``success`` and ``not_success`` criteria.
+
+The criteria may be one of:
+
+if_success
+    If current result status is success then exit the statement
+    block and continue execution at the next statement block.
+
+if_not_success
+    If current result status is not success then exit the statement
+    block and continue execution at the next statement block.
+
+always
+    Immediately exit the statement block and continue execution at the
+    next statement block.
+
+never
+    Effectively a no-op. Useful for debugging. Execution continues at
+    the next statement.
+
+Examples:
+^^^^^^^^^
+
+The following pseudo code:
+
+::
+
+    roles = [];
+    if ("Groups" in assertion) {
+        groups = assertion["Groups"].split(":");
+        if ("qa_test" in groups) {
+            roles.append("tester");
+        }
+    }
+
+could be implemented this way:
+
+::
+
+    [
+        ["set", "$roles", []],
+        ["in", "Groups", "$assertion"],
+        ["continue", "if_not_success"],
+        ["split" "$groups", $assertion[Groups]", ":"],
+        ["in", "qa_test", "$groups"],
+        ["continue", "if_not_success"],
+        ["append", "$roles", "tester"]
+    ]
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.png b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.png
new file mode 100644
index 00000000..728b86ce
Binary files /dev/null and b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.png differ
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.wsd b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.wsd
new file mode 100644
index 00000000..3a1c1474
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/resource_access_sequence.wsd
@@ -0,0 +1,25 @@
+title Resource Access Sequence with Access Token
+
+ This walks through a listing request of a secured resource (MD-SAL topology) 
+ from a client to the ODL controller using an access token (either one generated
+ by the ODL token endpoint, or a token from a third-party IdP) and shows how the
+ authentication context get set upon successful token validation.  If token 
+ validation fails, the TokenAuthFilter will return a 401, and the REST layer 
+ will be oblivious to the failed request.
+
+Client -> ServletContainer: list topologies
+note right of Client
+(Authorization = access token)
+end note
+ServletContainer -> TokenAuthFilter: access token
+loop foreach TokenAuth
+    TokenAuthFilter -> TokenAuth: validate(token)
+    TokenAuth -> TokenAuth: validateToken
+end
+TokenAuth -> TokenAuthFilter: Authentication
+note left of TokenAuth
+(user/domain/roles/expiration)
+end note
+TokenAuthFilter -> AuthenticationService: set(Authentication)
+TokenAuthFilter -> RestConf: list topologies
+RestConf -> AuthenticationService: get: Authentication
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.diag b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.diag
new file mode 100644
index 00000000..28317393
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.diag
@@ -0,0 +1,6 @@
+blockdiag {
+   User <-> AAA;
+   User [numbered = 1, shape = actor]
+   AAA [numbered = 2, label = "App Server\nAAA"]
+}
+
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.svg b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.svg
new file mode 100644
index 00000000..4056b10a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_01.svg
@@ -0,0 +1,32 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg viewBox="0 0 448 120" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <defs id="defs_block">
+    <filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
+      <feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
+    </filter>
+  </defs>
+  <title>blockdiag</title>
+  <desc>blockdiag {
+   User &lt;-&gt; AAA;
+   User [numbered = 1, shape = actor]
+   AAA [numbered = 2, label = "App Server\nAAA"]
+}
+
+</desc>
+  <polygon fill="rgb(0,0,0)" points="134,56 134,61 151,61 151,66 134,66 134,71 148,86 141,86 131,76 121,86 114,86 128,71 128,66 111,66 111,61 128,61 128,56" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" />
+  <ellipse cx="131" cy="51" fill="rgb(0,0,0)" rx="7" ry="7" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="46" />
+  <polygon fill="rgb(255,255,255)" points="131,50 131,55 148,55 148,60 131,60 131,65 145,80 138,80 128,70 118,80 111,80 125,65 125,60 108,60 108,55 125,55 125,50" stroke="rgb(0,0,0)" />
+  <ellipse cx="128" cy="45" fill="rgb(255,255,255)" rx="7" ry="7" stroke="rgb(0,0,0)" />
+  <ellipse cx="64" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="61" y="44">1</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="293" y="60">App Server</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="310" y="70">AAA</text>
+  <ellipse cx="256" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="253" y="44">2</text>
+  <path d="M 156 60 L 248 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="149,60 156,56 156,64 149,60" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="255,60 248,56 248,64 255,60" stroke="rgb(0,0,0)" />
+</svg>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.diag b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.diag
new file mode 100644
index 00000000..2076dd16
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.diag
@@ -0,0 +1,18 @@
+blockdiag {
+   span_width = 30
+   User <-> Apache;
+   Proxy <-> AAA;
+   group {
+   Apache <-> Proxy;
+   group {
+       orientation = portrait
+       Apache <-> SSSD;
+   }
+   }
+   User [numbered = 1, shape = actor, width = 60]
+   Apache [numbered = 2, label = "Apache\nAuthenticates user"]
+   SSSD [numbered = 3, label = "SSSD\nProvides user info"]
+   Proxy [numbered = 4, label = "Proxy Transport\nRequest + Metadata"]
+   AAA [numbered = 5, label = "App Server\nAAA"]
+}
+
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.svg b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.svg
new file mode 100644
index 00000000..42196b60
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_02.svg
@@ -0,0 +1,79 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg viewBox="0 0 594 200" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <defs id="defs_block">
+    <filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
+      <feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
+    </filter>
+  </defs>
+  <title>blockdiag</title>
+  <desc>blockdiag {
+   span_width = 30
+   User &lt;-&gt; Apache;
+   Proxy &lt;-&gt; AAA;
+   group {
+   Apache &lt;-&gt; Proxy;
+   group {
+       orientation = portrait
+       Apache &lt;-&gt; SSSD;
+   }
+   }
+   User [numbered = 1, shape = actor, width = 60]
+   Apache [numbered = 2, label = "Apache\nAuthenticates user"]
+   SSSD [numbered = 3, label = "SSSD\nProvides user info"]
+   Proxy [numbered = 4, label = "Proxy Transport\nRequest + Metadata"]
+   AAA [numbered = 5, label = "App Server\nAAA"]
+}
+
+</desc>
+  <rect fill="rgb(243,152,0)" height="140" style="filter:url(#filter_blur)" width="292" x="117" y="30" />
+  <rect fill="rgb(243,152,0)" height="140" style="filter:url(#filter_blur)" width="134" x="117" y="30" />
+  <polygon fill="rgb(0,0,0)" points="66,56 66,61 83,61 83,66 66,66 66,71 80,86 73,86 63,76 53,86 46,86 60,71 60,66 43,66 43,61 60,61 60,56" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" />
+  <ellipse cx="63" cy="51" fill="rgb(0,0,0)" rx="7" ry="7" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="123" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="123" y="126" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="281" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="439" y="46" />
+  <polygon fill="rgb(255,255,255)" points="63,50 63,55 80,55 80,60 63,60 63,65 77,80 70,80 60,70 50,80 43,80 57,65 57,60 40,60 40,55 57,55 57,50" stroke="rgb(0,0,0)" />
+  <ellipse cx="60" cy="45" fill="rgb(255,255,255)" rx="7" ry="7" stroke="rgb(0,0,0)" />
+  <ellipse cx="30" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="27" y="44">1</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="120" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="166" y="60">Apache</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="133" y="70">Authenticates user</text>
+  <ellipse cx="120" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="117" y="44">2</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="120" y="120" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="170" y="139">SSSD</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="138" y="149">Provides user info</text>
+  <ellipse cx="120" cy="120" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="117" y="124">3</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="278" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="300" y="59">Proxy Transport</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="289" y="71">Request + Metadata</text>
+  <ellipse cx="278" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="275" y="44">4</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="436" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="473" y="60">App Server</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="490" y="70">AAA</text>
+  <ellipse cx="436" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="433" y="44">5</text>
+  <path d="M 88 60 L 112 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="81,60 88,56 88,64 81,60" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="119,60 112,56 112,64 119,60" stroke="rgb(0,0,0)" />
+  <path d="M 414 60 L 428 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="407,60 414,56 414,64 407,60" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="435,60 428,56 428,64 435,60" stroke="rgb(0,0,0)" />
+  <path d="M 184 88 L 184 112" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="184,81 180,88 188,88 184,81" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="184,119 180,112 188,112 184,119" stroke="rgb(0,0,0)" />
+  <path d="M 256 60 L 270 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="249,60 256,56 256,64 249,60" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="277,60 270,56 270,64 277,60" stroke="rgb(0,0,0)" />
+  <path d="M 184 88 L 184 112" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="184,81 180,88 188,88 184,81" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="184,119 180,112 188,112 184,119" stroke="rgb(0,0,0)" />
+  <path d="M 256 60 L 270 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="249,60 256,56 256,64 249,60" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="277,60 270,56 270,64 277,60" stroke="rgb(0,0,0)" />
+</svg>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.diag b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.diag
new file mode 100644
index 00000000..6ece3760
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.diag
@@ -0,0 +1,31 @@
+seqdiag {
+    // Set edge properties
+    //edge_length = 300;  // default value is 192
+    //span_height = 80;  // default value is 40
+
+    // Set fontsize.
+    //default_fontsize = 12;  // default value is 11
+
+    // Numbering edges automaticaly
+     autonumber = False;
+
+    // Change note color
+    default_note_color = lightblue;
+
+    Client -> Apache [label = "Request"];
+    === Apache mod_auth_kerb ===
+    Client <- Apache [label = "401 Unauthorized"];
+    Client -> Apache [label = "Authorization: Credentials"];
+    Apache -> Apache [label = "Set\nUser Name\nAuth Type"];
+    === Apache mod_lookup_identity ===
+    Apache -> SSSD [label = "Get User Info"];
+    SSSD --> IdP [label = "Get User Info", leftnote = "Only if\nnot cached\nby SSSD"];
+    SSSD <-- IdP [label = "Return User Info"];
+    Apache <- SSSD [label = "Return User Info"];
+    Apache -> Apache [label = "Set User specific\nenvironment\nvariables"];
+    === Apache mod_proxy ===
+    Apache -> Container [label = "Proxy With User's Metadata"];    
+    Apache <- Container [label = "Response"];    
+    Client <- Apache [label = "Response"];    
+    
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.svg b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.svg
new file mode 100644
index 00000000..91e8b1be
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_03.svg
@@ -0,0 +1,143 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg viewBox="0 0 1024 1227" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <defs id="defs_block">
+    <filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
+      <feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
+    </filter>
+  </defs>
+  <title>blockdiag</title>
+  <desc>seqdiag {
+    // Set edge properties
+    //edge_length = 300;  // default value is 192
+    //span_height = 80;  // default value is 40
+
+    // Set fontsize.
+    //default_fontsize = 12;  // default value is 11
+
+    // Numbering edges automaticaly
+     autonumber = False;
+
+    // Change note color
+    default_note_color = lightblue;
+
+    Client -&gt; Apache [label = "Request"];
+    === Apache mod_auth_kerb ===
+    Client &lt;- Apache [label = "401 Unauthorized"];
+    Client -&gt; Apache [label = "Authorization: Credentials"];
+    Apache -&gt; Apache [label = "Set\nUser Name\nAuth Type"];
+    === Apache mod_lookup_identity ===
+    Apache -&gt; SSSD [label = "Get User Info"];
+    SSSD --&gt; IdP [label = "Get User Info", leftnote = "Only if\nnot cached\nby SSSD"];
+    SSSD &lt;-- IdP [label = "Return User Info"];
+    Apache &lt;- SSSD [label = "Return User Info"];
+    Apache -&gt; Apache [label = "Set User specific\nenvironment\nvariables"];
+    === Apache mod_proxy ===
+    Apache -&gt; Container [label = "Proxy With User's Metadata"];    
+    Apache &lt;- Container [label = "Response"];    
+    Client &lt;- Apache [label = "Response"];    
+    
+}
+</desc>
+  <rect fill="rgb(0,0,0)" height="1065" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="127" y="140" />
+  <rect fill="rgb(0,0,0)" height="142" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="319" y="140" />
+  <rect fill="rgb(0,0,0)" height="815" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="319" y="344" />
+  <rect fill="rgb(0,0,0)" height="200" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="511" y="586" />
+  <rect fill="rgb(0,0,0)" height="70" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="703" y="654" />
+  <rect fill="rgb(0,0,0)" height="64" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="8" x="895" y="1031" />
+  <polygon fill="rgb(0,0,0)" points="420,636 491,636 499,644 499,672 420,672 420,636" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="451" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="643" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="835" y="46" />
+  <path d="M 128 80 L 128 1215" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
+  <rect fill="moccasin" height="1065" stroke="rgb(0,0,0)" width="8" x="124" y="134" />
+  <path d="M 320 80 L 320 1215" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
+  <rect fill="moccasin" height="142" stroke="rgb(0,0,0)" width="8" x="316" y="134" />
+  <rect fill="moccasin" height="815" stroke="rgb(0,0,0)" width="8" x="316" y="338" />
+  <path d="M 512 80 L 512 1215" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
+  <rect fill="moccasin" height="200" stroke="rgb(0,0,0)" width="8" x="508" y="580" />
+  <path d="M 704 80 L 704 1215" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
+  <rect fill="moccasin" height="70" stroke="rgb(0,0,0)" width="8" x="700" y="648" />
+  <path d="M 896 80 L 896 1215" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
+  <rect fill="moccasin" height="64" stroke="rgb(0,0,0)" width="8" x="892" y="1025" />
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="113" y="64">Client</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="302" y="65">Apache</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="448" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="498" y="64">SSSD</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="640" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="697" y="64">IdP</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="832" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="871" y="64">Container</text>
+  <path d="M 136 134 L 312 134" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="304,130 312,134 304,138" stroke="rgb(0,0,0)" />
+  <path d="M 136 276 L 312 276" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="144,272 136,276 144,280" stroke="rgb(0,0,0)" />
+  <path d="M 136 338 L 312 338" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="304,334 312,338 304,342" stroke="rgb(0,0,0)" />
+  <path d="M 328 422 L 416 422" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 416 422 L 416 438" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 416 438 L 328 438" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="336,434 328,438 336,442" stroke="rgb(0,0,0)" />
+  <path d="M 328 580 L 504 580" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="496,576 504,580 496,584" stroke="rgb(0,0,0)" />
+  <path d="M 520 648 L 696 648" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="4" />
+  <polygon fill="rgb(0,0,0)" points="688,644 696,648 688,652" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(173,216,230)" points="417,630 488,630 496,638 496,666 417,666 417,630" stroke="rgb(0,0,0)" />
+  <path d="M 488 630 L 488 638" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 488 638 L 496 638" fill="none" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="425" y="642">Only if</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="425" y="652">not cached</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="425" y="664">by SSSD</text>
+  <path d="M 520 718 L 696 718" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="4" />
+  <polygon fill="rgb(0,0,0)" points="528,714 520,718 528,722" stroke="rgb(0,0,0)" />
+  <path d="M 328 780 L 504 780" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="336,776 328,780 336,784" stroke="rgb(0,0,0)" />
+  <path d="M 328 864 L 416 864" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 416 864 L 416 880" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 416 880 L 328 880" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="336,876 328,880 336,884" stroke="rgb(0,0,0)" />
+  <path d="M 328 1025 L 888 1025" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="880,1021 888,1025 880,1029" stroke="rgb(0,0,0)" />
+  <path d="M 328 1089 L 888 1089" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="336,1085 328,1089 336,1093" stroke="rgb(0,0,0)" />
+  <path d="M 136 1153 L 312 1153" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="144,1149 136,1153 144,1157" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="140" y="132">Request</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="217" y="274">401 Unauthorized</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="140" y="336">Authorization: Credentials</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="398">Set</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="408">User Name</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="420">Auth Type</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="332" y="578">Get User Info</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="524" y="646">Get User Info</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="608" y="716">Return User Info</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="416" y="778">Return User Info</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="842">Set User specific</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="852">environment</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="328" y="862">variables</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="332" y="1023">Proxy With User's Metadata</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="841" y="1087">Response</text>
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="265" y="1151">Response</text>
+  <path d="M 40 202 L 442 202" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 40 206 L 442 206" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 581 202 L 984 202" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 581 206 L 984 206" fill="none" stroke="rgb(0,0,0)" />
+  <rect fill="rgb(208,208,208)" height="18" stroke="rgb(0,0,0)" width="139" x="442" y="195" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="452" y="209">Apache mod_auth_kerb</text>
+  <path d="M 40 506 L 429 506" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 40 510 L 429 510" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 594 506 L 984 506" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 594 510 L 984 510" fill="none" stroke="rgb(0,0,0)" />
+  <rect fill="rgb(208,208,208)" height="18" stroke="rgb(0,0,0)" width="165" x="429" y="499" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="439" y="513">Apache mod_lookup_identity</text>
+  <path d="M 40 948 L 455 948" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 40 952 L 455 952" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 568 948 L 984 948" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 568 952 L 984 952" fill="none" stroke="rgb(0,0,0)" />
+  <rect fill="rgb(208,208,208)" height="18" stroke="rgb(0,0,0)" width="113" x="455" y="941" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="465" y="955">Apache mod_proxy</text>
+</svg>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.diag b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.diag
new file mode 100644
index 00000000..8f69a0b8
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.diag
@@ -0,0 +1,25 @@
+blockdiag {
+    Connector -> SssdFilter;
+    SssdFilter -> ClaimAuthFilter;
+    ClaimAuthFilter -> SssdClaimAuth;
+    SssdClaimAuth -> Assertion [folded];
+        
+    group {
+    orientation = portrait
+    Assertion -> JsonAssertion;
+    JsonAssertion -> IdPMapper;
+    IdPMapper -> JsonMapped;
+    }
+
+    JsonMapped -> Claim;
+
+    Connector [numbered = 1]
+    SssdFilter [numbered = 2]
+    ClaimAuthFilter [numbered = 3]
+    SssdClaimAuth [numbered = 4]
+    Assertion [numbered = 4.1]
+    JsonAssertion [numbered = 4.2]
+    IdPMapper  [numbered = 4.3]
+    JsonMapped [numbered = 4.4]
+    Claim [numbered = 5]
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.svg b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.svg
new file mode 100644
index 00000000..74850a85
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_04.svg
@@ -0,0 +1,100 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg viewBox="0 0 832 440" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <defs id="defs_block">
+    <filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
+      <feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
+    </filter>
+  </defs>
+  <title>blockdiag</title>
+  <desc>blockdiag {
+    Connector -&gt; SssdFilter;
+    SssdFilter -&gt; ClaimAuthFilter;
+    ClaimAuthFilter -&gt; SssdClaimAuth;
+    SssdClaimAuth -&gt; Assertion [folded];
+        
+    group {
+    orientation = portrait
+    Assertion -&gt; JsonAssertion;
+    JsonAssertion -&gt; IdPMapper;
+    IdPMapper -&gt; JsonMapped;
+    }
+
+    JsonMapped -&gt; Claim;
+
+    Connector [numbered = 1]
+    SssdFilter [numbered = 2]
+    ClaimAuthFilter [numbered = 3]
+    SssdClaimAuth [numbered = 4]
+    Assertion [numbered = 4.1]
+    JsonAssertion [numbered = 4.2]
+    IdPMapper  [numbered = 4.3]
+    JsonMapped [numbered = 4.4]
+    Claim [numbered = 5]
+}
+</desc>
+  <rect fill="rgb(243,152,0)" height="300" style="filter:url(#filter_blur)" width="144" x="56" y="110" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="451" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="643" y="46" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="126" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="206" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="286" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="366" />
+  <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="366" />
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="103" y="64">Connector</text>
+  <ellipse cx="64" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="61" y="44">1</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="294" y="64">SssdFilter</text>
+  <ellipse cx="256" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="253" y="44">2</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="448" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="471" y="64">ClaimAuthFilter</text>
+  <ellipse cx="448" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="445" y="44">3</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="640" y="40" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="665" y="64">SssdClaimAuth</text>
+  <ellipse cx="640" cy="40" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="637" y="44">4</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="120" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="103" y="144">Assertion</text>
+  <ellipse cx="64" cy="120" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="56" y="124">4.1</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="200" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="91" y="224">JsonAssertion</text>
+  <ellipse cx="64" cy="200" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="56" y="204">4.2</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="280" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="102" y="305">IdPMapper</text>
+  <ellipse cx="64" cy="280" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="56" y="284">4.3</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="360" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="97" y="385">JsonMapped</text>
+  <ellipse cx="64" cy="360" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="56" y="364">4.4</text>
+  <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="360" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="307" y="384">Claim</text>
+  <ellipse cx="256" cy="360" fill="pink" rx="12" ry="12" stroke="rgb(0,0,0)" />
+  <text fill="rgb(0,0,0)" font-family="sansserif" font-size="11" font-style="normal" font-weight="normal" x="253" y="364">5</text>
+  <path d="M 192 60 L 248 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="255,60 248,56 248,64 255,60" stroke="rgb(0,0,0)" />
+  <path d="M 384 60 L 440 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="447,60 440,56 440,64 447,60" stroke="rgb(0,0,0)" />
+  <path d="M 576 60 L 632 60" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="639,60 632,56 632,64 639,60" stroke="rgb(0,0,0)" />
+  <path d="M 704 80 L 704 100" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 128 100 L 704 100" fill="none" stroke="rgb(0,0,0)" />
+  <path d="M 128 100 L 128 112" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="128,119 124,112 132,112 128,119" stroke="rgb(0,0,0)" />
+  <path d="M 128 160 L 128 192" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="128,199 124,192 132,192 128,199" stroke="rgb(0,0,0)" />
+  <path d="M 128 240 L 128 272" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="128,279 124,272 132,272 128,279" stroke="rgb(0,0,0)" />
+  <path d="M 128 320 L 128 352" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="128,359 124,352 132,352 128,359" stroke="rgb(0,0,0)" />
+  <path d="M 192 380 L 248 380" fill="none" stroke="rgb(0,0,0)" />
+  <polygon fill="rgb(0,0,0)" points="255,380 248,376 248,384 255,380" stroke="rgb(0,0,0)" />
+</svg>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_05.svg b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_05.svg
new file mode 100644
index 00000000..f4657f06
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_05.svg
@@ -0,0 +1,613 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="689.19269"
+   height="212.05057"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="sssd_05.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient12785"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop12787" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop12789" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12777">
+      <stop
+         style="stop-color:#ffcc00;stop-opacity:1;"
+         offset="0"
+         id="stop12779" />
+      <stop
+         style="stop-color:#ffcc00;stop-opacity:0;"
+         offset="1"
+         id="stop12781" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Scissors"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Scissors"
+       style="overflow:visible">
+      <path
+         id="schere"
+         d="M 9.0898857,-3.6061018 C 8.1198849,-4.7769976 6.3697607,-4.7358294 5.0623558,-4.2327734 l -8.2124046,3.0779029 c -2.3882933,-1.3067135 -4.7482873,-0.9325372 -4.7482873,-1.5687873 0,-0.4973164 0.4566662,-0.3883222 0.3883068,-1.6831941 -0.065635,-1.2432767 -1.3635771,-2.1630796 -2.5903987,-2.0816435 -1.227271,-0.00735 -2.499439,0.9331613 -2.510341,2.2300611 -0.09143,1.3063864 1.007209,2.5196896 2.306764,2.6052316 1.5223406,0.2266616 4.218258,-0.6955566 5.482945,1.57086006 -0.9422847,1.73825774 -2.6140244,1.74307674 -4.1255107,1.65607034 -1.2548743,-0.072235 -2.7620933,0.2873979 -3.3606483,1.5208605 -0.578367,1.1820862 -0.0112,2.8646022 1.316749,3.226412 1.3401912,0.4918277 3.1806689,-0.129711 3.4993722,-1.6707242 0.2456585,-1.187823 -0.5953659,-1.7459574 -0.2725074,-2.1771537 0.2436135,-0.32536 1.7907806,-0.1368452 4.5471053,-1.3748244 L 5.6763468,4.2330688 C 6.8000164,4.5467672 8.1730685,4.5362646 9.1684433,3.4313614 L -0.05164093,-0.05372222 9.0898857,-3.6061018 z m -18.3078016,-1.900504 c 1.294559,0.7227998 1.1888392,2.6835702 -0.1564272,3.0632889 -1.2165179,0.423661 -2.7710269,-0.7589694 -2.3831779,-2.0774648 0.227148,-1.0818519 1.653387,-1.480632 2.5396051,-0.9858241 z m 0.056264,8.0173649 c 1.3508301,0.4988648 1.1214429,2.7844356 -0.2522207,3.091609 -0.9110594,0.3163391 -2.2135494,-0.1387976 -2.3056964,-1.2121394 -0.177609,-1.305055 1.356085,-2.4841482 2.5579171,-1.8794696 z"
+         style="fill:#000000"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="DotL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="DotL"
+       style="overflow:visible">
+      <path
+         id="path4170"
+         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="StopL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="StopL"
+       style="overflow:visible">
+      <path
+         id="path4278"
+         d="M 0,5.65 0,-5.65"
+         style="fill:none;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.8,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mstart"
+       style="overflow:visible">
+      <path
+         id="path4133"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(0.6,0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path4136"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path4118"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path4130"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <filter
+       color-interpolation-filters="sRGB"
+       height="1.5039999"
+       id="filter_blur"
+       inkscape:collect="always"
+       width="1.1575"
+       x="-0.078749999"
+       y="-0.252">
+      <feGaussianBlur
+         id="feGaussianBlur3780"
+         inkscape:collect="always"
+         stdDeviation="4.2" />
+    </filter>
+    <marker
+       inkscape:stockid="Arrow2Mstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mstart-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4133-8"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(0.6,0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4136-9"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <filter
+       color-interpolation-filters="sRGB"
+       height="1.5039999"
+       id="filter_blur-1"
+       inkscape:collect="always"
+       width="1.1575"
+       x="-0.078749999"
+       y="-0.252">
+      <feGaussianBlur
+         id="feGaussianBlur3780-1"
+         inkscape:collect="always"
+         stdDeviation="4.2" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter18355">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="6.2598764"
+         id="feGaussianBlur18357" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="405.52492"
+     inkscape:cy="110.18507"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:snap-grids="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="992"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-22.986913,-110.53072)">
+    <rect
+       y="136.89983"
+       x="254.85715"
+       height="185.19879"
+       width="456.83981"
+       id="rect12822"
+       style="fill:#f39800;fill-opacity:1;stroke:#000000;stroke-width:0.96499999999999997;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter18355)" />
+    <g
+       id="g18452">
+      <rect
+         y="244.58766"
+         x="105.58965"
+         height="41.710945"
+         width="129.83621"
+         id="rect2987"
+         style="fill:#ffffff;stroke:#000000;stroke-width:1.41119610999999989px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text2991"
+         y="261.25369"
+         x="112.20991"
+         style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           id="tspan2995"
+           y="261.25369"
+           x="112.20991"
+           sodipodi:role="line">Apache mod_proxy:</tspan><tspan
+           id="tspan2997"
+           y="276.25369"
+           x="112.20991"
+           sodipodi:role="line">forward port 8383</tspan></text>
+    </g>
+    <g
+       id="g18364">
+      <rect
+         y="167.43681"
+         x="304.33868"
+         height="50.483749"
+         width="98.582535"
+         id="rect2987-7"
+         style="fill:#ffffff;stroke:#000000;stroke-width:1.35282063000000008px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text2991-2"
+         y="181.34079"
+         x="353.99908"
+         style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+         xml:space="preserve"><tspan
+           id="tspan2997-2"
+           y="181.34079"
+           x="353.99908"
+           sodipodi:role="line">Connector:</tspan><tspan
+           id="tspan3813"
+           y="196.34079"
+           x="353.99908"
+           sodipodi:role="line">port = 80</tspan><tspan
+           id="tspan3908"
+           y="211.34079"
+           x="353.99908"
+           sodipodi:role="line">(web)</tspan></text>
+    </g>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3815"
+       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><flowRegion
+         id="flowRegion3817"><rect
+           id="rect3819"
+           width="201.02036"
+           height="90.913727"
+           x="174.25131"
+           y="117.466" /></flowRegion><flowPara
+         id="flowPara3821" /></flowRoot>    <g
+       id="g18419">
+      <rect
+         y="240.20126"
+         x="304.33868"
+         height="50.483749"
+         width="98.582535"
+         id="rect2987-7-6"
+         style="fill:#ffffff;stroke:#000000;stroke-width:1.35282063000000008px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text2991-2-6"
+         y="253.64822"
+         x="353.63287"
+         style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+         xml:space="preserve"><tspan
+           id="tspan2997-2-4"
+           y="253.64822"
+           x="353.63287"
+           sodipodi:role="line">Connector:</tspan><tspan
+           id="tspan3813-5"
+           y="268.64822"
+           x="353.63287"
+           sodipodi:role="line">port = 8383</tspan><tspan
+           id="tspan3908-2"
+           y="283.64822"
+           x="353.63287"
+           sodipodi:role="line">(auth proxy)</tspan></text>
+    </g>
+    <g
+       id="g7018"
+       transform="translate(-14,35.850205)">
+      <g
+         id="g7023"
+         transform="translate(218.19295,1.0101525)">
+        <g
+           id="g7028"
+           transform="translate(-97.984797,178.797)">
+          <polygon
+             id="polygon6858"
+             style="opacity:0.7;fill:#000000;fill-opacity:1;filter:url(#filter_blur)"
+             points="60,61 60,56 66,56 66,61 83,61 83,66 66,66 66,71 80,86 73,86 63,76 53,86 46,86 60,71 60,66 43,66 43,61 "
+             transform="translate(-115.02286,-17.004219)" />
+          <polygon
+             id="polygon6872"
+             points="57,55 57,50 63,50 63,55 80,55 80,60 63,60 63,65 77,80 70,80 60,70 50,80 43,80 57,65 57,60 40,60 40,55 "
+             style="fill:#ffffff;stroke:#000000"
+             transform="translate(-115.02286,-17.004219)" />
+          <ellipse
+             d="m 67,45 c 0,3.865993 -3.134007,7 -7,7 -3.865993,0 -7,-3.134007 -7,-7 0,-3.865993 3.134007,-7 7,-7 3.865993,0 7,3.134007 7,7 z"
+             id="ellipse6874"
+             ry="7"
+             rx="7"
+             cy="45"
+             cx="60"
+             sodipodi:cx="60"
+             sodipodi:cy="45"
+             sodipodi:rx="7"
+             sodipodi:ry="7"
+             style="fill:#ffffff;stroke:#000000"
+             transform="translate(-115.02286,-17.004219)" />
+        </g>
+      </g>
+    </g>
+    <rect
+       style="fill:#ffffff;stroke:#000000;stroke-width:1.35282063000000008px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
+       id="rect2987-7-5"
+       width="98.582535"
+       height="50.483749"
+       x="589.35858"
+       y="239.54141" />
+    <text
+       xml:space="preserve"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="638.74945"
+       y="254.25693"
+       id="text2991-2-67"
+       sodipodi:linespacing="125%"><tspan
+         id="tspan10147"
+         sodipodi:role="line"
+         x="638.74945"
+         y="254.25693">AAA Servlet</tspan><tspan
+         id="tspan10204"
+         sodipodi:role="line"
+         x="638.74945"
+         y="269.25693">executes</tspan><tspan
+         id="tspan10206"
+         sodipodi:role="line"
+         x="638.74945"
+         y="284.25693">with roles</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot10151"
+       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><flowRegion
+         id="flowRegion10153"><rect
+           id="rect10155"
+           width="139.90613"
+           height="110.10663"
+           x="648.01288"
+           y="147.2655" /></flowRegion><flowPara
+         id="flowPara10157" /></flowRoot>    <g
+       id="g18431">
+      <rect
+         y="169.04143"
+         x="589.86121"
+         height="50.483749"
+         width="98.582535"
+         id="rect2987-7-5-0"
+         style="fill:#ffffff;stroke:#000000;stroke-width:1.35282063000000008px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text2991-2-67-9"
+         y="191.07236"
+         x="638.61047"
+         style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+         xml:space="preserve"><tspan
+           y="191.07236"
+           x="638.61047"
+           sodipodi:role="line"
+           id="tspan10147-8">Non-AAA</tspan><tspan
+           y="206.07236"
+           x="638.61047"
+           sodipodi:role="line"
+           id="tspan10198">Servlet</tspan><tspan
+           y="221.07236"
+           x="638.61047"
+           sodipodi:role="line"
+           id="tspan10196" /></text>
+    </g>
+    <g
+       id="g18474">
+      <rect
+         y="168.30391"
+         x="437.00925"
+         height="122.27845"
+         width="121.29423"
+         id="rect2987-7-2-2"
+         style="fill:#ffffff;stroke:#000000;stroke-width:2.33539009000000020px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text2991-2-9-8"
+         y="181.0443"
+         x="497.75305"
+         style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+         xml:space="preserve"><tspan
+           id="tspan3908-4-7"
+           y="181.0443"
+           x="497.75305"
+           sodipodi:role="line">ClaimAuthFilter:</tspan><tspan
+           id="tspan4038"
+           y="196.0443"
+           x="497.75305"
+           sodipodi:role="line">localPort in</tspan><tspan
+           id="tspan4040"
+           y="211.0443"
+           x="497.75305"
+           sodipodi:role="line">secureProxyPorts?</tspan><tspan
+           id="tspan4044"
+           y="226.0443"
+           x="497.75305"
+           sodipodi:role="line" /></text>
+      <g
+         id="g18469">
+        <rect
+           style="fill:#ff0000;stroke:#000000;stroke-width:0.81352955000000005;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;fill-opacity:1"
+           id="rect10241"
+           width="98.994949"
+           height="23.733509"
+           x="448.15887"
+           y="220.00537" />
+        <text
+           xml:space="preserve"
+           style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+           x="488.27258"
+           y="236.16118"
+           id="text10243"
+           sodipodi:linespacing="125%"><tspan
+             sodipodi:role="line"
+             id="tspan10245"
+             x="488.27258"
+             y="236.16118">No</tspan></text>
+      </g>
+      <g
+         id="g18461">
+        <rect
+           style="fill:#00ff00;stroke:#000000;stroke-width:0.81352955000000005;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;fill-opacity:1"
+           id="rect10241-9"
+           width="98.994949"
+           height="23.733509"
+           x="448.15887"
+           y="253.81883" />
+        <text
+           xml:space="preserve"
+           style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+           x="488.27258"
+           y="269.97464"
+           id="text10243-4"
+           sodipodi:linespacing="125%"><tspan
+             sodipodi:role="line"
+             id="tspan10245-6"
+             x="488.27258"
+             y="269.97464">Yes</tspan></text>
+      </g>
+    </g>
+    <g
+       id="g7018-9"
+       transform="translate(-15.11838,-36.914245)">
+      <g
+         id="g7023-0"
+         transform="translate(218.19295,1.0101525)">
+        <g
+           id="g7028-1"
+           transform="translate(-97.984797,178.797)">
+          <polygon
+             id="polygon6858-6"
+             style="opacity:0.7;fill:#000000;fill-opacity:1;filter:url(#filter_blur-1)"
+             points="60,71 60,66 43,66 43,61 60,61 60,56 66,56 66,61 83,61 83,66 66,66 66,71 80,86 73,86 63,76 53,86 46,86 "
+             transform="translate(-115.02286,-17.004219)" />
+          <polygon
+             id="polygon6872-6"
+             points="57,65 57,60 40,60 40,55 57,55 57,50 63,50 63,55 80,55 80,60 63,60 63,65 77,80 70,80 60,70 50,80 43,80 "
+             style="fill:#ffffff;stroke:#000000"
+             transform="translate(-115.02286,-17.004219)" />
+          <ellipse
+             d="m 67,45 c 0,3.865993 -3.134007,7 -7,7 -3.865993,0 -7,-3.134007 -7,-7 0,-3.865993 3.134007,-7 7,-7 3.865993,0 7,3.134007 7,7 z"
+             id="ellipse6874-1"
+             ry="7"
+             rx="7"
+             cy="45"
+             cx="60"
+             sodipodi:cx="60"
+             sodipodi:cy="45"
+             sodipodi:rx="7"
+             sodipodi:ry="7"
+             style="fill:#ffffff;stroke:#000000"
+             transform="translate(-115.02286,-17.004219)" />
+        </g>
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="430.15594"
+       y="119.6479"
+       id="text12879"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan12881"
+         x="430.15594"
+         y="119.6479">Java EE Container</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 57.185293,265.44314 48.404357,0"
+       id="path13365"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#g7018"
+       inkscape:connection-start-point="d4" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 235.42587,265.44314 68.91281,0"
+       id="path14574"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 402.92122,265.52611 45.23767,0.0762"
+       id="path14999"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow1Mend)"
+       d="m 402.92122,206.09216 51.12769,13.91321"
+       id="path15397"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 542.32654,220.00537 47.53467,-12.62771"
+       id="path15795"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 547.15383,265.36883 42.20475,-0.2701"
+       id="path16193"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-7);marker-end:url(#Arrow2Mend-1)"
+       d="m 56.066913,192.67869 248.271767,0"
+       id="path17038"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#g7018-9"
+       inkscape:connection-start-point="d4" />
+  </g>
+</svg>
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.png b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.png
new file mode 100644
index 00000000..9f9a0b49
Binary files /dev/null and b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.png differ
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.wsd b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.wsd
new file mode 100644
index 00000000..f97ed1ee
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_auth_sequence.wsd
@@ -0,0 +1,23 @@
+title Federated Authentication with SSSD
+
+# This walks through the federated authentication sequence where a claim from a
+# third-party IdP system is posted to the ODL token endpoint in exchange for an 
+# access token. The claim information is assumed to be in format specific to the 
+# third-party IdP system and assumed to be captured via either Apache environment
+# variables (Servlet attributes) or HTTP headers. 
+
+Client -> Apache WebServer: authenticate
+note right of Client
+credentials
+end note
+Apache WebServer -> SSSD: authenticate
+SSSD -> LDAP/AD : authenticate
+SSSD -> Apache WebServer: claim
+Apache WebServer -> ServletContainer: CGI variables
+ServletContainer -> SSSD Plugin: Servlet attributes/headers
+SSSD Plugin -> SSSD Plugin : transformClaim
+SSSD Plugin -> TokenEndPoint : claim
+TokenEndPoint -> TokenEndPoint : createToken
+TokenEndPoint -> Client : refresh token, list of authorized domains
+Client -> TokenEndPoint : refresh token, domain
+TokenEndPoint -> Client : access token
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_configuration.rst b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_configuration.rst
new file mode 100644
index 00000000..7f912d94
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/sssd_configuration.rst
@@ -0,0 +1,1687 @@
+################################################
+Federated Authentication Utilizing Apache & SSSD
+################################################
+
+:Author: John Dennis
+:Email: jdennis@redhat.com
+
+.. contents:: Table of Contents
+
+************
+Introduction
+************
+
+Applications should not need to handle the burden of authentication
+and authorization. These are complex technologies further complicated
+by the existence of a wide variety of authentication
+mechanisms. Likewise there are numerous identity providers (IdP) which
+one may wish to utilize, perhaps in a federated manner. The potential
+to make critical mistakes are high while consuming significant
+engineering resources. Ideally an application should "outsource" it's
+authentication to an "expert" and avoid unnecessary development costs.
+
+For web based applications (both conventional HTML and REST API) there
+has been a trend to embed a simple HTTP server in the application or
+application server which handles the HTTP requests eschewing the use
+of a traditional web server such as Apache.
+
+.. figure:: sssd_01.png
+   :align: center
+
+   _`Figure 1.`
+
+But traditional web servers have a lot of advantages. They often come
+with extensive support for technologies you might wish to utilize in
+your application. It would require signification software engineering
+to add support for those technologies in your application. The problem
+is compounded by the fact many of these technologies demand domain
+expertise which is unlikely to be available in the application
+development team. Another problem is the libraries needed to utilize
+the technology may not even be available in the programming language
+the application is being developed in. Fundamentally an application
+developer should focus on developing their application instead of
+investing resources into implementing complex code for the ancillary
+technologies the application may wish to utilize.
+
+Therefore fronting your application with a web server such as Apache
+makes a lot of sense. One should allow Apache to handle complex tasks
+such as multiple authentication mechanisms talking to multiple
+IdP's. Suppose you want your application to handle Single Sign-On
+(SSO) via Kerberos or authentication based on X509 certificates
+(i.e. PKI). Apache already has extensions to handle these which have
+been field proven, it would be silly to try and support these in your
+application. Apache also comes with other useful extensions such as
+``mod_identity_lookup`` which can extract metadata about an
+authenticated user from multiple sources such as LDAP,
+Active Directory, NIS, etc.
+
+By fronting your application with Apache and allowing Apache to handle
+the complex task of authentication, identity lookups etc. you've
+greatly increased the features of your application while at the same
+time reducing application development time along with increasing
+application security and robustness.
+
+.. figure:: sssd_02.png
+   :align: center
+
+   _`Figure 2.`
+
+When Apache fronts your application you will be passed the results of
+authentication and identity lookups. Your application only needs a
+simple mechanism to accept these values. There are a variety of ways
+the values can be passed from Apache to your application which will be
+discussed in later sections.
+
+Authentication & Identity Properties
+====================================
+
+Authentication is proving that a user is who they claim to be, in
+other words after authentication the user has a proven identity. In
+security parlance the authenticated entity is call a
+principal. Principals may be humans, machines or
+services. Authorization is distinct from authentication. Authorization
+declares what actions an authenticated principal may perform. For
+example, does a principal have permission to read a certain file, run
+a specific command, etc. Identity metadata is typically bound to the
+principal to provide extra information. Examples include the users
+full name, their organization, the groups they are members of, etc.
+
+Apache can provide both authentication and identity metadata to an
+application freeing the application of this task. Authorization
+usually will remain the province of the application. A typical
+design pattern is to assign roles to a principal based on identity
+properties. As the application executes on behalf of a principal the
+application will check if the principal has the necessary role needed
+to perform the operation.
+
+Apache ships with a wide variety of authentication modules. After an
+Apache authentication module successfully authenticates a principal, it
+sets internal variables identifying the principal and the
+authentication method used to authenticate the principal. These are
+exported as the CGI variables REMOTE_USER and AUTH_TYPE respectively
+(see `CGI Export Issues`_ for further information).
+
+Identity Properties
+-------------------
+
+Most Apache authentication modules do not have access to any of the
+identity properties bound to the authenticated principal. Those
+identity properties must be provided by some other mechanism. Typical
+mechanisms include lookups in LDAP, Active Directory, NIS, POSIX
+passwd/gecos and SQL. Managing these lookups can be difficult
+especially in a networked environment where services may be
+temporarily unavailable and/or in a enterprise deployment where
+identity sources must be multiplexed across a variety of services
+according to enterprise wide policy.
+
+`SSSD`_ (System Security Services Daemon) is designed to alleviate many
+of the problems surrounding authentication and identity property
+lookup. SSSD can provide identity properties via D-Bus using it's
+InfoPipe (IFP) feature. The `mod_identity_lookup`_ Apache module is
+given the name of the authenticated principal and makes available
+identity properties via Apache environment variables (see `Configure
+SSSD IFP`_ for details).
+
+Exporting & Consuming Identity Metadata
+=======================================
+
+The authenticated principal (REMOTE_USER), the mechanism used to
+authenticate the principal (AUTH_TYPE) and identity properties
+(supplied by SSSD IFP) are exported to the application which trusts
+this metadata to be valid.
+
+How is this identity metadata exported from Apache and then be
+consumed by a Java EE Servlet?
+
+The architectural design inside Apache tries to capitalize on the
+existing CGI standard (`CGI RFC`_) as much as possible. CGI defines
+these relevant environment variables:
+
+  * REMOTE_USER
+  * AUTH_TYPE
+  * REMOTE_ADDR
+  * REMOTE_HOST
+
+
+Transporting Identity Metadata from Apache to a Java EE Servlet
+===============================================================
+
+In following figure we can see that the user connects to Apache
+instead of the servlet container. Apache authenticates the user, looks
+up the principal's identity information and then proxies the request
+to the servlet container. The additional identity metadata must be
+included in the proxy request in order for the servlet to extract it.
+
+.. figure:: sssd_03.png
+   :align: center
+
+   _`Figure 3.`
+
+The Java EE Servlet API is designed with the HTTP protocol in mind
+however the servlet never directly accesses the HTTP protocol stream.
+Instead it uses the servlet API to get access to HTTP request
+data. The responsibility for HTTP communication rests with the
+container's ``Connector`` objects. When the servlet API needs
+information it works in conjunction with the ``Connector`` to supply
+it. For example the ``HttpServletRequest.getRemoteHost()`` method
+interrogates information the ``Connector`` placed on the internal
+request object. Analogously ``HttpServletRequest.getRemoteUser()``
+interrogates information placed on the internal request object by an
+authentication filter.
+
+But what happens when a HTTP request is proxied to a servlet container
+by Apache and ``getRemoteHost()`` or ``getRemoteUser()`` is called? Most
+``Connector`` objects do not understand the proxy scenario, to them
+a request from a proxy looks just like a request sent directly to the
+servlet container. Therefore ``getRemoteHost()`` or ``getRemoteUser()``
+ends up returning information relative to the proxy instead of the
+user who connected to the proxy because it's the proxy who connected
+to the servlet container and not the end user. There are 2 fundamental
+approaches which allow the servlet API to return data supplied by the
+proxy:
+
+  1. Proxy uses special protocol (e.g. AJP) to embed metadata.
+  2. Metadata is embedded in an HTTP extension by the proxy (i.e. headers)
+
+Proxy With AJP Protocol
+-----------------------
+
+The AJP_ protocol was designed as a protocol to exchange HTTP requests
+and responses between Apache and a Java EE Servlet Container. One of
+its design goals was to improve performance by translating common text
+values appearing in HTTP requests to a more compact binary form. At
+the same time AJP provided a mechanism to supply metadata about the
+request to the servlet container. That metadata is encoded in an AJP
+attribute (a name/value pair). The Apache AJP Proxy module looks up
+information in the internal Apache request object (e.g. remote user,
+remote address, etc.) and encodes that metadata in AJP attributes. On
+the servlet container side a AJP ``Connector`` object is aware of these
+metadata attributes, extracts them from the protocol and supplies
+their values to the upper layers of the servlet API. Thus a call to
+``HttpServletRequest.getRemoteUser()`` made by a servlet will receive
+the value set by Apache prior to the proxy. This is the desired and
+expected behavior. A servlet should be ignorant of the consequences of
+proxies; the servlet API should behave the same regardless of the
+presence of a proxy.
+
+The AJP protocol also has a general purpose attribute mechanism whereby
+any arbitrary name/value pair can be passed. This proxy metadata can
+be retrieved by a servlet by calling ``ServletRequest.getAttribute()``
+[1]_ When Apache mod_proxy_ajp is being used the authentication
+metadata for the remote user and auth type are are automatically
+inserted into the AJP protocol and the AJP ``Connector`` object on
+the servlet receiving end supplies those values to
+``HttpServletRequest.getRemoteHost()`` and
+``HttpServletRequest.getRemoteUser()`` respectively. But the identity
+metadata supplied by ``mod_identity_lookup`` needs to be explicitly
+encoded into an AJP attribute (see `Configure SSSD IFP`_ for details)
+that can later be retrieved by ``ServletRequest.getAttribute()``.
+
+Proxy With HTTP Protocol
+------------------------
+
+Although the AJP protocol offers a number of nice advantages sometimes
+it's not an option. Not all servlet containers support AJP or there
+may be some other deployment constraint that precludes its use. In this
+case option 2 from above needs to be used. Option 2 requires only the
+defined HTTP protocol be used without any "out of band" metadata. The
+conventional way to attach extension metadata to a HTTP request is to
+add extension HTTP headers.
+
+One problem with using extension HTTP headers to pass metadata to a
+servlet is the expectation the servlet API will have the same
+behavior. In other words the value returned by
+``HttpServletRequest.getRemoteUser()`` should not depend on whether the
+proxy request was exchanged with the AJP protocol or the HTTP
+protocol. The solution to this is to wrap the ``HttpServletRequest``
+object in a servlet filter. The wrapper overrides certain request
+methods (e.g. ``getRemoteUser()``). The override method looks to see if
+the metadata is in the extension HTTP headers, if so it returns the
+value found in the extension HTTP header otherwise it defers to the
+existing servlet implementation. The ``ServletRequest.getAttribute()`` is
+overridden in an analogous manner in the wrapper filter. Any call to
+``ServletRequest.getAttribute()`` is first checked to see if the value
+exists in the extension HTTP header first.
+
+Metadata supplied by Apache that is **not** part of the normal Java
+EE Servlet API **always** appears to the servlet via the
+``ServletRequest.getAttribute()`` method regardless of the proxy
+transport mechanism. The consequence of this is a servlet
+continues to utilize the existing Java EE Servlet API without concern
+for intermediary proxies, *and* any other metadata supplied by a proxy
+is *always* retrieved via ``ServletRequest.getAttribute()`` (see the
+caveat about ``ServletRequest.getAttributeNames()`` [1]_).
+
+*******************
+Configuration Guide
+*******************
+
+Although Apache authentication and SSSD identity lookup can operate
+with a variety of authentication mechanisms, IdP's and identity
+metadata providers we will demonstrate a configuration example which
+utilizes the FreeIPA_ IdP. FreeIPA excels at Kerberos SSO authentication,
+Active Directory integration, LDAP based identity metadata storage and
+lookup, DNS services, host based RBAC, SSH key management, certificate
+management, friendly web based console, command line tools and many
+other advanced IdP features.
+
+The following configuration steps will need to be performed:
+
+1. Install FreeIPA_ by following the installation guides in the FreeIPA_
+   documentation area. When you install FreeIPA_ you will need to select a
+   realm (a.k.a domain) in which your users and hosts will exist. In
+   our example we will use the ``EXAMPLE.COM`` realm.
+
+2. Install and configure the Apache HTTP web server. The
+   recommendation is to install and run the Apache HTTP web server on
+   the same system the Java EE Container running AAA is installed on.
+
+3. Configure the proxy connector in the Java EE Container and set the
+   ``secureProxyPorts``.
+
+We will also illustrate the operation of the system by adding an
+example user named ``testuser`` who will be a member of the
+``odl_users`` and ``odl_admin`` groups.
+
+Add Example User and Groups to FreeIPA
+======================================
+
+After installing FreeIPA you will need to populate FreeIPA with your users,
+groups and other data. Refer to the documentation in FreeIPA_ for the
+variety of ways this task can be performed; it runs the gamut from web
+based console to command line utilities. For simplicity we will use
+the command line utilities.
+
+Identify yourself to FreeIPA as an administrator; this will give you the
+necessary privileges needed to create and modify data in FreeIPA. You do
+this by obtaining a Kerberos ticket for the ``admin`` user (or any
+other user in FreeIPA with administrator privileges.
+
+::
+
+  % kinit admin@EXAMPLE.COM
+
+Create the example ``odl_users`` and `odl_admin`` groups.
+
+::
+
+  % ipa group-add odl_users --desc 'OpenDaylight Users'
+  % ipa group-add odl_admin --desc 'OpenDaylight Administrators'
+
+Create the example user ``testuser`` with the first name "Test" and a
+last name of "User" and an email address of "test.user@example.com"
+
+::
+
+  % ipa user-add testuser --first Test --last User --email test.user@example.com
+
+Now add ``testuser`` to the ``odl_users`` and ``odl_admin`` groups.
+
+::
+
+  % ipa group-add-member odl_users --user testuser
+  % ipa group-add-member odl_admin --user testuser
+
+Configure Apache
+================
+
+A number of Apache configuration directives will need to be specified
+to implement the Apache to application binding. Although these
+configuration directives can be located in any number of different
+Apache configuration files the most sensible approach is to co-locate
+them in a single application configuration file. This greatly
+simplifies the deployment of your application and isolates your
+application configuration from other applications and services sharing
+the Apache installation. In the examples that follow our application
+will be named ``my_app`` and the Apache application configuration file
+will be named ``my_app.conf`` which should be located in Apache's
+``conf.d/`` directory. The web resource we are protecting and
+supplying identity metadata for will be named ``my_resource``.
+
+
+Configure Apache for Kerberos
+-----------------------------
+
+When FreeIPA is deployed Kerberos is the preferred authentication mechanism
+for Single Sign-On (SSO). FreeIPA also provides identity metadata via
+Apache ``mod_identity_lookup``. To protect your ``my_resource`` resource
+with Kerberos authentication identify your resource as requiring
+Kerberos authentication in your ``my_app.conf`` Apache
+configuration. For example:
+
+::
+
+  <Location my_resource>
+    AuthType Kerberos
+    AuthName "Kerberos Login"
+    KrbMethodNegotiate On
+    KrbMethodK5Passwd Off
+    KrbAuthRealms EXAMPLE.COM
+    Krb5KeyTab /etc/http.keytab
+    require valid-user
+  </Location>
+
+You will need to replace EXAMPLE.COM in the KrbAuthRealms declaration
+with the Kerberos realm for your deployment.
+
+
+Configure SSSD IFP
+------------------
+
+To use the Apache ``mod_identity_lookup`` module to supply identity
+metadata you need to do the following in ``my_app.conf``:
+
+1. Enable the module
+
+   ::
+
+     LoadModule lookup_identity_module modules/mod_lookup_identity.so
+
+2. Apply the identity metadata lookup to specific URL's
+   (e.g. ``my_resource``) via an Apache location directive. In this
+   example we look up the "mail" attribute and assign it to the
+   REMOTE_USER_EMAIL environment variable.
+
+   ::
+
+     <LocationMatch "my_resource">
+       LookupUserAttr mail REMOTE_USER_EMAIL
+     </LocationMatch>
+
+3. Export the environment variable via the desired proxy protocol, see
+   `Exporting Environment Variables to the Proxy`_
+
+Exporting Environment Variables to the Proxy
+--------------------------------------------
+
+First you need to decide which proxy protocol you're going to use, AJP
+or HTTP and then determine the target address and port to proxy to. The
+recommended configuration is to run both the Apache server and the
+servlet container on the same host and to proxy requests over the
+local loopback interface (see `Declaring the Connector Ports for
+Authentication Proxies`_). In our examples we'll use port 8383. Thus
+in ``my_app.conf`` add a proxy declaration.
+
+For HTTP Proxy
+
+::
+
+   ProxyPass / http://localhost:8383/
+   ProxyPassReverse / http://localhost:8383/
+
+For AJP Proxy
+
+::
+
+   ProxyPass / ajp://localhost:8383/
+   ProxyPassReverse / ajp://localhost:8383/
+
+AJP Exports
+^^^^^^^^^^^
+
+AJP automatically forwards REMOTE_USER and AUTH_TYPE making them
+available to the ``HttpServletRequest`` API, thus you do not need to
+explicitly forward these in the proxy configuration. However all other
+``mod_identity_lookup`` metadata must be explicitly forwarded as an AJP
+attribute. These AJP attributes become visible in the
+``ServletRequest.getAttribute()`` method [1]_.
+
+The Apache ``mod_proxy_ajp`` module automatically sends any Apache
+environment variable prefixed with "AJP\_" as an AJP attribute which
+can be retrieved with ``ServletRequest.getAttribute()``. Therefore the
+``mod_identity_lookup`` directives which specify the Apache environment
+variable to set with the result of a lookup must be prefixed with
+"AJP\_". Using the above example of looking up the principal's email
+address we modify the environment variable to include the "AJP\_"
+prefix. Thusly:
+
+   ::
+
+     <LocationMatch "my_resource">
+       LookupUserAttr mail AJP_REMOTE_USER_EMAIL
+     </LocationMatch>
+
+The sequence of events is as follows:
+
+  1. When the URL matches "my_resource".
+
+  2. ``mod_identity_lookup`` retrieves the mail attribute for the
+     principal.
+
+  3. ``mod_identity_lookup`` assigns the value of the mail attribute
+     lookup to the AJP_REMOTE_USER_EMAIL Apache environment variable.
+
+  4. ``mod_proxy_ajp`` encodes AJP_REMOTE_USER_EMAIL environment
+     variable into an AJP attribute in the AJP protocol because the
+     environment variable is prefixed with "AJP\_". The name of the
+     attribute is stripped of it's "AJP\_" prefix thus the
+     AJP_REMOTE_USER_EMAIL environment variable is transferred as the
+     AJP attribute REMOTE_USER_EMAIL.
+
+  5. The request is forwarded (i.e. proxied) to servlet container
+     using the AJP protocol.
+
+  6. The servlet container's AJP ``Connector`` object is assigned each AJP
+     attribute to the set of attributes on the ``ServletRequest``
+     attribute list. Thus a call to
+     ``ServletRequest.getAttribute("REMOTE_USER_EMAIL")`` yields the
+     value set by ``mod_identity_lookup``.
+
+
+HTTP Exports
+^^^^^^^^^^^^
+
+When HTTP proxy is used there are no automatic or implicit metadata
+transfers; every metadata attribute must be explicitly handled on both
+ends of the proxy connection. All identity metadata attributes are
+transferred as extension HTTP headers, by convention those headers are
+prefixed with "X-SSSD-".
+
+Using the original example of looking up the principal's email
+address we must now perform two independent actions:
+
+  1. Lookup the value via ``mod_identity_lookup`` and assign to an
+     Apache environment variable.
+
+  2. Export the environment variable in the request header with the
+     "X-SSSD-" prefix.
+
+   ::
+
+     <LocationMatch "my_resource">
+       LookupUserAttr mail REMOTE_USER_EMAIL
+       RequestHeader set X-SSSD-REMOTE_USER_EMAIL %{REMOTE_USER_EMAIL}e
+     </LocationMatch>
+
+The sequence of events is as follows:
+
+  1. When the URL matches "my_resource".
+
+  2. ``mod_identity_lookup`` retrieves the mail attribute for the
+     principal.
+
+  3. ``mod_identity_lookup`` assigns the value of the mail attribute
+     lookup to the REMOTE_USER_EMAIL Apache environment variable.
+
+  4. Apache's RequestHeader directive executes just prior to the
+     request being forwarded (i.e. in the Apache fixup stage). It adds
+     the header X-SSSD-REMOTE_USER_EMAIL and assigns the value for
+     REMOTE_USER_EMAIL found in the set of environment variables. It
+     does this because the syntax %{XXX} is a variable reference for
+     the name XXX and the 'e' appended after the closing brace
+     indicates the lookup is to be performed in the set of environment
+     variables.
+
+  5. The request is forwarded (i.e. proxied) to the servlet container
+     using the HTTP protocol.
+
+  6. When ``ServletRequest.getAttribute()`` is called the ``SssdFilter``
+     wrapper intercepts the ``getAttribute()`` method. It looks for an
+     HTTP header of the same name with "X-SSSD-" prefixed to it. In
+     this case ``getAttribute("REMOTE_USER_EMAIL")`` causes the lookup of
+     "X-SSSD-REMOTE_USER_EMAIL" in the HTTP headers, if found that
+     value is returned.
+
+AJP Proxy Example Configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you are using AJP proxy to the Java EE Container on port 8383 your
+``my_app.conf`` Apache configuration file will probably look like
+this:
+
+::
+
+  <LocationMatch "my_resource">
+
+    ProxyPass / ajp://localhost:8383/
+    ProxyPassReverse / ajp://localhost:8383/
+
+    LookupUserAttr mail AJP_REMOTE_USER_EMAIL " "
+    LookupUserAttr givenname AJP_REMOTE_USER_FIRSTNAME
+    LookupUserAttr sn AJP_REMOTE_USER_LASTNAME
+    LookupUserGroups AJP_REMOTE_USER_GROUPS ":"
+
+  </LocationMatch>
+
+Note the specification of the colon separator for the
+``LookupUserGroups`` operation. [3]_
+
+HTTP Proxy Example Configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you are using a conventional HTTP proxy to the Java EE Container on
+port 8383 your ``my_app.conf`` Apache configuration file will probably
+look like this:
+
+::
+
+  <LocationMatch "my_resource">
+
+    ProxyPass / http://localhost:8383/
+    ProxyPassReverse / http://localhost:8383/
+
+    RequestHeader set X-SSSD-REMOTE_USER expr=%{REMOTE_USER}
+    RequestHeader set X-SSSD-AUTH_TYPE expr=%{AUTH_TYPE}
+    RequestHeader set X-SSSD-REMOTE_HOST expr=%{REMOTE_HOST}
+    RequestHeader set X-SSSD-REMOTE_ADDR expr=%{REMOTE_ADDR}
+
+    LookupUserAttr mail REMOTE_USER_EMAIL
+    RequestHeader set X-SSSD-REMOTE_USER_EMAIL %{REMOTE_USER_EMAIL}e
+
+    LookupUserAttr givenname REMOTE_USER_FIRSTNAME
+    RequestHeader set X-SSSD-REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e
+
+    LookupUserAttr sn REMOTE_USER_LASTNAME
+    RequestHeader set X-SSSD-REMOTE_USER_LASTNAME %{REMOTE_USER_LASTNAME}e
+
+    LookupUserGroups REMOTE_USER_GROUPS ":"
+    RequestHeader set X-SSSD-REMOTE_USER_GROUPS %{REMOTE_USER_GROUPS}e
+
+  </LocationMatch>
+
+Note the specification of the colon separator for the
+``LookupUserGroups`` operation. [3]_
+
+
+Configure Java EE Container Proxy Connector
+===========================================
+
+The Java EE Container must be configured to listen for connections
+from the Apache web server. A Java EE Container specifies connections
+via a ``Connector`` object. A ``Connector`` **must** be dedicated
+**exclusively** for handling authenticated requests from the Apache
+web server. The reason for this is explained in `The Proxy
+Problem`_. In addition ``ClaimAuthFilter`` needs to validate that any
+request it processes originated from the trusted Apache instance. This
+is accomplished by dedicating one or more ports exclusively for use by
+the trusted Apache server and enumerating them in the
+``secureProxyPorts`` configuration as explained in `Locking Down the
+Apache to Java EE Container Channel`_ and `Declaring the Connector
+Ports for Authentication Proxies`_.
+
+Configure Tomcat Proxy Connector
+--------------------------------
+
+The Tomcat Java EE Container defines Connectors in its ``server.xml``
+configuration file.
+
+::
+
+    <Connector
+        address="127.0.0.1"
+        port="8383"
+        protocol="HTTP/1.1"
+        tomcatAuthentication="false"
+        connectionTimeout="20000"
+        redirectPort="8443"
+    />
+
+
+:address:
+  This should be the loopback address as explained `Locking Down the
+  Apache to Java EE Container Channel`_.
+
+:port:
+  In our examples we've been using port 8383 as the proxy port. The
+  exact port is not important but it must be consistent with the
+  Apache proxy port, the ``Connector`` declaration, and the port value
+  in ``secureProxyPorts``.
+
+:protocol:
+  As explained in `Transporting Identity Metadata from Apache to a
+  Java EE Servlet`_ you will need to decide if you are using HTTP or
+  AJP as the proxy protocol. In the example above the protocol is set
+  for HTTP, if you use AJP instead the protocol should instead be
+  "AJP/1.3".
+
+:tomcatAuthentication:
+  This boolean flag tells Tomcat whether Tomcat should perform
+  authentication on the incoming requests or not. Since authentication
+  is performed by Apache we do not want Tomcat to perform
+  authentication therefore this flag must be set to false.
+
+The AAA system needs to know which port(s) the trusted Apache proxy
+will be sending requests on so it can trust the request authentication
+metadata. See `Declaring the Connector Ports for Authentication
+Proxies`_ for more information). Set ``secureProxyPorts`` in the
+FederationConfiguration.
+
+::
+
+  secureProxyPorts=8383
+
+
+Configure Jetty Proxy Connector
+-------------------------------
+
+The Jetty Java EE Container defines Connectors in its ``jetty.xml``
+configuration file.
+
+::
+
+    <!-- Trusted Authentication Federation proxy connection -->
+    <Call name="addConnector">
+        <Arg>
+            <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+                <Set name="host">127.0.0.1</Set>
+                <Set name="port">8383</Set>
+                <Set name="maxIdleTime">300000</Set>
+                <Set name="Acceptors">2</Set>
+                <Set name="statsOn">false</Set>
+                <Set name="confidentialPort">8445</Set>
+                <Set name="name">federationConn</Set>
+                <Set name="lowResourcesConnections">20000</Set>
+                <Set name="lowResourcesMaxIdleTime">5000</Set>
+            </New>
+        </Arg>
+    </Call>
+
+:host:
+  This should be the loopback address as explained `Locking Down the
+  Apache to Java EE Container Channel`_.
+
+:port:
+  In our examples we've been using port 8383 as the proxy port. The
+  exact port is not important but it must be consistent with the
+  Apache proxy port, the ``Connector`` declaration, and the port value
+  in ``secureProxyPorts``.
+
+
+Note, values in Jetty XML can also be parameterized so that they may
+be passed from property files or set on the command line. Thus
+typically the port is set within Jetty XML, but uses the Property
+element to be customizable. Thus the above ``host`` and ``port``
+properties could be specificed this way:
+
+::
+
+    <Set name="host">
+        <Property name="jetty.host" default="127.0.0.1"/>
+    </Set>
+    <Set name="port">
+        <Property name="jetty.port" default="8383"/>
+    </Set>
+
+
+The AAA system needs to know which port(s) the trusted Apache proxy
+will be sending requests on so it can trust the request authentication
+metadata. See `Declaring the Connector Ports for Authentication
+Proxies`_ for more information). Set ``secureProxyPorts`` in the
+FederationConfiguration.
+
+************************************************
+How Apache Identity Metadata is Processed in AAA
+************************************************
+
+`Figure 2.`_ and `Figure 3.`_ illustrates the fact the first stage in
+processing a request from a user begins with Apache where the user is
+authenticated and SSSD supplies additional metadata about the
+user. The original request along with the metadata are subsequently
+forwarded by Apache to the Java EE Container. `Figure 4.`_ illustrates
+the processing inside the Java EE Container once it receives the
+request on one of its secure connectors.
+
+
+.. figure:: sssd_04.png
+   :align: center
+
+   _`Figure 4.`
+
+:Step 1:
+  One or more Connectors have been configured to listen for requests
+  being forwarded from a trusted Apache instance. The Connector is
+  configured to communicate using either the HTTP or AJP protocols.
+  See `Exporting Environment Variables to the Proxy`_ for more
+  information on selecting a proxy transport protocol.
+
+:Step 2:
+  The identity metadata bound to the request needs to be extracted
+  differently depending upon whether HTTP or AJP is the transport
+  protocol. To allow later stages in the pipeline to be ignorant of
+  the transport protocol semantics the ``SssdFilter`` servlet filter
+  is introduced. The ``SssdFilter`` wraps the ``HttpServletRequest``
+  class and intercepts calls which might return the identity
+  metadata. The wrapper in the filter looks in protocol specific
+  locations for the metadata. In this manner users of the
+  ``HttpServletRequest`` are isolated from protocol differences.
+
+
+:Step 3:
+
+  The ``ClaimAuthFilter`` is responsible for determining if identity
+  metadata is bound to the request. If so all identity metadata is
+  packaged into an assertion which is then handed off to
+  ``SssdClaimAuth`` which will transform the identity metadata in the
+  assertion into a AAA Claim which is the authorizing token for the user.
+
+:Step 4:
+  The ``SssdClaimAuth`` object is responsible for transforming the
+  external federated identity metadata provided by Apache and SSSD into
+  a AAA claim. The AAA claim is an authorization token which includes
+  information about the user plus a set of roles. These roles provide the
+  authorization to perform AAA tasks. Although how roles are assigned is
+  flexible the expectation is domain and/or group membership will be the
+  primary criteria for role assignment. Because deciding how to handle
+  external federated identity metadata is site and deployment specific
+  we need a loadable policy mechanism. This is accomplished by a set of
+  transformation rules which transforms the incoming IdP identity
+  metadata into a AAA claim. For greater clarity this important step is
+  broken down into smaller units in the shaded box in `Figure 4.`_.
+
+:Step 4.1:
+  `The Mapping Rule Processor`_ is designed to accept a JSON object
+  (set of key/value pairs) as input and emit a different JSON object
+  as output effectively operating as a transformation engine on
+  key/value pairs.
+
+:Step 4.2:
+  The input assertion is rewritten as a JSON object in the format
+  required by the Mapping Rule Processor. The JSON assertion is then
+  passed into the Mapping Rule Processor.
+
+:Step 4.3:
+  `The Mapping Rule Processor`_ identified as ``IdPMapper`` evaluates
+  the input JSON assertion in the context of the mapping rules defined
+  for the site deployment. If ``IdPMapper`` is able to successfully
+  transform the input it will return a JSON object which we called the
+  *mapped* result. If the input JSON assertion is not compatible with
+  the site specific rules loaded into the ``IdPMapper`` then NULL is
+  returned by the ``IdPMapper``.
+
+:Step 4.4:
+  If a mapped JSON object is returned by the ``IdPMapper`` the mapping
+  was successful. The values in the mapped result are re-written into
+  an AAA Claim token.
+
+How Apache Identity Metadata is Mapped to AAA Values
+====================================================
+
+A federated IdP supplies metadata in a form unique to the IdP. This is
+called an assertion. That assertion must be transformed into a format
+and data understood by AAA. More importantly that assertion needs to
+yield *authorization roles specific to AAA*. In `Figure 4.`_ Step 4.3
+the ``IdPMapper`` provides the transformation from an external IdP
+assertion to an AAA specific claim. It does this via a Mapping Rule
+Processor which reads a site specific set of transformation
+rules. These mapping rules define how to transform an external IdP
+assertion into a AAA claim. The mapping rules also are responsible for
+validating the external IdP claim to make sure it is consistent with
+the site specific requirements. The operation of the Mapping Rule
+Processor and the syntax of the mapping rules are defined in `The
+Mapping Rule Processor`_.
+
+Below is an example mapping rule which might be loaded into the
+Mapping Rule Processor. It is assumed there are two AAA roles which
+may be assigned [4]_:
+
+``user``
+  A role granting standard permissions for normal ODL users.
+
+``admin``
+  A special role granting full administrative permissions.
+
+In this example assigning the ``user`` and ``admin`` roles
+will be based on group membership in the following groups:
+
+``odl_users``
+  Members of this group are normal ODL users with restricted permissions.
+
+``odl_admin``
+  Members of this group are ODL administrators with permission to
+  perform all operations.
+
+Granting of the ``user`` and/or ``admin`` roles based on
+membership in the ``odl_users`` and ``odl_admin`` is illustrated in
+the follow mapping rule example which also extracts the user principal
+and domain information in the preferred format for the site
+(e.g. usernames are lowercase without domain suffixes and the domain
+is uppercase and supplied separately).
+
+_`Mapping Rule Example 1.`
+
+::
+
+  1   [
+  2     {"mapping": {"ClientId": "$client_id",
+  3            "UserId": "$user_id",
+  4            "User": "$username",
+  5            "Domain": "$domain",
+  6            "roles": "$roles",
+  7           },
+  8      "statement_blocks": [
+  9        [
+  10         ["set", "$groups", []],
+  11         ["set", "$roles", []]
+  12       ],
+  13       [
+  14         ["in", "REMOTE_USER", "$assertion"],
+  15         ["exit", "rule_fails", "if_not_success"],
+  16         ["regexp", "$assertion[REMOTE_USER]", "(?<username>\\w+)@(?<domain>.+)"],
+  17         ["exit", "rule_fails", "if_not_success"],
+  18         ["lower", "$username", "$regexp_map[username]"],
+  19         ["upper", "$domain", "$regexp_map[domain]"],
+  20       ],
+  21       [
+  22         ["in", "REMOTE_USER_GROUPS", "$assertion"],
+  23         ["exit", "rule_fails", "if_not_success"],
+  24         ["split", "$groups", "$assertion[REMOTE_USER_GROUPS]", ":"],
+  25       ],
+  26       [
+  27         ["in", "odl_users", "$groups"],
+  28         ["continue", "if_not_success"],
+  29         ["append", "$roles", "user"],
+  30       ],
+  31       [
+  32         ["in", "odl_admin", "$groups"],
+  33         ["continue", "if_not_success"],
+  34         ["append", "$roles", "admin"]
+  35       ],
+  36       [
+  37         ["unique", "$roles", "$roles"],
+  38         ["length", "$n_roles", "$roles"],
+  39         ["compare", "$n_roles", ">", 0],
+  40         ["exit", "rule_fails", "if_not_success"],
+  41       ],
+  42     ]
+  43    }
+  44  ]
+
+:Line 1:
+  Starts a list of rules. In this example only 1 rule is defined. Each
+  rule is a JSON object containing a ``mapping`` and a required list
+  of ``statement_blocks``. The ``mapping`` may either be specified
+  inside a rule as it is here or may be referenced by name in a table
+  of mappings (this is easier to manage if you have a large number of
+  rules and small number of mappings).
+
+:Lines 2-7:
+  Defines the JSON mapped result. Each key maps to AAA claim.  The
+  value is a rule variable whose value will be substituted if the rule
+  succeeds.  Thus for example the AAA claim value ``User`` will be
+  assigned the value from the ``$username`` rule variable.
+:Line 8:
+  Begins the list of statement blocks. A statement must be contained
+  inside a block.
+:Lines 9-12:
+  The first block usually initializes variables that will be
+  referenced later. Here we initialize ``$groups`` and ``$roles`` to
+  empty arrays. These arrays may be appended to in later blocks and
+  may be referenced in the final ``mapping`` output.
+:Lines 13-20:
+  This block sets the user and domain information based on
+  ``REMOTE_USER`` and exits the rule if ``REMOTE_USER`` is not defined.
+:Lines 14-15:
+  This test is critical, it assures ``REMOTE_USER`` is defined in the
+  assertion, if not the rule is skipped because we depend on
+  ``REMOTE_USER``.
+:Lines 16-17:
+  Performs a regular expression match against ``REMOTE_USER`` to split
+  the username from the domain. The regular expression uses named
+  groups, in this instance ``username`` and ``domain``. If the regular
+  expression does not match the rule is skipped.
+:Lines 18-19:
+  These lines reference the previous result of the regular expression
+  match which are stored in the special variable ``$regexp_map``. The
+  username is converted to lower case and stored in ``$username`` and
+  the domain is converted to upper case and stored in ``$domain``. The
+  choice of case is purely by convention and site requirements.
+:Lines 21-35:
+  These 3 blocks assign roles based on group membership.
+:Lines 21-25:
+  Assures ``REMOTE_USER_GROUPS`` is defined in the assertion; if not, the
+  rule is skipped. ``REMOTE_USER_GROUPS`` is colon separated list of group
+  names. In order to operate on the individual group names appearing
+  in ``REMOTE_USER_GROUPS`` line 24 splits the string on the colon
+  separator and stores the result in the ``$groups`` array.
+:Lines 27-30:
+  This block assigns the ``user`` role if the user is a member of the
+  ``odl_users`` group.
+:Lines 31-35:
+  This block assigns the ``admin`` role if the user is a
+  member of the ``odl_admin`` group.
+:Lines 36-41:
+  This block performs final clean up actions for the rule. First it
+  assures there are no duplicates in the ``$roles`` array by calling
+  the ``unique`` function. Then it gets a count of how many items are
+  in the ``$roles`` array and tests to see if it's empty. If there are
+  no roles assigned the rule is skipped.
+:Line 43:
+  This is the end of the rule. If we reach the end of the rule it
+  succeeds. When a rule succeeds the mapping associated with the rule
+  is looked up. Any rule variable appearing in the mapping is
+  substituted with its value.
+
+Using the rules in `Mapping Rule Example 1.`_ and following example assertion
+in JSON format:
+
+_`Assertion Example 1.`
+
+::
+
+  {
+    "REMOTE_USER": "TestUser@example.com",
+    "REMOTE_AUTH_TYPE": "Negotiate",
+    "REMOTE_USER_GROUPS": "odl_users:odl_admin",
+    "REMOTE_USER_EMAIL": "test.user@example.com",
+    "REMOTE_USER_FIRSTNAME": "Test",
+    "REMOTE_USER_LASTNAME": "User"
+  }
+
+Then the mapper will return the following mapped JSON document. This
+is the ``mapping`` defined on line 2 of `Mapping Rule Example 1.`_ with the
+variables substituted after the rule successfully executed. Note any
+valid JSON data type can be returned, in this example the ``null``
+value is returned for ``ClientId`` and ``UserId``, normal strings for
+``User`` and ``Domain`` and an array of strings for the ``roles`` value.
+
+_`Mapped Result Example 1.`
+
+::
+
+  {
+    "ClientId": null,
+    "UserId": null,
+    "User": "testuser",
+    "Domain": "EXAMPLE.COM",
+    "roles": ["user", "admin"]
+  }
+
+
+**************************
+The Mapping Rule Processor
+**************************
+
+The Mapping Rule Processor is designed to be as flexible and generic
+as possible. It accepts a JSON object as input and returns a JSON
+object as output. JSON was chosen because virtually all data can be
+represented in JSON, JSON has extensive support and JSON is human
+readable. The rules loaded into the Mapping Rule Processor are also
+expressed in JSON. One advantage of this is it makes it easy for a
+site administrator to define hardcoded values which are always
+returned and/or static tables of white and black listed users or users
+who are always mapped into certain roles.
+
+.. include:: mapping.rst
+
+***********************
+Security Considerations
+***********************
+
+Attack Vectors
+==============
+
+A Java EE Container fronted by Apache has by definition 2 major
+components:
+
+* Apache
+* Java EE Container
+
+Each of these needs to be secure in its own right. There is extensive
+documentation on securing each of these components and the reader is
+encouraged to review this material. For the purpose of this discussion
+we are most interested in how Apache and the Java EE
+Container cooperate to form an integrated security system. Because
+Apache is performing authentication on behalf of the Java EE Container,
+it views Apache as a trusted partner. Our primary concern is the
+communication channel between Apache and the Java EE Container. We
+must assure the Java EE Container knows who it's trusted partner is
+and that it only accepts security sensitive data from that partner,
+this can best be described as `The Proxy Problem`_.
+
+Forged REMOTE_USER
+------------------
+
+HTTP request handling is often implemented as a processing pipeline
+where individual handlers are passed the request, they may then attach
+additional metadata to the request or transform it in some manner
+before handing it off to the next stage in the pipeline. A request
+handler may also short circuit the request processing pipeline and
+cause a response to be generated. Authentication is typically
+implemented an as early stage request handler. If a request gets past
+an authentication handler later stage handlers can safely assume the
+request belongs to an authenticated user. Authorization metadata may
+also have been attached to the request. Later stage handlers use the
+authentication/authorization metadata to make decisions as to whether
+the operations in the request can be satisfied.
+
+When a request is fielded by a traditional web server with CGI (Common
+Gateway Interface, RFC 3875) the request metadata is passed via CGI
+meta-variables. CGI meta-variables are often implemented as environment
+variables, but in practical terms CGI metadata is really just a set of
+name/value pairs a later stage (i.e. CGI script, servlet, etc.) can
+reference to learn information about the request.
+
+The CGI meta-variables REMOTE_USER and AUTH_TYPE relate to
+authentication. REMOTE_USER is the identity of the authenticated user
+and AUTH_TYPE is the authentication mechanism that was used to
+authenticate the user.
+
+**If a later stage request handler sees REMOTE_USER and AUTH_TYPE as
+non-null values it assumes the user is fully authenticated! Therefore
+is it essential REMOTE_USER and AUTH_TYPE can only enter the request
+pipeline via a trusted source.**
+
+The Proxy Problem
+=================
+
+In a traditional monolithic web server the CGI meta-variables are
+created and managed by the web server, which then passes them to CGI
+scripts and executables in a very controlled environment where they
+execute in the context of the web server. Forgery of CGI
+meta-variables is generally not possible unless the web server has
+been compromised in some fashion.
+
+However in our configuration the Apache web server acts as an identity
+processor, which then forwards (i.e. proxies) the request to the Java
+EE container (i.e Tomcat, Jetty, etc.). One could think of the Java
+EE container as just another CGI script which receives CGI
+meta-variables provided by the Apache web server. Where this analogy
+breaks down is how Apache invokes the CGI script. Instead of forking a
+child process where the child's environment and input/output pipes are
+carefully controlled by Apache the request along with its additional
+metadata is forwarded over a transport (typically TCP/IP) to another
+process, the proxy, which listens on socket.
+
+The proxy (in this case the Java EE container) reads the request and
+the attached metadata and acts upon it. If the request read by the
+proxy contains the REMOTE_USER and AUTH_TYPE CGI meta-variables the
+proxy will consider the request **fully authenticated!**. Therefore
+when the Java EE container is configured as a proxy it is
+**essential** it only reads requests from a **trusted** Apache web
+server. If any other client aside from the trusted Apache web server
+is permitted to connect to the Java EE container that client could
+present forged REMOTE_USER and AUTH_TYPE meta-variables, which would be
+automatically accepted as valid thus opening a huge security hole.
+
+
+Possible Approaches to Lock Down a Proxy Channel
+================================================
+
+Tomcat Valves
+-------------
+
+You can use a `Tomcat Remote Address Valve`_ valve to filter by IP or
+hostname to only allow a subset of machines to connect. This can be
+configured at the Engine, Host, or Context level in the
+conf/server.xml by adding something like the following:
+
+::
+
+  <!-- allow only LAN IPs to connect -->
+  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
+   allow="192.168.1.*">
+  </Valve>
+
+The problem with valves is they are a Tomcat only concept, the
+``RemoteAddrValve`` only checks addresses, not port numbers (although
+it should be easy to add port checking) and they don't offer anything
+better than what is described in `Locking Down the Apache to Java EE
+Container Channel`_, which is not container specific. Servlet filters
+are always available regardless of the container the servlet is
+running in. A filter can check both the address and port number and
+refuse to operate on the request if the address and port are not known to
+be a trusted authentication proxy. Also note that if the Java EE
+Container is configured to accept connections other than from the
+trusted HTTP proxy server (a very likely scenario) then filtering at
+the connector level is not sufficient because a servlet which trusts
+``REMOTE_USER`` must be assured the request arrived only on a
+trusted HTTP proxy server connection, not one of the other possible
+connections.
+
+SSL/TLS with client auth
+------------------------
+
+SSL with client authentication is the ultimate way to lock down a HTTP
+Server to Java EE Container proxy connection. SSL with client
+authentication provides authenticity, integrity, and
+confidentiality. However those desirable attributes come at a
+performance cost which may be excessive. Unless a persistent TCP
+connection is established between the HTTP server and the Java EE
+Container a SSL handshake will need to occur on each request being
+proxied, SSL handshakes are expensive. Given that the HTTP server and
+the Java EE Container will likely be deployed on the same compute node
+(or at a minimum on a secure subnet) the advantage of SSL for proxy
+connections may not be warranted because other options are available
+for these configuration scenarios; see `Locking Down the Apache to Java EE
+Container Channel`_. Also note that if the Java EE
+Container is configured to accept connections other than from the
+trusted HTTP proxy server (a very likely scenario), then filtering at
+the connector level is not sufficient because a servlet which trusts
+``REMOTE_USER`` must be assured that the request arrived only on a
+trusted HTTP proxy server connection, not one of the other possible
+connections.
+
+
+Java Security Manager Permissions
+---------------------------------
+
+The Java Security Manager allows you define permissions which are
+checked at run time before code executes.
+``java.net.SocketPermission`` and ``java.net.NetPermission`` would
+appear to offer solutions for restricting which host and port a
+request containing ``REMOTE_USER`` will be trusted. However security
+permissions are applied *after* a request is accepted by a
+connector. They are also more geared towards what connections code can
+subsequently utilize as opposed to what connection a request was
+presented on. Therefore security manager permissions seem to offer little
+value for our purpose. One can simply test to see which host sent the
+proxy request and on what port it arrived on by looking at the
+connection information in the request. Restricting which proxies can
+submit trusted requests is better handled at the level of the
+connector, which unfortunately is a container implementation
+issue. Tomcat and Jetty have different ways of handling connector
+specifications.
+
+AJP requiredSecret
+------------------
+
+The AJP protocol includes an attribute called ``requiredSecret``, which
+can be used to secure the connection between AJP endpoints. When an
+HTTP server sends an AJP proxy request to a Java EE Container it
+embeds in the protocol transmission a string (``requiredSecret``)
+known only to the HTTP server and the Java EE Container. The AJP
+connector on the Java EE Container is configured with the
+``requiredSecret`` value and will reject as unauthorized any AJP
+requests whose ``requiredSecret`` does not match.
+
+There are two problems with `requiredSecret``. First of all it's not
+particularly secure. In fact, it's fundamentally no different than
+sending a cleartext password. If the AJP request is not encrypted it
+means the ``requiredSecret`` will be sent in the clear which is
+probably one of the most egregious security mistakes. If the AJP
+request is transmitted in a manner where the traffic can be sniffed, it
+would be trivial to recover the ``requiredSecret`` and forge a request
+with it. On the other hand encrypting the communication channel
+between the HTTP server and the Java EE Container means using SSL
+which is fairly heavyweight. But more to the point, if one is using
+SSL to encrypt the channel there is a *far better* mechanism to ensure
+the HTTP server is who it claims to be than embedding
+``requiredSecret``. If one is using SSL you might as well use SSL
+client authentication where the HTTP identifies itself via a client
+certificate. SSL client authentication is a very robust authentication
+mechanism. But doing SSL client authentication, or for that matter
+just SSL encryption, for *every* AJP protocol request is prohibitively
+expensive from a performance standpoint.
+
+The second problem with ``requiredSecret`` is that despite being documented
+in a number of places it's not actually implemented in Apache
+``mod_proxy_ajp``. This is detailed in `bug 53098`_. You can set
+``requiredSecret`` in the ``mod_proxy_ajp`` configuration, but it won't
+be included in the wire protocol. There is a patch to implement
+``requiredSecret`` but, it hasn't made it into any shipping version of
+Apache yet. But even if ``requiredSecret`` was implemented it's not
+useful. Also one could construct the equivalent of ``requiredSecret``
+from other AJP attributes and/or an HTTP extension header but those
+would suffer from the same security issues ``requiredSecret`` has,
+therefore it's mostly pointless.
+
+Java EE Container Issues
+========================
+
+Jetty Issues
+------------
+
+Jetty is a Java EE Container which can be used
+as alternative to Tomcat. Jetty is an Eclipse project. Recent versions
+of Jetty have dropped support for AJP; this is described in the
+`Jetty AJP Configuration Guide`_ which states:
+
+  Configuring AJP13 Using mod_jk or mod_proxy_ajp. Support for this
+  feature has been dropped with Jetty 9.  If you feel this should be
+  brought back please file a bug.
+
+Eclipse `Bug 387928`_ *Retire jetty-ajp* was opened to track the
+removal of AJP in Jetty and is now closed.
+
+Tomcat Issues
+-------------
+
+You should refer the `Tomcat Security How-To`_ for a full discussion
+of Tomcat security issues.
+
+The tomcatAuthentication attribute is used with the AJP connectors to
+determine if Tomcat should authenticate the user or if authentication
+can be delegated to the reverse proxy that will then pass the
+authenticated username to Tomcat as part of the AJP protocol.
+
+The requiredSecret attribute in AJP connectors configures a shared
+secret between Tomcat and the reverse proxy in front of Tomcat. It is used
+to prevent unauthorized connections over AJP protocol.
+
+Locking Down the Apache to Java EE Container Channel
+====================================================
+
+The recommended approach to lock down the proxy channel is:
+
+  * Run both Apache and the servlet container on the same host.
+
+  * Configure Apache to forward the proxy request on the loopback
+    interface (e.g. 127.0.0.1 also known as ``localhost``). This
+    prohibits any external IP address from connecting, only processes
+    running on the locked down host can communicate over
+    ``localhost``.
+
+  * Reserve one or more ports for communication **exclusively** for
+    proxy communication between Apache and the servlet container. The
+    servlet container may listen on other ports for non-critical
+    non-authenticated requests.
+
+  * The ``ClaimAuthFilter`` that reads the identity metadata **must**
+    assure that requests have arrived only on a **trusted port**. To
+    achieve this the ``FederationConfiguration`` defines the
+    ``secureProxyPorts`` configuration option. ``secureProxyPorts`` is
+    a space delimited list of ports which during deployment the
+    administrator has configured such that they are **exclusively**
+    dedicated for use by the Apache server(s) providing authentication
+    and identity information. These ports are set in the servlet
+    container's ``Connector`` declarations. See `Declaring the
+    Connector Ports for Authentication Proxies`_ for more
+    information).
+
+  * When the ``ClaimAuthFilter`` receives a request, the first thing
+    it does is check the ``ServletRequest.getLocalPort()`` value and
+    verifies it is a member of the ``secureProxyPorts`` configuration
+    option. If the port is a member of ``secureProxyPorts``, it will
+    trust every identity assertion found in the request. If the local
+    port is not a member of ``secureProxyPorts``, a HTTP 401
+    (unauthorized) error status will be returned for the request. A
+    warning message will be logged the first time this occurs.
+
+
+Declaring the Connector Ports for Authentication Proxies
+--------------------------------------------------------
+
+As described in `The Proxy Problem`_ the AAA authentication system
+**must** confirm the request it is processing originated from a *trusted
+HTTP proxy server*. This is accomplished with port isolation.
+
+The administrator deploying a federated AAA solution with SSSD
+identity lookups must declare in the AAA federation configuration
+which ports the proxy requests from the trusted HTTP server will
+arrive on by setting the ``secureProxyPorts`` configuration
+item. These ports **must** only be used for the trusted HTTP proxy
+server. The AAA federation software will not perform authentication
+for any request arriving on a port other than those listed in
+``secureProxyPorts``.
+
+.. figure:: sssd_05.png
+   :align: center
+
+   _`Figure 5.`
+
+``secureProxyPorts`` configuration option is set either in the
+``federation.cfg`` file or in the
+``org.opendaylight.aaa.federation.secureProxyPorts`` bundle
+configuration. ``secureProxyPorts`` is a space-delimited list of port
+numbers on which a trusted HTTP proxy performing authentication
+forwards pre-authenticated requests. For example:
+
+::
+
+  secureProxyPorts=8383
+
+Means a request which arrived on port 8383 is from a trusted HTTP
+proxy server and the value of ``REMOTE_USER`` and other authentication
+metadata in request can be trusted.
+
+########
+Appendix
+########
+
+*****************
+CGI Export Issues
+*****************
+
+Apache processes requests as a series of steps in a pipeline
+fashion. The ordering of these steps is important. Core Apache is
+fairly minimal, most of Apache's features are supplied by loadable
+modules. When a module is loaded it registers a set of *hooks*
+(function pointers) which are to be run at specific stages in the
+Apache request processing pipeline. Thus a module can execute code at
+any of a number of stages in the request pipeline.
+
+The user metadata supplied by Apache is initialized in two distinct
+parts of Apache.
+
+  1. an authentication module (e.g. mod_auth_kerb)
+  2. the ``mod_lookup_identity`` module.
+
+After successful authentication the authentication module will set the
+name of the user principal and the mechanism used for authentication
+in the request structure.
+
+  * ``request->user``
+  * ``request->ap_auth_type``
+
+Authentication hooks run early in the request pipeline for the obvious
+reason a request should not be processed if not authenticated. The
+specific authentication module that runs is defined by ``Location``
+directive in the Apache configuration which binds specific
+authentication to specific URL's. The ``mod_lookup_identity`` module
+must run *after* authentication module runs because it depends on
+knowing who the authenticated principal is so it can lookup the data
+on that principal.
+
+When reading ``mod_lookup_identity`` documentation one often sees
+references to the ``REMOTE_USER`` CGI environment variable with the
+implication ``REMOTE_USER`` is how one accesses the name of the
+authenticated principal. This is a bit misleading, ``REMOTE_USER`` is
+a CGI environment variable. CGI environment variables are only set by
+Apache when it believes the request is going to be processed by a CGI
+implementation. In this case ``REMOTE_USER`` is initialized from the
+``request->user`` value.
+
+How is the authenticated principal actually forwarded to our proxy?
+===================================================================
+
+If we are using the AJP proxy protocol the ``mod_proxy_ajp`` module
+when preparing the proxy request will read the value of
+``request->user`` and insert it into the ``SC_A_REMOTE_USER`` AJP
+attribute. On the receiving end ``SC_A_REMOTE_USER`` will be extracted
+from the AJP request and used to populate the value returned
+by``HttpServletRequest.getRemoteUser()``. The exchange of the
+authenticated principal when using AJP is transparent to both the
+sender and receiver, nothing special needs to be done. See
+`Transporting Identity Metadata from Apache to a Java EE Servlet`_
+for details on how metadata can be exchanged with the proxy.
+
+However, if AJP is not being used to proxy the request the
+authenticated principal must be passed through some other mechanism,
+an HTTP extension header is the obvious solution. The Apache
+``mod_headers`` module can be used to add HTTP request headers to the
+proxy request, for example:
+
+::
+
+  RequestHeader set MY_HEADER MY_VALUE
+
+Where does the value MY_VALUE come from? It can be hardcoded into the
+``RequestHeader`` statement or it can reference an existing
+environment variable like this:
+
+::
+
+  RequestHeader set MY_HEADER %{FOOBAR}e
+
+where the notation ``%{FOOBAR}e`` is the contents of the environment
+variable FOOBAR. Thus we might expect we could do this:
+
+::
+
+  RequestHeader set REMOTE_USER %{REMOTE_USER}e
+
+The conundrum is the presumption the ``REMOTE_USER`` environment
+variable has already been set at the time ``mod_headers`` executes the
+``RequestHeader`` statement. Unfortunately this often is not the
+case.
+
+The Apache environment variables ``REMOTE_USER`` and ``AUTH_TYPE`` are
+set by the Apache function ``ap_add_common_vars()`` defined in
+server/util_script.c.  ``ap_add_common_vars()`` and is called by the
+following modules:
+
+  * mod_authnz_fcgi
+  * mod_proxy_fcgi
+  * mod_proxy_scgi
+  * mod_isapi
+  * mod_ext_filter
+  * mod_include
+  * mod_cgi
+  * mod_cgid
+
+Apache variables
+================
+
+Apache modules provide access to variables which can be referenced by
+configuration directives. Unfortunately there isn't a lot of
+uniformity to what the variables are and how they're referenced; it
+mostly depends on how a given Apache module was implemented. As you
+might imagine a bit of inconsistent historical cruft has accumulated
+over the years, it can be confusing. The Apache Foundation is trying
+to clean some of this up bringing uniformity to modules by utilizing
+the common ``expr`` (expression) module `ap_expr`_. The idea being modules will
+forgo their home grown expression syntax with its numerous quirks and
+instead expose the common ``expr`` language. However this is a work in
+progress and at the time of this writing only a few modules have acquired
+``expr`` expression support.
+
+Among the existing Apache modules there currently are three different
+sets of variables.
+
+  1. Server variables.
+  2. Environment variables.
+  3. SSL variables.
+
+Server variables (item 1) are names given to internal values. The set
+of names for server variables and what they map to are defined by the
+module implementing the server variable lookup. For example
+``mod_rewrite`` has its own variable lookup implementation.
+
+Environment variables (item 2) are variables *exported* to a
+subprocess. Internally they are stored in
+``request->subprocess_env``. The most common use of environment
+variables exported to a subprocess are the CGI variables.
+
+SSL variables are connection specific values describing the SSL
+connection. The lookup is implemented by ``ssl_var_lookup()``, which
+given a variable name looks in a variety of internal data structures to
+find the matching value.
+
+The important thing to remember is **server variables != environment
+variables**. This can be confusing because they often share the same
+name. For example, there is the server variable ``REMOTE_USER`` and
+there is the environment variable ``REMOTE_USER``. The environment
+variable ``REMOTE_USER`` only exists if some module has called
+``ap_add_common_vars()``. To complicate matters, some modules allow you
+to access *server variables*, other modules allow you to access
+*environment variables* and some modules provide access to both
+*server variables* and *environment variables*.
+
+Coming back to our goal of setting an HTTP extension header to the
+value of ``REMOTE_USER``, we observe that ``mod_headers`` provides the
+needed ``RequestHeader`` operation to set a HTTP header in the
+request. Looking at the documentation for ``RequestHeader`` we see a
+value can be specified with one of the following lookups:
+
+%{VARNAME}e
+  The contents of the environment variable VARNAME.
+
+%{VARNAME}s
+  The contents of the SSL environment variable VARNAME, if mod_ssl is enabled.
+
+But wait! This only gives us access to *environment variables* and the
+``REMOTE_USER`` environment variable is only set if
+``ap_add_common_vars()`` is called by a module **after** an
+authentication module runs! ``ap_add_common_vars()`` is usually only
+invoked if the request is going to be passed to a CGI script. But
+we're not doing CGI; instead we're proxying the request. The
+likelihood the ``REMOTE_USER`` environment variable will be set is
+quite low. See `Setting the REMOTE_USER environment variable`_.
+
+``mod_headers`` is the only way to set a HTTP extension header and
+``mod_headers`` only gives you access to environment variables and the
+``REMOTE_USER`` environment variable is not set. Therefore if we're
+not using AJP and must depend on setting a HTTP extension header for
+``REMOTE_USER``, we have a **serious problem**.
+
+But there is a solution; you can either try the machinations described
+in `Setting the REMOTE_USER environment variable`_ or assure you're
+running at least Apache version 2.4.10. In Apache 2.4.10 the
+``mod_headers`` module added support for `ap_expr`_. `ap_expr`_
+provides access to *server variables* by using the ``%{VARIABLE}``
+notation. `ap_expr`_ also can lookup subprocess environment variables
+and operating system environment variables using its ``reqenv()`` and
+``osenv()`` functions respectively.
+
+Thus the simple solution for exporting the ``REMOTE_USER`` HTTP
+extension header if you're running Apache 2.4.10 or later is:
+
+::
+
+  RequestHeader set X-SSSD-REMOTE_USER expr=%{REMOTE_USER}
+
+The ``expr=%{REMOTE_USER}`` in the above statement says pass
+``%{REMOTE_USER}`` as an expression to `ap_expr`_, evaluate the
+expression and return the value. In this case the expression
+``%{REMOTE_USER}`` is very simple, just the value of the server
+variables ``REMOTE_USER``. Because ``RequestHeader`` runs after
+authentication ``request->user`` will have been set.
+
+Setting the REMOTE_USER environment variable
+============================================
+
+If you do a web search on how to export ``REMOTE_USER`` in a HTTP
+extension header for a proxy you will discover this is a common
+problem that has frustrated a lot of people [2]_. The usual advice seems to
+be to use ``mod_rewrite`` with a look-ahead. In fact this is even
+documented in the `mod_rewrite documentation for REMOTE_USER`_ which says:
+
+  %{LA-U:variable} can be used for look-aheads which perform an
+  internal (URL-based) sub-request to determine the final value of
+  variable. This can be used to access variable for rewriting which is
+  not available at the current stage, but will be set in a later
+  phase.
+
+  For instance, to rewrite according to the REMOTE_USER variable from
+  within the per-server context (httpd.conf file) you must use
+  %{LA-U:REMOTE_USER} - this variable is set by the authorization
+  phases, which come after the URL translation phase (during which
+  mod_rewrite operates).
+
+One suggested solution is this:
+
+::
+
+  RewriteCond %{LA-U:REMOTE_USER} (.+)
+  RewriteRule .* - [E=RU:%1]
+  RequestHeader set X_REMOTE_USER %{RU}e
+
+1. The RewriteCond with the %{LA-U:} construct performs an internal
+   redirect to obtain the value of ``REMOTE_USER`` *server variable*,
+   if that value is non-empty because the (.+) regular expression
+   matched the rewrite condition succeeds and the following
+   RewriteRule executes.
+
+2. The RewriteRule executes, the first parameter is a pattern, the
+   second parameter is the replacement which can be followed by
+   optional flags inside brackets. The .* pattern is a regular
+   expression that matches anything, the - replacement is a special
+   value which indicates no replacement is to be performed. In other
+   words the pattern and replacement are no-ops and the RewriteRule is
+   just being used for it's side effect defined in the flags. The
+   E=NAME:VALUE notation says set the NAME environment variable to
+   VALUE. In this case the environment variable is RU and the value is
+   %1. The documentation for RewriteRule tells us that %N are
+   back-references to the last matched RewriteCond pattern, in this
+   case it's the value of ``REMOTE_USER``.
+
+3. Finally ``RequestHeader`` sets the request header
+   ``X_REMOTE_USER`` to the value of the ``RU`` environment variable.
+
+Another suggested solution is this:
+
+::
+
+  RewriteRule .* - [E=REMOTE_USER:%{LA-U:REMOTE_USER}]
+
+The Problem with mod_rewrite lookahead
+--------------------------------------
+
+I **do not recommend** using mod_rewrite's lookahead to gain access to
+authentication data values. Although the above suggestions will work
+to get access to ``REMOTE_USER`` it is *extremely inefficient* because
+it causes Apache to reprocess the request with an internal
+redirect. The documentation suggests a lookahead reference will cause
+one internal redirect. However from examining Apache debug logs the
+``mod_rewite`` lookahead caused ``mod_lookup_identity`` to be invoked
+**11 times** while handling one request. If the ``mod_rewrite``
+lookahead is removed and another technique is used to get access to
+``REMOTE_USER`` then ``mod_lookup_identity`` is invoked exactly once
+as expected.
+
+But it's not just ``REMOTE_USER`` which we need access to, we also need
+to reference ``AUTH_TYPE`` which has the identical issues associated
+with ``REMOTE_USER``. If an equivalent ``mod_rewrite`` block is added
+to the configuration for ``AUTH_TYPE`` so that both ``REMOTE_USER``
+and ``auth_type`` are resolved using a lookahead Apache appears to go
+into an infinite loop and the request stalls.
+
+I tried to debug what was occurring when Apache was configured this way
+and why it seemed to be executing the same code over and over but I
+was not able to figure it out. My conclusion is **using mod_rewrite
+lookahead's is not a viable solution!** Other web posts also make
+reference to the inefficiency but they seem to be unaware of just how
+bad it is.
+
+.. [1]
+   Tomcat has a bug/feature, not all attributes are enumerated by
+   getAttributeNames() therefore getAttributeNames() cannot be used to
+   obtain the full set of attributes. However if you know the name of
+   the attribute a priori you can call getAttribute() and obtain the
+   value. Therefore we maintain a list of attribute names
+   (httpAttributes) which will be used to call getAttribute() with so we
+   don't miss essential attributes.
+
+   This is the Tomcat bug, note it is marked WONTFIX. Bug 25363 -
+   request.getAttributeNames() not working properly Status: RESOLVED
+   WONTFIX https://issues.apache.org/bugzilla/show_bug.cgi?id=25363
+
+   The solution adopted by Tomcat is to document the behavior in the
+   "The Apache Tomcat Connector - Reference Guide" under the JkEnvVar
+   property where is says:
+
+   You can retrieve the variables on Tomcat as request attributes via
+   request.getAttribute(attributeName). Note that the variables send via
+   JkEnvVar will not be listed in request.getAttributeNames().
+
+.. [2]
+   Some examples of posts concerning the export of ``REMOTE_USER``  include:
+   http://www.jaddog.org/2010/03/22/how-to-proxy-pass-remote_user/ and
+   http://serverfault.com/questions/23273/apache-proxy-passing-on-remote-user-to-backend-server/
+
+.. [3]
+   The ``mod_lookup_identity`` ``LookupUserGroups`` option accepts an
+   optional parameter to specify the separator used to separate group
+   names. By convention this is normally the colon (:) character. In
+   our examples we explicitly specify the colon separator because the
+   mapping rules split the value found in ``REMOTE_USER_GROUPS`` on
+   the colon character.
+
+.. [4]
+   The example of using the `The Mapping Rule Processor`_ to establish
+   the set of roles assigned to a user based on group membership is
+   for illustrative purposes in order to show features of the
+   federated IdP and mapping mechanism. Role assignment in AAA may be
+   done in other ways. For example an unscoped token without roles can
+   be used to acquire a scoped token with roles by presenting it to
+   the appropriate REST API endpoint. In actual deployments this may
+   be preferable because it places the responsibility of deciding who
+   has what role/permission on what part of the controller/network
+   resources more in the hands of the SDN controller administrator
+   than the IdP administrator.
+
+.. _FreeIPA: http://www.freeipa.org/
+
+.. _SSSD: https://fedorahosted.org/sssd/
+
+.. _mod_identity_lookup: http://www.adelton.com/apache/mod_lookup_identity/
+
+.. _AJP: http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
+
+.. _Tomcat Security How-To: http://tomcat.apache.org/tomcat-7.0-doc/security-howto.html
+
+.. _The Apache Tomcat Connector - Generic HowTo: http://tomcat.apache.org/connectors-doc/generic_howto/printer/proxy.html
+
+.. _CGI RFC: http://www.ietf.org/rfc/rfc3875
+
+.. _ap_expr: http://httpd.apache.org/docs/current/expr.html
+
+.. _mod_rewrite documentation for REMOTE_USER: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritecond
+
+.. _bug 53098: https://issues.apache.org/bugzilla/show_bug.cgi?id=53098
+
+.. _Jetty AJP Configuration Guide: http://wiki.eclipse.org/Jetty/Howto/Configure_AJP13
+
+.. _Bug 387928: https://bugs.eclipse.org/bugs/show_bug.cgi?id=387928
+
+.. _Tomcat Remote Address Valve: http://tomcat.apache.org/tomcat-7.0-doc/config/valve.html#Remote_Address_Filter
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Authentication.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Authentication.java
new file mode 100644
index 00000000..25ba898b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Authentication.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * An immutable authentication context.
+ *
+ * @author liemmn
+ */
+public interface Authentication extends Claim {
+
+    /**
+     * Get the authentication expiration date/time in number of milliseconds
+     * since start of epoch.
+     *
+     * @return expiration milliseconds since start of UTC epoch
+     */
+    long expiration();
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationException.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationException.java
new file mode 100644
index 00000000..d4621527
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * A catch-all authentication exception.
+ *
+ * @author liemmn
+ *
+ */
+public class AuthenticationException extends RuntimeException {
+    private static final long serialVersionUID = -187422301135305719L;
+
+    public AuthenticationException(String msg) {
+        super(msg);
+    }
+
+    public AuthenticationException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    public AuthenticationException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationService.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationService.java
new file mode 100644
index 00000000..24ae9238
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/AuthenticationService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * Authentication service to provide authentication context.
+ */
+public interface AuthenticationService {
+    /**
+     * Retrieve the current security context, or null if none exists.
+     *
+     * @return security context
+     */
+    Authentication get();
+
+    /**
+     * Set the current security context. Only {@link TokenAuth} should set
+     * security context based on the authentication result.
+     *
+     * @param auth
+     *            security context
+     */
+    void set(Authentication auth);
+
+    /**
+     * Clear the current security context.
+     */
+    void clear();
+
+    /**
+     * Checks to see if authentication is enabled.
+     *
+     * @return true if it is, false otherwise
+     */
+    boolean isAuthEnabled();
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Claim.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Claim.java
new file mode 100644
index 00000000..7d9a229a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Claim.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+import java.util.Set;
+
+/**
+ * A claim typically provided by an identity provider after validating the
+ * needed identity and credentials.
+ *
+ * @author liemmn
+ *
+ */
+public interface Claim {
+    /**
+     * Get the id of the authorized client. If the id is an empty string, it
+     * means that the client is anonymous.
+     *
+     * @return id of the authorized client, or empty string if anonymous
+     */
+    String clientId();
+
+    /**
+     * Get the user id. User IDs are system-created.
+     *
+     * @return unique user id
+     */
+    String userId();
+
+    /**
+     * Get the user name. User names are externally created.
+     *
+     * @return unique user name
+     */
+    String user();
+
+    /**
+     * Get the fully-qualified domain name. Domain names are externally created.
+     *
+     * @return unique domain name, or empty string for a claim tied to no domain
+     */
+    String domain();
+
+    /**
+     * Get a set of user roles. Roles are externally created.
+     *
+     * @return set of user roles
+     */
+    Set<String> roles();
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClaimAuth.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClaimAuth.java
new file mode 100644
index 00000000..447ffb35
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClaimAuth.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+import java.util.Map;
+
+/**
+ * An interface for in-bound claim transformation.
+ *
+ * @author liemmn
+ *
+ */
+public interface ClaimAuth {
+
+    /**
+     * Transform a map of opaque in-bound claims into a {@link Claim} object. An
+     * example of an opaque claim map entry is
+     * <code>"USER_NAME" -&gt; "joe".</code>
+     * <p>
+     * If there is no applicable claim information for the current
+     * implementation, this method should return a <code>null</code>.
+     * <p>
+     * In-bound claims are extracted from HttpServletRequest attributes,
+     * headers, and CGI variables as documented per Servlet specs.
+     *
+     * @param claim
+     *            opaque claim
+     * @return normalized claim, or null if not applicable
+     */
+    Claim transform(Map<String, Object> claim);
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClientService.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClientService.java
new file mode 100644
index 00000000..c11eec1c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/ClientService.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * A service for managing authorized clients to the controller.
+ *
+ * @author liemmn
+ *
+ */
+public interface ClientService {
+
+    void validate(String clientId, String clientSecret) throws AuthenticationException;
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/CredentialAuth.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/CredentialAuth.java
new file mode 100644
index 00000000..341e49ae
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/CredentialAuth.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * An interface for direct authentication with some given credentials.
+ *
+ * @author liemmn
+ */
+public interface CredentialAuth<T extends Credentials> {
+
+    /**
+     * Authenticate a claim with the given credentials and domain scope.
+     *
+     * @param cred
+     *            credentials
+     * @throws AuthenticationException
+     *             if failed authentication
+     * @return authenticated claim
+     */
+    Claim authenticate(T cred) throws AuthenticationException;
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Credentials.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Credentials.java
new file mode 100644
index 00000000..7d2f19e5
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/Credentials.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * An interface to represent user credentials.
+ */
+public interface Credentials {
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreException.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreException.java
new file mode 100644
index 00000000..026c11ce
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.api;
+
+/*
+ * @author - Sharon Aicler (saichler@cisco.com)
+ */
+public class IDMStoreException extends Exception {
+
+    private static final long serialVersionUID = -7534127680943957878L;
+
+    public IDMStoreException(Exception e) {
+        super(e);
+    }
+
+    public IDMStoreException(String msg) {
+        super(msg);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreUtil.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreUtil.java
new file mode 100644
index 00000000..07dd522f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IDMStoreUtil.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.api;
+
+import javax.naming.OperationNotSupportedException;
+
+/*
+ *  This class is a utility to construct the different elements keys for the different data stores.
+ *  For not making mistakes around the code constructing an element key, this class standardize the
+ *  way the key is constructed to be used by the different data stores.
+ *
+ *  @author - Sharon Aicler (saichler@cisco.com)
+ */
+
+public class IDMStoreUtil {
+    private IDMStoreUtil() throws OperationNotSupportedException {
+        throw new OperationNotSupportedException();
+    }
+
+    public static String createDomainid(String domainName) {
+        return domainName;
+    }
+
+    public static String createUserid(String username, String domainid) {
+        return username + "@" + domainid;
+    }
+
+    public static String createRoleid(String rolename, String domainid) {
+        return rolename + "@" + domainid;
+    }
+
+    public static String createGrantid(String userid, String domainid, String roleid) {
+        return userid + "@" + roleid + "@" + domainid;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IIDMStore.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IIDMStore.java
new file mode 100644
index 00000000..7b031e05
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IIDMStore.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.api;
+
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+
+/**
+ * @author - Sharon Aicler (saichler@cisco.com)
+ **/
+public interface IIDMStore {
+    public String DEFAULT_DOMAIN = "sdn";
+
+    // Domain methods
+    public Domain writeDomain(Domain domain) throws IDMStoreException;
+
+    public Domain readDomain(String domainid) throws IDMStoreException;
+
+    public Domain deleteDomain(String domainid) throws IDMStoreException;
+
+    public Domain updateDomain(Domain domain) throws IDMStoreException;
+
+    public Domains getDomains() throws IDMStoreException;
+
+    // Role methods
+    public Role writeRole(Role role) throws IDMStoreException;
+
+    public Role readRole(String roleid) throws IDMStoreException;
+
+    public Role deleteRole(String roleid) throws IDMStoreException;
+
+    public Role updateRole(Role role) throws IDMStoreException;
+
+    public Roles getRoles() throws IDMStoreException;
+
+    // User methods
+    public User writeUser(User user) throws IDMStoreException;
+
+    public User readUser(String userid) throws IDMStoreException;
+
+    public User deleteUser(String userid) throws IDMStoreException;
+
+    public User updateUser(User user) throws IDMStoreException;
+
+    public Users getUsers() throws IDMStoreException;
+
+    public Users getUsers(String username, String domain) throws IDMStoreException;
+
+    // Grant methods
+    public Grant writeGrant(Grant grant) throws IDMStoreException;
+
+    public Grant readGrant(String grantid) throws IDMStoreException;
+
+    public Grant deleteGrant(String grantid) throws IDMStoreException;
+
+    public Grants getGrants(String domainid, String userid) throws IDMStoreException;
+
+    public Grants getGrants(String userid) throws IDMStoreException;
+
+    public Grant readGrant(String domainid, String userid, String roleid) throws IDMStoreException;
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IdMService.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IdMService.java
new file mode 100644
index 00000000..1d698da5
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/IdMService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+import java.util.List;
+
+/**
+ * A service to provide identity information.
+ *
+ * @author liemmn
+ *
+ */
+public interface IdMService {
+    /**
+     * List all domains that the given user has at least one role on.
+     *
+     * @param userId
+     *            id of user
+     * @return list of all domains that the given user has access to
+     */
+    List<String> listDomains(String userId);
+
+    /**
+     * List all roles that the given user has on the given domain.
+     *
+     * @param userId
+     *            id of user
+     * @param domain
+     *            domain
+     * @return list of roles
+     */
+    List<String> listRoles(String userId, String domain);
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/PasswordCredentials.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/PasswordCredentials.java
new file mode 100644
index 00000000..e5fa346d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/PasswordCredentials.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * Good 'ole username/password.
+ */
+public interface PasswordCredentials extends Credentials {
+    String username();
+
+    String password();
+
+    String domain();
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/SHA256Calculator.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/SHA256Calculator.java
new file mode 100644
index 00000000..903fe3de
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/SHA256Calculator.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.api;
+
+import java.security.MessageDigest;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import javax.xml.bind.DatatypeConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sharon Aicler (saichler@cisco.com)
+ */
+public class SHA256Calculator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SHA256Calculator.class);
+
+    private static MessageDigest md = null;
+    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    private static WriteLock writeLock = lock.writeLock();
+
+    public static String generateSALT() {
+        StringBuffer salt = new StringBuffer();
+        for (int i = 0; i < 12; i++) {
+            int random = (int) (Math.random() * 24 + 1);
+            salt.append((char) (65 + random));
+        }
+        return salt.toString();
+    }
+
+    public static String getSHA256(byte data[], String salt) {
+        byte SALT[] = salt.getBytes();
+        byte temp[] = new byte[data.length + SALT.length];
+        System.arraycopy(data, 0, temp, 0, data.length);
+        System.arraycopy(SALT, 0, temp, data.length, SALT.length);
+
+        if (md == null) {
+            try {
+                writeLock.lock();
+                if (md == null) {
+                    try {
+                        md = MessageDigest.getInstance("SHA-256");
+                    } catch (Exception err) {
+                        LOG.error("Error calculating SHA-256 for SALT", err);
+                    }
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+
+        byte by[] = null;
+
+        try {
+            writeLock.lock();
+            md.update(temp);
+            by = md.digest();
+        } finally {
+            writeLock.unlock();
+        }
+        //Make sure the outcome hash does not contain special characters
+        return DatatypeConverter.printBase64Binary(by);
+    }
+
+    public static String getSHA256(String password, String salt) {
+        return getSHA256(password.getBytes(), salt);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenAuth.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenAuth.java
new file mode 100644
index 00000000..bbf6fa2b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenAuth.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An interface for in-bound token authentication.
+ *
+ * @author liemmn
+ */
+public interface TokenAuth {
+
+    /**
+     * Validate the given token contained in the in-bound headers.
+     * <p>
+     * If there is no token signature in the given headers for this
+     * implementation, this method should return a null. If there is an
+     * applicable token signature, but the token validation fails, this method
+     * should throw an {@link AuthenticationException}.
+     *
+     * @param headers
+     *            headers containing token to validate
+     * @return authenticated context, or null if not applicable
+     * @throws AuthenticationException
+     *             if authentication fails
+     */
+    Authentication validate(Map<String, List<String>> headers) throws AuthenticationException;
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenStore.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenStore.java
new file mode 100644
index 00000000..4cd7aa78
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/TokenStore.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api;
+
+/**
+ * A datastore for auth tokens.
+ *
+ * @author liemmn
+ *
+ */
+public interface TokenStore {
+    void put(String token, Authentication auth);
+
+    Authentication get(String token);
+
+    boolean delete(String token);
+
+    long tokenExpiration();
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Claim.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Claim.java
new file mode 100644
index 00000000..180bddfb
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Claim.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Claim")
+public class Claim {
+    private String domainid;
+    private String userid;
+    private String username;
+    private List<Role> roles;
+
+    public String getDomainid() {
+        return domainid;
+    }
+
+    public void setDomainid(String id) {
+        this.domainid = id;
+    }
+
+    public String getUserid() {
+        return userid;
+    }
+
+    public void setUserid(String id) {
+        this.userid = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String name) {
+        this.username = name;
+    }
+
+    public List<Role> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<Role> roles) {
+        this.roles = roles;
+    }
+
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domain.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domain.java
new file mode 100644
index 00000000..a42e0b6d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domain.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "domain")
+public class Domain {
+    private String domainid;
+    private String name;
+    private String description;
+    private Boolean enabled;
+
+    public String getDomainid() {
+        return domainid;
+    }
+
+    public void setDomainid(String id) {
+        this.domainid = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        Domain other = (Domain) obj;
+        if (other == null)
+            return false;
+        if (compareValues(getName(), other.getName())
+                && compareValues(getDomainid(), other.getDomainid())
+                && compareValues(getDescription(), other.getDescription()))
+            return true;
+        return false;
+    }
+
+    private boolean compareValues(Object a, Object b) {
+        if (a == null && b != null)
+            return false;
+        if (a != null && b == null)
+            return false;
+        if (a == null && b == null)
+            return true;
+        if (a.equals(b))
+            return true;
+        return false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domains.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domains.java
new file mode 100644
index 00000000..a8f2064b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Domains.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "domains")
+public class Domains {
+    private List<Domain> domains = new ArrayList<Domain>();
+
+    public void setDomains(List<Domain> domains) {
+        this.domains = domains;
+    }
+
+    public List<Domain> getDomains() {
+        return domains;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grant.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grant.java
new file mode 100644
index 00000000..20c2d128
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grant.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "grant")
+public class Grant {
+    private String grantid;
+    private String domainid;
+    private String userid;
+    private String roleid;
+
+    public String getGrantid() {
+        return this.grantid;
+    }
+
+    public void setGrantid(String id) {
+        this.grantid = id;
+    }
+
+    public String getDomainid() {
+        return domainid;
+    }
+
+    public void setDomainid(String id) {
+        this.domainid = id;
+    }
+
+    public String getUserid() {
+        return userid;
+    }
+
+    public void setUserid(String id) {
+        this.userid = id;
+    }
+
+    public String getRoleid() {
+        return roleid;
+    }
+
+    public void setRoleid(String id) {
+        this.roleid = id;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.getUserid().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        Grant other = (Grant) obj;
+        if (other == null)
+            return false;
+        if (compareValues(getDomainid(), other.getDomainid())
+                && compareValues(getRoleid(), other.getRoleid())
+                && compareValues(getUserid(), other.getUserid()))
+            return true;
+        return false;
+    }
+
+    private boolean compareValues(Object a, Object b) {
+        if (a == null && b != null)
+            return false;
+        if (a != null && b == null)
+            return false;
+        if (a == null && b == null)
+            return true;
+        if (a.equals(b))
+            return true;
+        return false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grants.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grants.java
new file mode 100644
index 00000000..ce0d9b85
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Grants.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "grants")
+public class Grants {
+    private List<Grant> grants = new ArrayList<Grant>();
+
+    public void setGrants(List<Grant> grants) {
+        this.grants = grants;
+    }
+
+    public List<Grant> getGrants() {
+        return grants;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/IDMError.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/IDMError.java
new file mode 100644
index 00000000..f44c43d9
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/IDMError.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.ws.rs.core.Response;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement(name = "idmerror")
+public class IDMError {
+    private static final Logger LOG = LoggerFactory.getLogger(IDMError.class);
+
+    private String message;
+    private String details;
+    private int code = 500;
+
+    public IDMError() {
+    };
+
+    public IDMError(int statusCode, String msg, String msgDetails) {
+        code = statusCode;
+        message = msg;
+        details = msgDetails;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String msg) {
+        this.message = msg;
+    }
+
+    public String getDetails() {
+        return details;
+    }
+
+    public void setDetails(String details) {
+        this.details = details;
+    }
+
+    public Response response() {
+        LOG.error("error: {} details: {} status: {}", this.message, this.details, code);
+        return Response.status(this.code).entity(this).build();
+    }
+
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Role.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Role.java
new file mode 100644
index 00000000..de707496
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Role.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "role")
+public class Role {
+    private String roleid;
+    private String name;
+    private String description;
+    private String domainid;
+
+    public String getRoleid() {
+        return roleid;
+    }
+
+    public void setRoleid(String id) {
+        this.roleid = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        Role other = (Role) obj;
+        if (other == null)
+            return false;
+        if (compareValues(getName(), other.getName())
+                && compareValues(getRoleid(), other.getRoleid())
+                && compareValues(getDescription(), other.getDescription()))
+            return true;
+        return false;
+    }
+
+    public void setDomainid(String domainid) {
+        this.domainid = domainid;
+    }
+
+    public String getDomainid() {
+        return this.domainid;
+    }
+
+    private boolean compareValues(Object a, Object b) {
+        if (a == null && b != null)
+            return false;
+        if (a != null && b == null)
+            return false;
+        if (a == null && b == null)
+            return true;
+        if (a.equals(b))
+            return true;
+        return false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Roles.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Roles.java
new file mode 100644
index 00000000..33521028
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Roles.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "roles")
+public class Roles {
+    private List<Role> roles = new ArrayList<Role>();
+
+    public void setRoles(List<Role> roles) {
+        this.roles = roles;
+    }
+
+    public List<Role> getRoles() {
+        return roles;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/User.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/User.java
new file mode 100644
index 00000000..c6c1f9a6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/User.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "user")
+public class User {
+    private String userid;
+    private String name;
+    private String description;
+    private Boolean enabled;
+    private String email;
+    private String password;
+    private String salt;
+    private String domainid;
+
+    public String getUserid() {
+        return userid;
+    }
+
+    public void setUserid(String id) {
+        this.userid = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setSalt(String s) {
+        this.salt = s;
+    }
+
+    public String getSalt() {
+        return this.salt;
+    }
+
+    public String getDomainid() {
+        return domainid;
+    }
+
+    public void setDomainid(String domainid) {
+        this.domainid = domainid;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        User other = (User) obj;
+        if (other == null)
+            return false;
+        if (compareValues(getName(), other.getName())
+                && compareValues(getEmail(), other.getEmail())
+                && compareValues(isEnabled(), other.isEnabled())
+                && compareValues(getPassword(), other.getPassword())
+                && compareValues(getSalt(), other.getSalt())
+                && compareValues(getUserid(), other.getUserid())
+                && compareValues(getDescription(), other.getDescription()))
+            return true;
+        return false;
+    }
+
+    private boolean compareValues(Object a, Object b) {
+        if (a == null && b != null)
+            return false;
+        if (a != null && b == null)
+            return false;
+        if (a == null && b == null)
+            return true;
+        if (a.equals(b))
+            return true;
+        return false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/UserPwd.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/UserPwd.java
new file mode 100644
index 00000000..4750616d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/UserPwd.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "userpwd")
+public class UserPwd {
+    private String username;
+    private String userpwd;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String name) {
+        this.username = name;
+    }
+
+    public String getUserpwd() {
+        return userpwd;
+    }
+
+    public void setUserpwd(String pwd) {
+        this.userpwd = pwd;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Users.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Users.java
new file mode 100644
index 00000000..a0a001bd
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Users.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "users")
+public class Users {
+    private List<User> users = new ArrayList<User>();
+
+    public void setUsers(List<User> users) {
+        this.users = users;
+    }
+
+    public List<User> getUsers() {
+        return users;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Version.java b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Version.java
new file mode 100644
index 00000000..a88c1f80
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-api/src/main/java/org/opendaylight/aaa/api/model/Version.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.api.model;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "version")
+public class Version {
+    private String id;
+    private String updated;
+    private String status;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUpdated() {
+        return updated;
+    }
+
+    public void setUpdated(String name) {
+        this.updated = name;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-basic/pom.xml b/odl-aaa-moon/aaa/aaa-authn-basic/pom.xml
new file mode 100644
index 00000000..47562896
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-basic/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-basic</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.aaa.basic.Activator</Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/Activator.java b/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/Activator.java
new file mode 100644
index 00000000..bd57c9d3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/Activator.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.basic;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.osgi.framework.BundleContext;
+
+public class Activator extends DependencyActivatorBase {
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent()
+                .setInterface(new String[] { TokenAuth.class.getName() }, null)
+                .setImplementation(HttpBasicAuth.class)
+                .add(createServiceDependency().setService(CredentialAuth.class).setRequired(true)));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/HttpBasicAuth.java b/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/HttpBasicAuth.java
new file mode 100644
index 00000000..eff47e63
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-basic/src/main/java/org/opendaylight/aaa/basic/HttpBasicAuth.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.basic;
+
+import com.sun.jersey.core.util.Base64;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.PasswordCredentialBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An HTTP Basic authenticator. Note that this is provided as a Hydrogen
+ * backward compatible authenticator, but usage of this authenticator or HTTP
+ * Basic Authentication is highly discouraged due to its vulnerability.
+ *
+ * To obtain a token using the HttpBasicAuth Strategy, add a header to your HTTP
+ * request in the form:
+ * <code>Authorization: Basic BASE_64_ENCODED_CREDENTIALS</code>
+ *
+ * Where <code>BASE_64_ENCODED_CREDENTIALS</code> is the base 64 encoded value
+ * of the user's credentials in the following form: <code>user:password</code>
+ *
+ * For example, assuming the user is "admin" and the password is "admin":
+ * <code>Authorization: Basic YWRtaW46YWRtaW4=</code>
+ *
+ * @author liemmn
+ *
+ */
+public class HttpBasicAuth implements TokenAuth {
+
+    public static final String AUTH_HEADER = "Authorization";
+
+    public static final String AUTH_SEP = ":";
+
+    public static final String BASIC_PREFIX = "Basic ";
+
+    // TODO relocate this constant
+    public static final String DEFAULT_DOMAIN = "sdn";
+
+    /**
+     * username and password
+     */
+    private static final int NUM_HEADER_CREDS = 2;
+
+    /**
+     * username, password and domain
+     */
+    private static final int NUM_TOKEN_CREDS = 3;
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpBasicAuth.class);
+
+    volatile CredentialAuth<PasswordCredentials> credentialAuth;
+
+    private static boolean checkAuthHeaderFormat(final String authHeader) {
+        return (authHeader != null && authHeader.startsWith(BASIC_PREFIX));
+    }
+
+    private static String extractAuthHeader(final Map<String, List<String>> headers) {
+        return headers.get(AUTH_HEADER).get(0);
+    }
+
+    private static String[] extractCredentialArray(final String authHeader) {
+        return new String(Base64.base64Decode(authHeader.substring(BASIC_PREFIX.length())))
+                .split(AUTH_SEP);
+    }
+
+    private static boolean verifyCredentialArray(final String[] creds) {
+        return (creds != null && creds.length == NUM_HEADER_CREDS);
+    }
+
+    private static String[] addDomainToCredentialArray(final String[] creds) {
+        String newCredentialArray[] = new String[NUM_TOKEN_CREDS];
+        System.arraycopy(creds, 0, newCredentialArray, 0, creds.length);
+        newCredentialArray[2] = DEFAULT_DOMAIN;
+        return newCredentialArray;
+    }
+
+    private static Authentication generateAuthentication(
+            CredentialAuth<PasswordCredentials> credentialAuth, final String[] creds)
+            throws ArrayIndexOutOfBoundsException {
+        final PasswordCredentials pc = new PasswordCredentialBuilder().setUserName(creds[0])
+                .setPassword(creds[1]).setDomain(creds[2]).build();
+        final Claim claim = credentialAuth.authenticate(pc);
+        return new AuthenticationBuilder(claim).build();
+    }
+
+    @Override
+    public Authentication validate(final Map<String, List<String>> headers)
+            throws AuthenticationException {
+        if (headers.containsKey(AUTH_HEADER)) {
+            final String authHeader = extractAuthHeader(headers);
+            if (checkAuthHeaderFormat(authHeader)) {
+                // HTTP Basic Auth
+                String[] creds = extractCredentialArray(authHeader);
+                // If no domain was supplied then use the default one, which is
+                // "sdn".
+                if (verifyCredentialArray(creds)) {
+                    creds = addDomainToCredentialArray(creds);
+                }
+                // Assumes correct formatting in form Base64("user:password").
+                // Throws an exception if an unknown format is used.
+                try {
+                    return generateAuthentication(this.credentialAuth, creds);
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    final String message = "Login Attempt in Bad Format."
+                            + " Please provide user:password in Base64 format.";
+                    LOG.info(message);
+                    throw new AuthenticationException(message);
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-basic/src/test/java/org/opendaylight/aaa/basic/HttpBasicAuthTest.java b/odl-aaa-moon/aaa/aaa-authn-basic/src/test/java/org/opendaylight/aaa/basic/HttpBasicAuthTest.java
new file mode 100644
index 00000000..4ee439df
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-basic/src/test/java/org/opendaylight/aaa/basic/HttpBasicAuthTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.basic;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.sun.jersey.core.util.Base64;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.PasswordCredentialBuilder;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.CredentialAuth;
+
+public class HttpBasicAuthTest {
+    private static final String USERNAME = "admin";
+    private static final String PASSWORD = "admin";
+    private static final String DOMAIN = "sdn";
+    private HttpBasicAuth auth;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setup() {
+        auth = new HttpBasicAuth();
+        auth.credentialAuth = mock(CredentialAuth.class);
+        when(
+                auth.credentialAuth.authenticate(new PasswordCredentialBuilder()
+                        .setUserName(USERNAME).setPassword(PASSWORD).setDomain(DOMAIN).build()))
+                .thenReturn(
+                        new ClaimBuilder().setUser("admin").addRole("admin").setUserId("123")
+                                .build());
+        when(
+                auth.credentialAuth.authenticate(new PasswordCredentialBuilder()
+                        .setUserName(USERNAME).setPassword("bozo").setDomain(DOMAIN).build()))
+                .thenThrow(new AuthenticationException("barf"));
+    }
+
+    @Test
+    public void testValidateOk() throws UnsupportedEncodingException {
+        String data = USERNAME + ":" + PASSWORD + ":" + DOMAIN;
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put("Authorization",
+                Arrays.asList("Basic " + new String(Base64.encode(data.getBytes("utf-8")))));
+        Claim claim = auth.validate(headers);
+        assertNotNull(claim);
+        assertEquals(USERNAME, claim.user());
+        assertEquals("admin", claim.roles().iterator().next());
+    }
+
+    @Test(expected = AuthenticationException.class)
+    public void testValidateBadPassword() throws UnsupportedEncodingException {
+        String data = USERNAME + ":bozo:" + DOMAIN;
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put("Authorization",
+                Arrays.asList("Basic " + new String(Base64.encode(data.getBytes("utf-8")))));
+        auth.validate(headers);
+    }
+
+    @Test(expected = AuthenticationException.class)
+    public void testValidateBadPasswordNoDOMAIN() throws UnsupportedEncodingException {
+        String data = USERNAME + ":bozo";
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put("Authorization",
+                Arrays.asList("Basic " + new String(Base64.encode(data.getBytes("utf-8")))));
+        auth.validate(headers);
+    }
+
+    @Test(expected = AuthenticationException.class)
+    public void testBadHeaderFormatNoPassword() throws UnsupportedEncodingException {
+        // just provide the username
+        String data = USERNAME;
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put("Authorization",
+                Arrays.asList("Basic " + new String(Base64.encode(data.getBytes("utf-8")))));
+        auth.validate(headers);
+    }
+
+    @Test(expected = AuthenticationException.class)
+    public void testBadHeaderFormat() throws UnsupportedEncodingException {
+        // provide username:
+        String data = USERNAME + "$" + PASSWORD;
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put("Authorization",
+                Arrays.asList("Basic " + new String(Base64.encode(data.getBytes("utf-8")))));
+        auth.validate(headers);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/pom.xml b/odl-aaa-moon/aaa/aaa-authn-federation/pom.xml
new file mode 100644
index 00000000..e217f48c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/pom.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-federation</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.common</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet-tester</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>*,com.sun.jersey.spi.container.servlet</Import-Package>
+                        <Web-ContextPath>/oauth2/federation</Web-ContextPath>
+                        <Web-Connectors>federationConn</Web-Connectors>
+                        <Bundle-Activator>org.opendaylight.aaa.federation.Activator</Bundle-Activator>
+                        <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/federation.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/Activator.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/Activator.java
new file mode 100644
index 00000000..4ae027c8
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/Activator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import java.util.Dictionary;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * An activator for the secure token server to inject in a
+ * <code>CredentialAuth</code> implementation.
+ *
+ * @author liemmn
+ *
+ */
+public class Activator extends DependencyActivatorBase {
+    private static final String FEDERATION_PID = "org.opendaylight.aaa.federation";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent()
+                .setImplementation(ServiceLocator.getInstance())
+                .add(createServiceDependency().setService(TokenStore.class).setRequired(true))
+                .add(createServiceDependency().setService(IdMService.class).setRequired(true))
+                .add(createServiceDependency().setService(ClaimAuth.class).setRequired(false)
+                        .setCallbacks("claimAuthAdded", "claimAuthRemoved")));
+        context.registerService(ManagedService.class, FederationConfiguration.instance(),
+                addPid(FederationConfiguration.defaults));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+    private Dictionary<String, ?> addPid(Dictionary<String, String> dict) {
+        dict.put(Constants.SERVICE_PID, FEDERATION_PID);
+        return dict;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ClaimAuthFilter.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ClaimAuthFilter.java
new file mode 100644
index 00000000..10a1277d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ClaimAuthFilter.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+import static org.opendaylight.aaa.federation.FederationEndpoint.AUTH_CLAIM;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A generic {@link Filter} for {@link ClaimAuth} implementations.
+ * <p>
+ * This filter trusts any authentication metadata bound to a request. A request
+ * with fake authentication claims could be forged by an attacker and submitted
+ * to one of the Connector ports the engine is listening on and we would blindly
+ * accept the forged information in this filter. Therefore it is vital we only
+ * accept authentication claims from a trusted proxy. It is incumbent upon the
+ * site administrator to dedicate specific connector ports on which previously
+ * authenticated requests from a trusted proxy will be sent to and to assure
+ * only a trusted proxy can connect to that port. The site administrator must
+ * enumerate those ports in the configuration. We reject any request which did
+ * not originate on one of the configured secure proxy ports.
+ *
+ * @author liemmn
+ *
+ */
+public class ClaimAuthFilter implements Filter {
+    private static final Logger LOG = LoggerFactory.getLogger(ClaimAuthFilter.class);
+
+    private static final String CGI_AUTH_TYPE = "AUTH_TYPE";
+    private static final String CGI_PATH_INFO = "PATH_INFO";
+    private static final String CGI_PATH_TRANSLATED = "PATH_TRANSLATED";
+    private static final String CGI_QUERY_STRING = "QUERY_STRING";
+    private static final String CGI_REMOTE_ADDR = "REMOTE_ADDR";
+    private static final String CGI_REMOTE_HOST = "REMOTE_HOST";
+    private static final String CGI_REMOTE_PORT = "REMOTE_PORT";
+    private static final String CGI_REMOTE_USER = "REMOTE_USER";
+    private static final String CGI_REMOTE_USER_GROUPS = "REMOTE_USER_GROUPS";
+    private static final String CGI_REQUEST_METHOD = "REQUEST_METHOD";
+    private static final String CGI_SCRIPT_NAME = "SCRIPT_NAME";
+    private static final String CGI_SERVER_PROTOCOL = "SERVER_PROTOCOL";
+
+    static final String UNAUTHORIZED_PORT_ERR = "Unauthorized proxy port";
+
+    @Override
+    public void init(FilterConfig fc) throws ServletException {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
+            throws IOException, ServletException {
+        Set<Integer> secureProxyPorts;
+        int localPort;
+
+        // Check to see if we are communicated over an authorized port or not
+        secureProxyPorts = FederationConfiguration.instance().secureProxyPorts();
+        localPort = req.getLocalPort();
+        if (!secureProxyPorts.contains(localPort)) {
+            ((HttpServletResponse) resp).sendError(SC_UNAUTHORIZED, UNAUTHORIZED_PORT_ERR);
+            return;
+        }
+
+        // Let's do some transformation!
+        List<ClaimAuth> claimAuthCollection = ServiceLocator.getInstance().getClaimAuthCollection();
+        for (ClaimAuth ca : claimAuthCollection) {
+            Claim claim = ca.transform(claims((HttpServletRequest) req));
+            if (claim != null) {
+                req.setAttribute(AUTH_CLAIM, claim);
+                // No need to do further transformation since it has been done
+                break;
+            }
+        }
+        chain.doFilter(req, resp);
+    }
+
+    // Extract attributes and headers out of the request
+    private Map<String, Object> claims(HttpServletRequest req) {
+        String name;
+        Object objectValue;
+        String stringValue;
+        Map<String, Object> claims = new HashMap<>();
+
+        /*
+         * Tomcat has a bug/feature, not all attributes are enumerated by
+         * getAttributeNames() therefore getAttributeNames() cannot be used to
+         * obtain the full set of attributes. However if you know the name of
+         * the attribute a priori you can call getAttribute() and obtain the
+         * value. Therefore we maintain a list of attribute names
+         * (httpAttributes) which will be used to call getAttribute() with so we
+         * don't miss essential attributes.
+         *
+         * This is the Tomcat bug, note it is marked WONTFIX. Bug 25363 -
+         * request.getAttributeNames() not working properly Status: RESOLVED
+         * WONTFIX https://issues.apache.org/bugzilla/show_bug.cgi?id=25363
+         *
+         * The solution adopted by Tomcat is to document the behavior in the
+         * "The Apache Tomcat Connector - Reference Guide" under the JkEnvVar
+         * property where is says:
+         *
+         * You can retrieve the variables on Tomcat as request attributes via
+         * request.getAttribute(attributeName). Note that the variables send via
+         * JkEnvVar will not be listed in request.getAttributeNames().
+         */
+
+        // Capture attributes which can be enumerated ...
+        @SuppressWarnings("unchecked")
+        Enumeration<String> attrs = req.getAttributeNames();
+        while (attrs.hasMoreElements()) {
+            name = attrs.nextElement();
+            objectValue = req.getAttribute(name);
+            if (objectValue instanceof String) {
+                // metadata might be i18n, assume UTF8 and decode
+                stringValue = decodeUTF8((String) objectValue);
+                objectValue = stringValue;
+            }
+            claims.put(name, objectValue);
+        }
+
+        // Capture specific attributes which cannot be enumerated ...
+        for (String attr : FederationConfiguration.instance().httpAttributes()) {
+            name = attr;
+            objectValue = req.getAttribute(name);
+            if (objectValue instanceof String) {
+                // metadata might be i18n, assume UTF8 and decode
+                stringValue = decodeUTF8((String) objectValue);
+                objectValue = stringValue;
+            }
+            claims.put(name, objectValue);
+        }
+
+        /*
+         * In general we should not utilize HTTP headers as validated security
+         * assertions because they are too easy to forge. Therefore in general
+         * we don't include HTTP headers, however in certain circumstances
+         * specific headers may be acceptable, thus we permit an admin to
+         * configure the capture of specific headers.
+         */
+        for (String header : FederationConfiguration.instance().httpHeaders()) {
+            claims.put(header, req.getHeader(header));
+        }
+
+        // Capture standard CGI variables...
+        claims.put(CGI_AUTH_TYPE, req.getAuthType());
+        claims.put(CGI_PATH_INFO, req.getPathInfo());
+        claims.put(CGI_PATH_TRANSLATED, req.getPathTranslated());
+        claims.put(CGI_QUERY_STRING, req.getQueryString());
+        claims.put(CGI_REMOTE_ADDR, req.getRemoteAddr());
+        claims.put(CGI_REMOTE_HOST, req.getRemoteHost());
+        claims.put(CGI_REMOTE_PORT, req.getRemotePort());
+        // remote user might be i18n, assume UTF8 and decode
+        claims.put(CGI_REMOTE_USER, decodeUTF8(req.getRemoteUser()));
+        claims.put(CGI_REMOTE_USER_GROUPS, req.getAttribute(CGI_REMOTE_USER_GROUPS));
+        claims.put(CGI_REQUEST_METHOD, req.getMethod());
+        claims.put(CGI_SCRIPT_NAME, req.getServletPath());
+        claims.put(CGI_SERVER_PROTOCOL, req.getProtocol());
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("ClaimAuthFilter claims = {}", claims.toString());
+        }
+
+        return claims;
+    }
+
+    /**
+     * Decode from UTF-8, return Unicode.
+     *
+     * If we're unable to UTF-8 decode the string the fallback is to return the
+     * string unmodified and log a warning.
+     *
+     * Some data, especially metadata attached to a user principal may be
+     * internationalized (i18n). The classic examples are the user's name,
+     * location, organization, etc. We need to be able to read this metadata and
+     * decode it into unicode characters so that we properly handle i18n string
+     * values.
+     *
+     * One of the the prolems is we often don't know the encoding (i.e. charset)
+     * of the string. RFC-5987 is supposed to define how non-ASCII values are
+     * transmitted in HTTP headers, this is a follow on from the work in
+     * RFC-2231. However at the time of this writing these RFC's are not
+     * implemented in the Servlet Request classes. Not only are these RFC's
+     * unimplemented but they are specific to HTTP headers, much of our metadata
+     * arrives via attributes as opposed to being in a header.
+     *
+     * Note: ASCII encoding is a subset of UTF-8 encoding therefore any strings
+     * which are pure ASCII will decode from UTF-8 just fine. However on the
+     * other hand Latin-1 (ISO-8859-1) encoding is not compatible with UTF-8 for
+     * code points in the range 128-255 (i.e. beyond 7-bit ascii). ISO-8859-1 is
+     * the default encoding for HTTP and HTML 4, however the consensus is the
+     * use of ISO-8859-1 was a mistake and Unicode with UTF-8 encoding is now
+     * the norm. If a string value is transmitted encoded in ISO-8859-1
+     * contaiing code points in the range 128-255 and we try to UTF-8 decode it
+     * it will either not be the correct decoded string or it will throw a
+     * decoding exception.
+     *
+     * Conventional practice at the moment is for the sending side to encode
+     * internationalized values in UTF-8 with the receving end decoding the
+     * value back from UTF-8. We do not expect the use of ISO-8859-1 on these
+     * attributes. However due to peculiarities of the Java String
+     * implementation we have to specify the raw bytes are encoded in ISO-8859-1
+     * just to get back the raw bytes to be able to feed into the UTF-8 decoder.
+     * This doesn't seem right but it is because we need the full 8-bit byte and
+     * the only way to say "unmodified 8-bit bytes" in Java is to call it
+     * ISO-8859-1. Ugh!
+     *
+     * @param string
+     *            The input string in UTF-8 to be decoded.
+     * @return Unicode string
+     */
+    private String decodeUTF8(String string) {
+        if (string == null) {
+            return null;
+        }
+        try {
+            return new String(string.getBytes("ISO8859-1"), "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            LOG.warn("Unable to UTF-8 decode: ", string, e);
+            return string;
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationConfiguration.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationConfiguration.java
new file mode 100644
index 00000000..a68dc15c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationConfiguration.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * AAA federation configurations in OSGi.
+ *
+ * @author liemmn
+ *
+ */
+public class FederationConfiguration implements ManagedService {
+    private static final String FEDERATION_CONFIG_ERR = "Error saving federation configuration";
+
+    static final String HTTP_HEADERS = "httpHeaders";
+    static final String HTTP_ATTRIBUTES = "httpAttributes";
+    static final String SECURE_PROXY_PORTS = "secureProxyPorts";
+
+    static FederationConfiguration instance = new FederationConfiguration();
+
+    static final Hashtable<String, String> defaults = new Hashtable<>();
+    static {
+        defaults.put(HTTP_HEADERS, "");
+        defaults.put(HTTP_ATTRIBUTES, "");
+    }
+    private static Map<String, String> configs = new ConcurrentHashMap<>();
+
+    // singleton
+    private FederationConfiguration() {
+    }
+
+    public static FederationConfiguration instance() {
+        return instance;
+    }
+
+    @Override
+    public void updated(Dictionary<String, ?> props) throws ConfigurationException {
+        if (props == null) {
+            configs.clear();
+            configs.putAll(defaults);
+        } else {
+            try {
+                Enumeration<String> keys = props.keys();
+                while (keys.hasMoreElements()) {
+                    String key = keys.nextElement();
+                    configs.put(key, (String) props.get(key));
+                }
+            } catch (Throwable t) {
+                throw new ConfigurationException(null, FEDERATION_CONFIG_ERR, t);
+            }
+        }
+    }
+
+    public List<String> httpHeaders() {
+        String headers = configs.get(HTTP_HEADERS);
+        return (headers == null) ? new ArrayList<String>() : Arrays.asList(headers.split(" "));
+    }
+
+    public List<String> httpAttributes() {
+        String attributes = configs.get(HTTP_ATTRIBUTES);
+        return (attributes == null) ? new ArrayList<String>() : Arrays
+                .asList(attributes.split(" "));
+    }
+
+    public Set<Integer> secureProxyPorts() {
+        String ports = configs.get(SECURE_PROXY_PORTS);
+        Set<Integer> secureProxyPorts = new TreeSet<Integer>();
+
+        if (ports != null && !ports.isEmpty()) {
+            for (String port : ports.split(" ")) {
+                secureProxyPorts.add(Integer.parseInt(port));
+            }
+        }
+        return secureProxyPorts;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationEndpoint.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationEndpoint.java
new file mode 100644
index 00000000..6ac76c0a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/FederationEndpoint.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
+import org.apache.oltu.oauth2.as.issuer.UUIDValueGenerator;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+
+/**
+ * An endpoint for claim-based authentication federation (in-bound).
+ *
+ * @author liemmn
+ *
+ */
+public class FederationEndpoint extends HttpServlet {
+
+    private static final long serialVersionUID = -5553885846238987245L;
+
+    /** An in-bound authentication claim */
+    static final String AUTH_CLAIM = "AAA-CLAIM";
+
+    private static final String UNAUTHORIZED = "unauthorized";
+
+    private transient OAuthIssuer oi;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        oi = new OAuthIssuerImpl(new UUIDValueGenerator());
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException,
+            ServletException {
+        try {
+            createRefreshToken(req, resp);
+        } catch (Exception e) {
+            error(resp, SC_UNAUTHORIZED, e.getMessage());
+        }
+    }
+
+    // Create a refresh token
+    private void createRefreshToken(HttpServletRequest req, HttpServletResponse resp)
+            throws OAuthSystemException, IOException {
+        Claim claim = (Claim) req.getAttribute(AUTH_CLAIM);
+        oauthRefreshTokenResponse(resp, claim);
+    }
+
+    // Build OAuth refresh token response from the given claim mapped and
+    // injected by the external IdP
+    private void oauthRefreshTokenResponse(HttpServletResponse resp, Claim claim)
+            throws OAuthSystemException, IOException {
+        if (claim == null) {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+
+        String userName = claim.user();
+        // Need to have at least a mapped username!
+        if (userName == null) {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+
+        String domain = claim.domain();
+        // Need to have at least a domain!
+        if (domain == null) {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+
+        String userId = userName + "@" + domain;
+
+        // Create an unscoped ODL context from the external claim
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder(claim).setUserId(userId)
+                .build()).setExpiration(tokenExpiration()).build();
+
+        // Create OAuth response
+        String token = oi.refreshToken();
+        OAuthResponse r = OAuthASResponse
+                .tokenResponse(SC_CREATED)
+                .setRefreshToken(token)
+                .setExpiresIn(Long.toString(auth.expiration()))
+                .setScope(
+                // Use mapped domain if there is one, else list
+                // all the ones that this user has access to
+                        (claim.domain().isEmpty()) ? listToString(ServiceLocator.getInstance()
+                                .getIdmService().listDomains(userId)) : claim.domain())
+                .buildJSONMessage();
+        // Cache this token...
+        ServiceLocator.getInstance().getTokenStore().put(token, auth);
+        write(resp, r);
+    }
+
+    // Token expiration
+    private long tokenExpiration() {
+        return ServiceLocator.getInstance().getTokenStore().tokenExpiration();
+    }
+
+    // Space-delimited string from a list of strings
+    private String listToString(List<String> list) {
+        StringBuffer sb = new StringBuffer();
+        for (String s : list) {
+            sb.append(s).append(" ");
+        }
+        return sb.toString().trim();
+    }
+
+    // Emit an error OAuthResponse with the given HTTP code
+    private void error(HttpServletResponse resp, int httpCode, String error) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(httpCode).setError(error)
+                    .buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    // Write out an OAuthResponse
+    private void write(HttpServletResponse resp, OAuthResponse r) throws IOException {
+        resp.setStatus(r.getResponseStatus());
+        PrintWriter pw = resp.getWriter();
+        pw.print(r.getBody());
+        pw.flush();
+        pw.close();
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ServiceLocator.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ServiceLocator.java
new file mode 100644
index 00000000..dd861514
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/ServiceLocator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import java.util.List;
+import java.util.Vector;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.TokenStore;
+
+/**
+ * A service locator to bridge between the web world and OSGi world.
+ *
+ * @author liemmn
+ *
+ */
+public class ServiceLocator {
+
+    private static final ServiceLocator instance = new ServiceLocator();
+
+    protected volatile List<ClaimAuth> claimAuthCollection = new Vector<>();
+
+    protected volatile TokenStore tokenStore;
+
+    protected volatile IdMService idmService;
+
+    private ServiceLocator() {
+    }
+
+    public static ServiceLocator getInstance() {
+        return instance;
+    }
+
+    /**
+     * Called through reflection from the federation Activator
+     *
+     * @see org.opendaylight.aaa.federation.ServiceLocator
+     * @param ca the injected claims implementation
+     */
+    protected void claimAuthAdded(ClaimAuth ca) {
+        this.claimAuthCollection.add(ca);
+    }
+
+    /**
+     * Called through reflection from the federation Activator
+     *
+     * @see org.opendaylight.aaa.federation.Activator
+     * @param ca the claims implementation to remove
+     */
+    protected void claimAuthRemoved(ClaimAuth ca) {
+        this.claimAuthCollection.remove(ca);
+    }
+
+    public List<ClaimAuth> getClaimAuthCollection() {
+        return claimAuthCollection;
+    }
+
+    public void setClaimAuthCollection(List<ClaimAuth> claimAuthCollection) {
+        this.claimAuthCollection = claimAuthCollection;
+    }
+
+    public TokenStore getTokenStore() {
+        return tokenStore;
+    }
+
+    public void setTokenStore(TokenStore tokenStore) {
+        this.tokenStore = tokenStore;
+    }
+
+    public IdMService getIdmService() {
+        return idmService;
+    }
+
+    public void setIdmService(IdMService idmService) {
+        this.idmService = idmService;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/SssdFilter.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/SssdFilter.java
new file mode 100644
index 00000000..9223c6dd
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/java/org/opendaylight/aaa/federation/SssdFilter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+class SssdHeadersRequest extends HttpServletRequestWrapper {
+    private static final String headerPrefix = "X-SSSD-";
+
+    public SssdHeadersRequest(HttpServletRequest request) {
+        super(request);
+    }
+
+    public Object getAttribute(String name) {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + name);
+        if (headerValue != null) {
+            return headerValue;
+        } else {
+            return request.getAttribute(name);
+        }
+    }
+
+    @Override
+    public String getRemoteUser() {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + "REMOTE_USER");
+        if (headerValue != null) {
+            return headerValue;
+        } else {
+            return request.getRemoteUser();
+        }
+    }
+
+    @Override
+    public String getAuthType() {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + "AUTH_TYPE");
+        if (headerValue != null) {
+            return headerValue;
+        } else {
+            return request.getAuthType();
+        }
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + "REMOTE_ADDR");
+        if (headerValue != null) {
+            return headerValue;
+        } else {
+            return request.getRemoteAddr();
+        }
+    }
+
+    @Override
+    public String getRemoteHost() {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + "REMOTE_HOST");
+        if (headerValue != null) {
+            return headerValue;
+        } else {
+            return request.getRemoteHost();
+        }
+    }
+
+    @Override
+    public int getRemotePort() {
+        HttpServletRequest request = (HttpServletRequest) getRequest();
+        String headerValue;
+
+        headerValue = request.getHeader(headerPrefix + "REMOTE_PORT");
+        if (headerValue != null) {
+            return Integer.parseInt(headerValue);
+        } else {
+            return request.getRemotePort();
+        }
+    }
+
+}
+
+/**
+ * Populate HttpRequestServlet API data from HTTP extension headers.
+ *
+ * When SSSD is used for authentication and identity lookup those actions occur
+ * in an Apache HTTP server which is fronting the servlet container. After
+ * successful authentication Apache will proxy the request to the container
+ * along with additional authentication and identity metadata.
+ *
+ * The preferred way to transport the metadata and have it appear seamlessly in
+ * the servlet API is via the AJP protocol. However AJP may not be available or
+ * desirable. An alternative method is to transport the metadata in extension
+ * HTTP headers. However we still want the standard servlet request API methods
+ * to work. Another way to say this is we do not want upper layers to be aware
+ * of the transport mechanism. To achieve this we wrap the HttpServletRequest
+ * class and override specific methods which need to extract the data from the
+ * extension HTTP headers. (This is roughly equivalent to what happens when AJP
+ * is implemented natively in the container).
+ *
+ * The extension HTTP headers are identified by the prefix "X-SSSD-". The
+ * overridden methods check for the existence of the appropriate extension
+ * header and if present returns the value found in the extension header,
+ * otherwise it returns the value from the method it's wrapping.
+ *
+ */
+public class SssdFilter implements Filter {
+    @Override
+    public void init(FilterConfig fc) throws ServletException {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
+            FilterChain filterChain) throws IOException, ServletException {
+        if (servletRequest instanceof HttpServletRequest) {
+            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+            SssdHeadersRequest request = new SssdHeadersRequest(httpServletRequest);
+            filterChain.doFilter(request, servletResponse);
+        } else {
+            filterChain.doFilter(servletRequest, servletResponse);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.properties b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 00000000..4323c04d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,11 @@
+org.opendaylight.aaa.federation.name = Opendaylight AAA Federation Configuration
+org.opendaylight.aaa.federation.description = Configuration for AAA federation
+org.opendaylight.aaa.federation.httpHeaders.name = Custom HTTP Headers
+org.opendaylight.aaa.federation.httpHeaders.description = Space-delimited list of \
+specific HTTP headers to capture for authentication federation.
+org.opendaylight.aaa.federation.httpAttributes.name = Custom HTTP Attributes
+org.opendaylight.aaa.federation.httpAttributes.description = Space-delimited list of \
+specific HTTP attributes to capture for authentication federation.
+org.opendaylight.aaa.federation.secureProxyPorts.name = Secure Proxy Ports
+org.opendaylight.aaa.federation.secureProxyPorts.description = Space-delimited list of \
+port numbers on which a trusted HTTP proxy performing authentication forwards pre-authenticated requests.
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.xml b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.xml
new file mode 100644
index 00000000..e2efd3d4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
+    localization="OSGI-INF/metatype/metatype">
+    <OCD id="org.opendaylight.aaa.federation" name="%org.opendaylight.aaa.federation.name"
+        description="%org.opendaylight.aaa.federation.description">
+        <AD id="httpHeaders" type="String" default=""
+            name="%org.opendaylight.aaa.federation.httpHeaders.name"
+            description="%org.opendaylight.aaa.federation.httpHeaders.description" />
+        <AD id="httpAttributes" type="String" default=""
+            name="%org.opendaylight.aaa.federation.httpAttributes.name"
+            description="%org.opendaylight.aaa.federation.httpAttributes.description" />
+        <AD id="secureProxyPorts" type="String" default=""
+            name="%org.opendaylight.aaa.federation.secureProxyPorts.name"
+            description="%org.opendaylight.aaa.federation.secureProxyPorts.description" />
+    </OCD>
+    <Designate pid="org.opendaylight.aaa.federation">
+        <Object ocdref="org.opendaylight.aaa.federation" />
+    </Designate>
+</metatype:MetaData>
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/WEB-INF/web.xml b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/WEB-INF/web.xml
new file mode 100644
index 00000000..9fd9751f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/WEB-INF/web.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+    version="3.0">
+
+    <servlet>
+        <servlet-name>federation</servlet-name>
+        <servlet-class>org.opendaylight.aaa.federation.FederationEndpoint</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>federation</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <!-- Federation Auth filter -->
+    <filter>
+        <filter-name>SssdFilter</filter-name>
+        <filter-class>org.opendaylight.aaa.federation.SssdFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>SssdFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+    <filter>
+        <filter-name>ClaimAuthFilter</filter-name>
+        <filter-class>org.opendaylight.aaa.federation.ClaimAuthFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>ClaimAuthFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+</web-app>
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/federation.cfg b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/federation.cfg
new file mode 100644
index 00000000..60ef1c46
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/main/resources/federation.cfg
@@ -0,0 +1,3 @@
+httpHeaders=
+httpAttributes=
+secureProxyPorts=
diff --git a/odl-aaa-moon/aaa/aaa-authn-federation/src/test/java/org/opendaylight/aaa/federation/FederationEndpointTest.java b/odl-aaa-moon/aaa/aaa-authn-federation/src/test/java/org/opendaylight/aaa/federation/FederationEndpointTest.java
new file mode 100644
index 00000000..ae098652
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-federation/src/test/java/org/opendaylight/aaa/federation/FederationEndpointTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.federation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.TreeSet;
+import org.eclipse.jetty.testing.HttpTester;
+import org.eclipse.jetty.testing.ServletTester;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.TokenStore;
+
+/**
+ * A unit test for federation endpoint.
+ *
+ * @author liemmn
+ *
+ */
+public class FederationEndpointTest {
+    private static final long TOKEN_TIMEOUT_SECS = 10;
+    private static final String CONTEXT = "/oauth2/federation";
+
+    private final static ServletTester server = new ServletTester();
+    private static final Claim claim = new ClaimBuilder().setUser("bob").setUserId("1234")
+            .addRole("admin").build();
+
+    @BeforeClass
+    public static void init() throws Exception {
+        // Set up server
+        server.setContextPath(CONTEXT);
+
+        // Add our servlet under test
+        server.addServlet(FederationEndpoint.class, "/*");
+
+        // Add ClaimAuth filter
+        server.addFilter(ClaimAuthFilter.class, "/*", 0);
+
+        // Let's do dis
+        server.start();
+    }
+
+    @AfterClass
+    public static void shutdown() throws Exception {
+        server.stop();
+    }
+
+    @Before
+    public void setup() {
+        mockServiceLocator();
+        when(ServiceLocator.getInstance().getTokenStore().tokenExpiration()).thenReturn(
+                TOKEN_TIMEOUT_SECS);
+    }
+
+    @After
+    public void teardown() {
+        ServiceLocator.getInstance().getClaimAuthCollection().clear();
+    }
+
+    @Test
+    public void testFederationUnconfiguredProxyPort() throws Exception {
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setURI(CONTEXT + "/");
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(401, resp.getStatus());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testFederation() throws Exception {
+        when(ServiceLocator.getInstance().getClaimAuthCollection().get(0).transform(anyMap()))
+                .thenReturn(claim);
+        when(ServiceLocator.getInstance().getIdmService().listDomains(anyString())).thenReturn(
+                Arrays.asList("pepsi", "coke"));
+
+        // Configure secure port (of zero)
+        FederationConfiguration.instance = mock(FederationConfiguration.class);
+        when(FederationConfiguration.instance.secureProxyPorts()).thenReturn(
+                new TreeSet<Integer>(Arrays.asList(0)));
+
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setURI(CONTEXT + "/");
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(201, resp.getStatus());
+        String content = resp.getContent();
+        assertTrue(content.contains("pepsi coke"));
+    }
+
+    private static void mockServiceLocator() {
+        ServiceLocator.getInstance().setIdmService(mock(IdMService.class));
+        ServiceLocator.getInstance().setTokenStore(mock(TokenStore.class));
+        ServiceLocator.getInstance().getClaimAuthCollection().add(mock(ClaimAuth.class));
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-keystone/pom.xml b/odl-aaa-moon/aaa/aaa-authn-keystone/pom.xml
new file mode 100644
index 00000000..e85d620d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-keystone/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-keystone</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpcore-osgi</artifactId>
+            <version>${httpclient.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient-osgi</artifactId>
+            <version>${httpclient.version}</version>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.aaa.keystone.Activator</Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/Activator.java b/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/Activator.java
new file mode 100644
index 00000000..c3c3bfb1
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/Activator.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.keystone;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An activator for {@link KeystoneTokenAuth}.
+ *
+ * @author liemmn
+ *
+ */
+public class Activator extends DependencyActivatorBase {
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent().setInterface(new String[] { TokenAuth.class.getName() }, null)
+                                     .setImplementation(KeystoneTokenAuth.class));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/KeystoneTokenAuth.java b/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/KeystoneTokenAuth.java
new file mode 100644
index 00000000..6f4b4bb1
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-keystone/src/main/java/org/opendaylight/aaa/keystone/KeystoneTokenAuth.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.keystone;
+
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Keystone {@link TokenAuth} filter.
+ *
+ * @author liemmn
+ */
+public class KeystoneTokenAuth implements TokenAuth {
+    private static final Logger LOG = LoggerFactory.getLogger(KeystoneTokenAuth.class);
+
+    static final String TOKEN = "X-Auth-Token";
+
+    @Override
+    public Authentication validate(Map<String, List<String>> headers) {
+        if (!headers.containsKey(TOKEN)) {
+            return null; // Not a Keystone token
+        }
+
+        // TODO: Call into Keystone to get security context...
+        LOG.info("Not yet validating token {}", headers.get(TOKEN).get(0));
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/pom.xml b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/pom.xml
new file mode 100644
index 00000000..da6f27f1
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-mdsal-api</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>yang-ext</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <stylesheet>maven</stylesheet>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>aggregate</goal>
+                        </goals>
+                        <phase>site</phase>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+    <packaging>bundle</packaging>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/src/main/yang/aaa-authn-model.yang b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/src/main/yang/aaa-authn-model.yang
new file mode 100644
index 00000000..227cb313
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-api/src/main/yang/aaa-authn-model.yang
@@ -0,0 +1,154 @@
+module aaa-authn-model {
+  yang-version 1;
+  namespace "urn:aaa:yang:authn:claims";
+  prefix "authn";
+    organization "TBD";
+
+    contact "wdec@cisco.com";
+
+    revision 2014-10-29 {
+        description
+            "Initial revision.";
+    }
+
+//Main module begins
+
+// Following container provides the AuthN Claims data-structure
+
+  container tokencache {
+    config false;
+    list claims {
+      key "token";
+
+      leaf token {
+        type string;
+        description "Token";
+      }
+      leaf clientId {
+        type string;
+        description "id of the authorized client, or null if anonymous";
+      }
+      leaf userId {
+        type string;
+        description "Unique user-id. User IDs are system-created";
+      }
+      leaf user {
+        type string;
+        description "User name";
+      }
+      leaf domain {
+        type string;
+        description "Fully-qualified domain name";
+      }
+      leaf-list roles {
+        type string;
+        description "Assigned user roles";
+      }
+    }
+  }
+
+  container token_cache_times {
+
+    list token_list {
+      key userId;
+
+      leaf userId {
+        //TODO: Change to instance-ref
+        type string;
+      }
+
+    list user_tokens {
+      key tokenid;
+      leaf tokenid {
+        type leafref {path "/tokencache/claims/token";}
+      }
+      leaf timestamp {
+        type uint64;
+      }
+      leaf expiration {
+          type int64;
+          description "Expiration milliseconds since start of UTC epoch";
+      }
+      }
+    }
+  }
+
+  //authentication model is for generating objects to be stores in the
+  //data store for all the prev idm model objects.
+  container authentication{
+     list domain{
+         key domainid;
+         leaf domainid {
+             type string;
+         }
+         leaf name {
+             type string;
+         }
+         leaf description {
+             type string;
+         }
+         leaf enabled {
+             type boolean;
+         }
+     }
+
+     list user {
+         key userid;
+         leaf userid {
+             type string;
+         }
+         leaf name {
+             type string;
+         }
+         leaf description {
+             type string;
+         }
+         leaf enabled {
+             type boolean;
+         }
+         leaf email {
+             type string;
+         }
+         leaf password {
+             type string;
+         }
+         leaf salt {
+             type string;
+         }
+         leaf domainid {
+             type string;
+         }
+     }
+     list role {
+         key roleid;
+         leaf roleid {
+             type string;
+         }
+         leaf name {
+             type string;
+         }
+         leaf description {
+             type string;
+         }
+         leaf domainid {
+             type string;
+         }
+     }
+
+     list grant {
+         key grantid;
+         leaf grantid {
+             type string;
+         }
+         leaf domainid {
+             type string;
+         }
+         leaf userid {
+             type string;
+         }
+         leaf roleid {
+             type string;
+         }
+     }
+  }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/pom.xml b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/pom.xml
new file mode 100644
index 00000000..3ac6e57f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-mdsal-config</artifactId>
+    <description>AuthN Token Store Service Configuration file </description>
+    <packaging>jar</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/initial/${config.authn.store.configfile}</file>
+                                    <type>xml</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/src/main/resources/initial/08-authn-config.xml b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/src/main/resources/initial/08-authn-config.xml
new file mode 100644
index 00000000..e4a78f4d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-config/src/main/resources/initial/08-authn-config.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+                <!-- defines an implementation module -->
+                <module>
+                    <type xmlns:authn="config:aaa:authn:mdsal:store">authn:aaa-authn-mdsal-store</type>
+                    <name>aaa-authn-mdsal-store</name>
+                    <dom-broker>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                            dom:dom-broker-osgi-registry
+                        </type>
+                        <name>dom-broker</name>
+                    </dom-broker>
+                    <data-broker>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                            binding:binding-async-data-broker
+                        </type>
+                        <name>binding-data-broker</name>
+                    </data-broker>
+                    <timeToLive>3600000</timeToLive>
+                    <timeToWait>15</timeToWait>
+                    <password>CHANGE_ME</password>
+                </module>
+            </modules>
+        </data>
+
+    </configuration>
+    <required-capabilities>
+        <capability>config:aaa:authn:mdsal:store?module=aaa-authn-mdsal-store-cfg&amp;revision=2014-10-31</capability>
+    </required-capabilities>
+
+</snapshot>
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/pom.xml b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/pom.xml
new file mode 100644
index 00000000..069ec60c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/pom.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-mdsal-store-impl</artifactId>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <powermock.version>1.5.2</powermock.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-core-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-mdsal-api</artifactId>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-api-mockito</artifactId>
+          <version>${powermock.version}</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-module-junit4</artifactId>
+          <version>${powermock.version}</version>
+          <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <!-- <Bundle-Activator>/Bundle-Activator> -->
+                        <Export-Package>org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+                <!-- <configuration> <Export-Package> </Export-Package> </configuration> -->
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/AuthNStore.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/AuthNStore.java
new file mode 100644
index 00000000..09170182
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/AuthNStore.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import java.math.BigInteger;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenStore;
+import org.opendaylight.aaa.authn.mdsal.store.util.AuthNStoreUtil;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.TokenCacheTimes;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenList;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenListKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokens;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.Claims;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthNStore implements AutoCloseable, TokenStore {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthNStore.class);
+    private DataBroker broker;
+    private static BigInteger timeToLive;
+    private static Integer timeToWait;
+    private final ExecutorService deleteExpiredTokenThread = Executors.newFixedThreadPool(1);
+    private final DataEncrypter dataEncrypter;
+
+    public AuthNStore(final DataBroker dataBroker, final String config_key) {
+        this.broker = dataBroker;
+        this.dataEncrypter = new DataEncrypter(config_key);
+        LOG.info("Created MD-SAL AAA Token Cache Service...");
+    }
+
+    @Override
+    public void close() throws Exception {
+        deleteExpiredTokenThread.shutdown();
+        LOG.info("MD-SAL AAA Token Cache closed...");
+
+    }
+
+    @Override
+    public void put(String token, Authentication auth) {
+        token = dataEncrypter.encrypt(token);
+        Claims claims = AuthNStoreUtil.createClaimsRecord(token, auth);
+
+        // create and insert parallel struct
+        UserTokens userTokens = AuthNStoreUtil.createUserTokens(token, timeToLive.longValue());
+        TokenList tokenlist = AuthNStoreUtil.createTokenList(userTokens, auth.userId());
+
+        writeClaimAndTokenToStore(claims, userTokens, tokenlist);
+        deleteExpiredTokenThread.execute(deleteOldTokens(claims));
+    }
+
+    @Override
+    public Authentication get(String token) {
+        token = dataEncrypter.encrypt(token);
+        Authentication authentication = null;
+        Claims claims = readClaims(token);
+        if (claims != null) {
+            UserTokens userToken = readUserTokensFromDS(claims.getToken(), claims.getUserId());
+            authentication = AuthNStoreUtil.convertClaimToAuthentication(claims,
+                    userToken.getExpiration());
+        }
+        deleteExpiredTokenThread.execute(deleteOldTokens(claims));
+        return authentication;
+    }
+
+    @Override
+    public boolean delete(String token) {
+        token = dataEncrypter.encrypt(token);
+        boolean result = false;
+        Claims claims = readClaims(token);
+        result = deleteClaims(token);
+        if (result) {
+            deleteUserTokenFromDS(token, claims.getUserId());
+        }
+        deleteExpiredTokenThread.execute(deleteOldTokens(claims));
+        return result;
+    }
+
+    @Override
+    public long tokenExpiration() {
+        return timeToLive.longValue();
+    }
+
+    public void setTimeToLive(BigInteger timeToLive) {
+        this.timeToLive = timeToLive;
+    }
+
+    public void setTimeToWait(Integer timeToWait) {
+        this.timeToWait = timeToWait;
+    }
+
+    private void writeClaimAndTokenToStore(final Claims claims, UserTokens usertokens,
+            final TokenList tokenlist) {
+
+        final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(claims.getToken());
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.put(LogicalDatastoreType.OPERATIONAL, claims_iid, claims, true);
+
+        final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
+                tokenlist.getUserId(), usertokens.getTokenid());
+        tx.put(LogicalDatastoreType.OPERATIONAL, userTokens_iid, usertokens, true);
+
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
+        Futures.addCallback(commitFuture, new FutureCallback<Void>() {
+
+            @Override
+            public void onSuccess(Void result) {
+                LOG.trace("Token {} was written to datastore.", claims.getToken());
+                LOG.trace("Tokenlist for userId {} was written to datastore.",
+                        tokenlist.getUserId());
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.error("Inserting token {} to datastore failed.", claims.getToken());
+                LOG.trace("Inserting for userId {} tokenlist to datastore failed.",
+                        tokenlist.getUserId());
+            }
+
+        });
+    }
+
+    private Claims readClaims(String token) {
+        final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(token);
+        Claims claims = null;
+        ReadTransaction rt = broker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Claims>, ReadFailedException> claimsFuture = rt.read(
+                LogicalDatastoreType.OPERATIONAL, claims_iid);
+        try {
+            Optional<Claims> maybeClaims = claimsFuture.checkedGet();
+            if (maybeClaims.isPresent()) {
+                claims = maybeClaims.get();
+            }
+        } catch (ReadFailedException e) {
+            LOG.error(
+                    "Something wrong happened in DataStore. Getting Claim for token {} failed.",
+                    token, e);
+        }
+        return claims;
+    }
+
+    private TokenList readTokenListFromDS(String userId) {
+        InstanceIdentifier<TokenList> tokenList_iid = InstanceIdentifier.builder(
+                TokenCacheTimes.class).child(TokenList.class, new TokenListKey(userId)).build();
+        TokenList tokenList = null;
+        ReadTransaction rt = broker.newReadOnlyTransaction();
+        CheckedFuture<Optional<TokenList>, ReadFailedException> userTokenListFuture = rt.read(
+                LogicalDatastoreType.OPERATIONAL, tokenList_iid);
+        try {
+            Optional<TokenList> maybeTokenList = userTokenListFuture.checkedGet();
+            if (maybeTokenList.isPresent()) {
+                tokenList = maybeTokenList.get();
+            }
+        } catch (ReadFailedException e) {
+            LOG.error(
+                    "Something wrong happened in DataStore. Getting TokenList for userId {} failed.",
+                    userId, e);
+        }
+        return tokenList;
+    }
+
+    private UserTokens readUserTokensFromDS(String token, String userId) {
+        final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
+                userId, token);
+        UserTokens userTokens = null;
+
+        ReadTransaction rt = broker.newReadOnlyTransaction();
+        CheckedFuture<Optional<UserTokens>, ReadFailedException> userTokensFuture = rt.read(
+                LogicalDatastoreType.OPERATIONAL, userTokens_iid);
+
+        try {
+            Optional<UserTokens> maybeUserTokens = userTokensFuture.checkedGet();
+            if (maybeUserTokens.isPresent()) {
+                userTokens = maybeUserTokens.get();
+            }
+        } catch (ReadFailedException e) {
+            LOG.error(
+                    "Something wrong happened in DataStore. Getting UserTokens for token {} failed.",
+                    token, e);
+        }
+
+        return userTokens;
+    }
+
+    private boolean deleteClaims(String token) {
+        final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(token);
+        boolean result = false;
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.delete(LogicalDatastoreType.OPERATIONAL, claims_iid);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
+
+        try {
+            commitFuture.checkedGet();
+            result = true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Something wrong happened in DataStore. Claim "
+                    + "deletion for token {} from DataStore failed.", token, e);
+        }
+        return result;
+    }
+
+    private void deleteUserTokenFromDS(String token, String userId) {
+        final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
+                userId, token);
+
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.delete(LogicalDatastoreType.OPERATIONAL, userTokens_iid);
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
+        try {
+            commitFuture.checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Something wrong happened in DataStore. UserToken "
+                    + "deletion for token {} from DataStore failed.", token, e);
+        }
+    }
+
+    private Runnable deleteOldTokens(final Claims claims) {
+        return new Runnable() {
+
+            @Override
+            public void run() {
+                TokenList tokenList = null;
+                if (claims != null) {
+                    tokenList = readTokenListFromDS(claims.getUserId());
+                }
+                if (tokenList != null) {
+                    for (UserTokens currUserToken : tokenList.getUserTokens()) {
+                        long diff = System.currentTimeMillis()
+                                - currUserToken.getTimestamp().longValue();
+                        if (diff > currUserToken.getExpiration()
+                                && currUserToken.getExpiration() != 0) {
+                            if (deleteClaims(currUserToken.getTokenid())) {
+                                deleteUserTokenFromDS(currUserToken.getTokenid(),
+                                        claims.getUserId());
+                                LOG.trace("Expired tokens for UserId {} deleted.",
+                                        claims.getUserId());
+                            }
+                        }
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypter.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypter.java
new file mode 100644
index 00000000..ca0a74be
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypter.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import java.security.spec.KeySpec;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author - Sharon Aicler (saichler@cisco.com)
+ **/
+public class DataEncrypter {
+
+    final protected SecretKey k;
+    private static final Logger LOG = LoggerFactory.getLogger(DataEncrypter.class);
+    private static final byte[] iv = { 0, 5, 0, 0, 7, 81, 0, 3, 0, 0, 0, 0, 0, 43, 0, 1 };
+    private static final IvParameterSpec ivspec = new IvParameterSpec(iv);
+    public static final String ENCRYPTED_TAG = "Encrypted:";
+
+    public DataEncrypter(final String ckey) {
+        SecretKey tmp = null;
+        if (ckey != null && !ckey.isEmpty()) {
+
+            try {
+                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+                KeySpec spec = new PBEKeySpec(ckey.toCharArray(), iv, 32768, 128);
+                tmp = keyFactory.generateSecret(spec);
+            } catch (Exception e) {
+                LOG.error("Couldn't initialize key factory", e);
+            }
+            if (tmp != null) {
+                k = new SecretKeySpec(tmp.getEncoded(), "AES");
+            } else {
+                throw new RuntimeException("Couldn't initalize encryption key");
+            }
+        } else {
+            k = null;
+            LOG.warn("Void crypto key passed! AuthN Store Encryption disabled");
+        }
+
+    }
+
+    protected String encrypt(String token) {
+
+        if (k == null) {
+            return token;
+        }
+
+        String cryptostring = null;
+        try {
+            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            c.init(Cipher.ENCRYPT_MODE, k, ivspec);
+            byte[] cryptobytes = c.doFinal(token.getBytes());
+            cryptostring = DatatypeConverter.printBase64Binary(cryptobytes);
+            return ENCRYPTED_TAG + cryptostring;
+        } catch (Exception e) {
+            LOG.error("Couldn't encrypt token", e);
+            return null;
+        }
+    }
+
+    protected String decrypt(String eToken) {
+        if (k == null) {
+            return eToken;
+        }
+
+        if (eToken == null || eToken.length() == 0) {
+            return null;
+        }
+
+        if (!eToken.startsWith(ENCRYPTED_TAG)) {
+            return eToken;
+        }
+
+        try {
+            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            c.init(Cipher.DECRYPT_MODE, k, ivspec);
+
+            byte[] cryptobytes = DatatypeConverter.parseBase64Binary(eToken.substring(ENCRYPTED_TAG.length()));
+            byte[] clearbytes = c.doFinal(cryptobytes);
+            return DatatypeConverter.printBase64Binary(clearbytes);
+
+        } catch (Exception e) {
+            LOG.error("Couldn't decrypt token", e);
+            return null;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMMDSALStore.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMMDSALStore.java
new file mode 100644
index 00000000..88fba0ba
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMMDSALStore.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.SHA256Calculator;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.Authentication;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.DomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.DomainKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.GrantBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.GrantKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.RoleBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.RoleKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.UserBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.UserKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sharon Aicler - saichler@cisco.com
+ *
+ */
+public class IDMMDSALStore {
+
+    private static final Logger LOG = LoggerFactory.getLogger(IDMMDSALStore.class);
+    private final DataBroker dataBroker;
+
+    public IDMMDSALStore(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    public static final String getString(String aValue, String bValue) {
+        if (aValue != null)
+            return aValue;
+        return bValue;
+    }
+
+    public static final Boolean getBoolean(Boolean aValue, Boolean bValue) {
+        if (aValue != null)
+            return aValue;
+        return bValue;
+    }
+
+    public static boolean waitForSubmit(CheckedFuture<Void, TransactionCommitFailedException> submit) {
+        // This can happen only when testing
+        if (submit == null)
+            return false;
+        while (!submit.isDone() && !submit.isCancelled()) {
+            try {
+                Thread.sleep(1000);
+            } catch (Exception err) {
+                LOG.error("Interrupted", err);
+            }
+        }
+        return submit.isCancelled();
+    }
+
+    // Domain methods
+    public Domain writeDomain(Domain domain) {
+        Preconditions.checkNotNull(domain);
+        Preconditions.checkNotNull(domain.getName());
+        Preconditions.checkNotNull(domain.isEnabled());
+        DomainBuilder b = new DomainBuilder();
+        b.setDescription(domain.getDescription());
+        b.setDomainid(domain.getName());
+        b.setEnabled(domain.isEnabled());
+        b.setName(domain.getName());
+        b.setKey(new DomainKey(b.getName()));
+        domain = b.build();
+        InstanceIdentifier<Domain> ID = InstanceIdentifier.create(Authentication.class).child(
+                Domain.class, new DomainKey(domain.getDomainid()));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.put(LogicalDatastoreType.CONFIGURATION, ID, domain, true);
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrt.submit();
+        if (!waitForSubmit(submit)) {
+            return domain;
+        } else {
+            return null;
+        }
+    }
+
+    public Domain readDomain(String domainid) {
+        Preconditions.checkNotNull(domainid);
+        InstanceIdentifier<Domain> ID = InstanceIdentifier.create(Authentication.class).child(
+                Domain.class, new DomainKey(domainid));
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Domain>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, ID);
+        if (read == null) {
+            LOG.error("Failed to read domain from data store");
+            return null;
+        }
+        Optional<Domain> optional = null;
+        try {
+            optional = read.get();
+        } catch (InterruptedException | ExecutionException e1) {
+            LOG.error("Failed to read domain from data store", e1);
+            return null;
+        }
+
+        if (optional == null)
+            return null;
+
+        if (!optional.isPresent())
+            return null;
+
+        return optional.get();
+    }
+
+    public Domain deleteDomain(String domainid) {
+        Preconditions.checkNotNull(domainid);
+        Domain domain = readDomain(domainid);
+        if (domain == null) {
+            LOG.error("Failed to delete domain from data store, unknown domain");
+            return null;
+        }
+        InstanceIdentifier<Domain> ID = InstanceIdentifier.create(Authentication.class).child(
+                Domain.class, new DomainKey(domainid));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.delete(LogicalDatastoreType.CONFIGURATION, ID);
+        wrt.submit();
+        return domain;
+    }
+
+    public Domain updateDomain(Domain domain) throws IDMStoreException {
+        Preconditions.checkNotNull(domain);
+        Preconditions.checkNotNull(domain.getDomainid());
+        Domain existing = readDomain(domain.getDomainid());
+        DomainBuilder b = new DomainBuilder();
+        b.setDescription(getString(domain.getDescription(), existing.getDescription()));
+        b.setName(existing.getName());
+        b.setEnabled(getBoolean(domain.isEnabled(), existing.isEnabled()));
+        return writeDomain(b.build());
+    }
+
+    public List<Domain> getAllDomains() {
+        InstanceIdentifier<Authentication> id = InstanceIdentifier.create(Authentication.class);
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Authentication>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, id);
+        if (read == null)
+            return null;
+
+        try {
+            if (read.get() == null)
+                return null;
+            if (read.get().isPresent()) {
+                Authentication auth = read.get().get();
+                return auth.getDomain();
+            }
+        } catch (Exception err) {
+            LOG.error("Failed to read domains", err);
+        }
+        return null;
+    }
+
+    public List<Role> getAllRoles() {
+        InstanceIdentifier<Authentication> id = InstanceIdentifier.create(Authentication.class);
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Authentication>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, id);
+        if (read == null)
+            return null;
+
+        try {
+            if (read.get() == null)
+                return null;
+            if (read.get().isPresent()) {
+                Authentication auth = read.get().get();
+                return auth.getRole();
+            }
+        } catch (Exception err) {
+            LOG.error("Failed to read domains", err);
+        }
+        return null;
+    }
+
+    public List<User> getAllUsers() {
+        InstanceIdentifier<Authentication> id = InstanceIdentifier.create(Authentication.class);
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Authentication>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, id);
+        if (read == null)
+            return null;
+
+        try {
+            if (read.get() == null)
+                return null;
+            if (read.get().isPresent()) {
+                Authentication auth = read.get().get();
+                return auth.getUser();
+            }
+        } catch (Exception err) {
+            LOG.error("Failed to read domains", err);
+        }
+        return null;
+    }
+
+    public List<Grant> getAllGrants() {
+        InstanceIdentifier<Authentication> id = InstanceIdentifier.create(Authentication.class);
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Authentication>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, id);
+        if (read == null)
+            return null;
+
+        try {
+            if (read.get() == null)
+                return null;
+            if (read.get().isPresent()) {
+                Authentication auth = read.get().get();
+                return auth.getGrant();
+            }
+        } catch (Exception err) {
+            LOG.error("Failed to read domains", err);
+        }
+        return null;
+    }
+
+    // Role methods
+    public Role writeRole(Role role) {
+        Preconditions.checkNotNull(role);
+        Preconditions.checkNotNull(role.getName());
+        Preconditions.checkNotNull(role.getDomainid());
+        Preconditions.checkNotNull(readDomain(role.getDomainid()));
+        RoleBuilder b = new RoleBuilder();
+        b.setDescription(role.getDescription());
+        b.setRoleid(IDMStoreUtil.createRoleid(role.getName(), role.getDomainid()));
+        b.setKey(new RoleKey(b.getRoleid()));
+        b.setName(role.getName());
+        b.setDomainid(role.getDomainid());
+        role = b.build();
+        InstanceIdentifier<Role> ID = InstanceIdentifier.create(Authentication.class).child(
+                Role.class, new RoleKey(role.getRoleid()));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.put(LogicalDatastoreType.CONFIGURATION, ID, role, true);
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrt.submit();
+        if (!waitForSubmit(submit)) {
+            return role;
+        } else {
+            return null;
+        }
+    }
+
+    public Role readRole(String roleid) {
+        Preconditions.checkNotNull(roleid);
+        InstanceIdentifier<Role> ID = InstanceIdentifier.create(Authentication.class).child(
+                Role.class, new RoleKey(roleid));
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Role>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, ID);
+        if (read == null) {
+            LOG.error("Failed to read role from data store");
+            return null;
+        }
+        Optional<Role> optional = null;
+        try {
+            optional = read.get();
+        } catch (InterruptedException | ExecutionException e1) {
+            LOG.error("Failed to read role from data store", e1);
+            return null;
+        }
+
+        if (optional == null)
+            return null;
+
+        if (!optional.isPresent())
+            return null;
+
+        return optional.get();
+    }
+
+    public Role deleteRole(String roleid) {
+        Preconditions.checkNotNull(roleid);
+        Role role = readRole(roleid);
+        if (role == null) {
+            LOG.error("Failed to delete role from data store, unknown role");
+            return null;
+        }
+        InstanceIdentifier<Role> ID = InstanceIdentifier.create(Authentication.class).child(
+                Role.class, new RoleKey(roleid));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.delete(LogicalDatastoreType.CONFIGURATION, ID);
+        wrt.submit();
+        return role;
+    }
+
+    public Role updateRole(Role role) {
+        Preconditions.checkNotNull(role);
+        Preconditions.checkNotNull(role.getRoleid());
+        Role existing = readRole(role.getRoleid());
+        RoleBuilder b = new RoleBuilder();
+        b.setDescription(getString(role.getDescription(), existing.getDescription()));
+        b.setName(existing.getName());
+        b.setDomainid(existing.getDomainid());
+        return writeRole(b.build());
+    }
+
+    // User methods
+    public User writeUser(User user) throws IDMStoreException {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(user.getName());
+        Preconditions.checkNotNull(user.getDomainid());
+        Preconditions.checkNotNull(readDomain(user.getDomainid()));
+        UserBuilder b = new UserBuilder();
+        if (user.getSalt() == null) {
+            b.setSalt(SHA256Calculator.generateSALT());
+        } else {
+            b.setSalt(user.getSalt());
+        }
+        b.setUserid(IDMStoreUtil.createUserid(user.getName(), user.getDomainid()));
+        b.setDescription(user.getDescription());
+        b.setDomainid(user.getDomainid());
+        b.setEmail(user.getEmail());
+        b.setEnabled(user.isEnabled());
+        b.setKey(new UserKey(b.getUserid()));
+        b.setName(user.getName());
+        b.setPassword(SHA256Calculator.getSHA256(user.getPassword(), b.getSalt()));
+        user = b.build();
+        InstanceIdentifier<User> ID = InstanceIdentifier.create(Authentication.class).child(
+                User.class, new UserKey(user.getUserid()));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.put(LogicalDatastoreType.CONFIGURATION, ID, user, true);
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrt.submit();
+        if (!waitForSubmit(submit)) {
+            return user;
+        } else {
+            return null;
+        }
+    }
+
+    public User readUser(String userid) {
+        Preconditions.checkNotNull(userid);
+        InstanceIdentifier<User> ID = InstanceIdentifier.create(Authentication.class).child(
+                User.class, new UserKey(userid));
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<User>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, ID);
+        if (read == null) {
+            LOG.error("Failed to read user from data store");
+            return null;
+        }
+        Optional<User> optional = null;
+        try {
+            optional = read.get();
+        } catch (InterruptedException | ExecutionException e1) {
+            LOG.error("Failed to read domain from data store", e1);
+            return null;
+        }
+
+        if (optional == null)
+            return null;
+
+        if (!optional.isPresent())
+            return null;
+
+        return optional.get();
+    }
+
+    public User deleteUser(String userid) {
+        Preconditions.checkNotNull(userid);
+        User user = readUser(userid);
+        if (user == null) {
+            LOG.error("Failed to delete user from data store, unknown user");
+            return null;
+        }
+        InstanceIdentifier<User> ID = InstanceIdentifier.create(Authentication.class).child(
+                User.class, new UserKey(userid));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.delete(LogicalDatastoreType.CONFIGURATION, ID);
+        wrt.submit();
+        return user;
+    }
+
+    public User updateUser(User user) throws IDMStoreException {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(user.getUserid());
+        User existing = readUser(user.getUserid());
+        UserBuilder b = new UserBuilder();
+        b.setName(existing.getName());
+        b.setDomainid(existing.getDomainid());
+        b.setDescription(getString(user.getDescription(), existing.getDescription()));
+        b.setEmail(getString(user.getEmail(), existing.getEmail()));
+        b.setEnabled(getBoolean(user.isEnabled(), existing.isEnabled()));
+        b.setPassword(getString(user.getPassword(), existing.getPassword()));
+        b.setSalt(getString(user.getSalt(), existing.getSalt()));
+        return writeUser(b.build());
+    }
+
+    // Grant methods
+    public Grant writeGrant(Grant grant) throws IDMStoreException {
+        Preconditions.checkNotNull(grant);
+        Preconditions.checkNotNull(grant.getDomainid());
+        Preconditions.checkNotNull(grant.getUserid());
+        Preconditions.checkNotNull(grant.getRoleid());
+        Preconditions.checkNotNull(readDomain(grant.getDomainid()));
+        Preconditions.checkNotNull(readUser(grant.getUserid()));
+        Preconditions.checkNotNull(readRole(grant.getRoleid()));
+        GrantBuilder b = new GrantBuilder();
+        b.setDomainid(grant.getDomainid());
+        b.setRoleid(grant.getRoleid());
+        b.setUserid(grant.getUserid());
+        b.setGrantid(IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(),
+                grant.getRoleid()));
+        b.setKey(new GrantKey(b.getGrantid()));
+        grant = b.build();
+        InstanceIdentifier<Grant> ID = InstanceIdentifier.create(Authentication.class).child(
+                Grant.class, new GrantKey(grant.getGrantid()));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.put(LogicalDatastoreType.CONFIGURATION, ID, grant, true);
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrt.submit();
+        if (!waitForSubmit(submit)) {
+            return grant;
+        } else {
+            return null;
+        }
+    }
+
+    public Grant readGrant(String grantid) {
+        Preconditions.checkNotNull(grantid);
+        InstanceIdentifier<Grant> ID = InstanceIdentifier.create(Authentication.class).child(
+                Grant.class, new GrantKey(grantid));
+        ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+        CheckedFuture<Optional<Grant>, ReadFailedException> read = rot.read(
+                LogicalDatastoreType.CONFIGURATION, ID);
+        if (read == null) {
+            LOG.error("Failed to read grant from data store");
+            return null;
+        }
+        Optional<Grant> optional = null;
+        try {
+            optional = read.get();
+        } catch (InterruptedException | ExecutionException e1) {
+            LOG.error("Failed to read domain from data store", e1);
+            return null;
+        }
+
+        if (optional == null)
+            return null;
+
+        if (!optional.isPresent())
+            return null;
+
+        return optional.get();
+    }
+
+    public Grant deleteGrant(String grantid) {
+        Preconditions.checkNotNull(grantid);
+        Grant grant = readGrant(grantid);
+        if (grant == null) {
+            LOG.error("Failed to delete grant from data store, unknown grant");
+            return null;
+        }
+        InstanceIdentifier<Grant> ID = InstanceIdentifier.create(Authentication.class).child(
+                Grant.class, new GrantKey(grantid));
+        WriteTransaction wrt = dataBroker.newWriteOnlyTransaction();
+        wrt.delete(LogicalDatastoreType.CONFIGURATION, ID);
+        wrt.submit();
+        return grant;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMObject2MDSAL.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMObject2MDSAL.java
new file mode 100644
index 00000000..0b58ced7
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMObject2MDSAL.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.DomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.GrantBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.RoleBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.UserBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+/**
+ *
+ * @author saichler@gmail.com
+ *
+ * This class is a codec to convert between MDSAL objects and IDM model objects. It is doing so via reflection when it assumes that the MDSAL
+ * Object and the IDM model object has the same method names.
+ */
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sharon Aicler - saichler@cisco.com
+ *
+ */
+public abstract class IDMObject2MDSAL {
+    private static final Logger LOG = LoggerFactory.getLogger(IDMObject2MDSAL.class);
+    // this is a Map mapping between the class type of the IDM Model object to a
+    // structure containing the corresponding setters and getter methods
+    // in MDSAL object
+    private static Map<Class<?>, ConvertionMethods> typesMethods = new HashMap<Class<?>, ConvertionMethods>();
+
+    // This method generically via reflection receive a MDSAL object and the
+    // corresponding IDM model object class type and
+    // creates an IDM model element from the MDSAL element
+    private static Object fromMDSALObject(Object mdsalObject, Class<?> type) throws Exception {
+        if (mdsalObject == null)
+            return null;
+        Object result = type.newInstance();
+        ConvertionMethods cm = typesMethods.get(type);
+        if (cm == null) {
+            cm = new ConvertionMethods();
+            typesMethods.put(type, cm);
+            Method methods[] = type.getMethods();
+            for (Method m : methods) {
+                if (m.getName().startsWith("set")) {
+                    cm.setMethods.add(m);
+                    Method gm = null;
+                    if (m.getParameterTypes()[0].equals(Boolean.class)
+                            || m.getParameterTypes()[0].equals(boolean.class))
+                        gm = ((DataObject) mdsalObject).getImplementedInterface().getMethod(
+                                "is" + m.getName().substring(3), (Class[]) null);
+                    else {
+                        try {
+                            gm = ((DataObject) mdsalObject).getImplementedInterface().getMethod(
+                                    "get" + m.getName().substring(3), (Class[]) null);
+                        } catch (Exception err) {
+                            LOG.error("Error associating get call", err);
+                        }
+                    }
+                    cm.getMethods.put(m.getName(), gm);
+                }
+            }
+        }
+        for (Method m : cm.setMethods) {
+            try {
+                m.invoke(
+                        result,
+                        new Object[] { cm.getMethods.get(m.getName()).invoke(mdsalObject,
+                                (Object[]) null) });
+            } catch (Exception err) {
+                LOG.error("Error invoking reflection method", err);
+            }
+        }
+        return result;
+    }
+
+    // This method generically use reflection to receive an IDM model object and
+    // the corresponsing MDSAL object and creates
+    // a MDSAL object out of the IDM model object
+    private static Object toMDSALObject(Object object, Class<?> mdSalBuilderType) throws Exception {
+        if (object == null)
+            return null;
+        Object result = mdSalBuilderType.newInstance();
+        ConvertionMethods cm = typesMethods.get(mdSalBuilderType);
+        if (cm == null) {
+            cm = new ConvertionMethods();
+            typesMethods.put(mdSalBuilderType, cm);
+            Method methods[] = mdSalBuilderType.getMethods();
+            for (Method m : methods) {
+                if (m.getName().startsWith("set")) {
+                    try {
+                        Method gm = null;
+                        if (m.getParameterTypes()[0].equals(Boolean.class)
+                                || m.getParameterTypes()[0].equals(boolean.class))
+                            gm = object.getClass().getMethod("is" + m.getName().substring(3),
+                                    (Class[]) null);
+                        else
+                            gm = object.getClass().getMethod("get" + m.getName().substring(3),
+                                    (Class[]) null);
+                        cm.getMethods.put(m.getName(), gm);
+                        cm.setMethods.add(m);
+                    } catch (NoSuchMethodException err) {
+                    }
+                }
+            }
+            cm.builderMethod = mdSalBuilderType.getMethod("build", (Class[]) null);
+        }
+        for (Method m : cm.setMethods) {
+            m.invoke(result,
+                    new Object[] { cm.getMethods.get(m.getName()).invoke(object, (Object[]) null) });
+        }
+
+        return cm.builderMethod.invoke(result, (Object[]) null);
+    }
+
+    // A struccture class to hold the getters & setters of each type to speed
+    // things up
+    private static class ConvertionMethods {
+        private List<Method> setMethods = new ArrayList<Method>();
+        private Map<String, Method> getMethods = new HashMap<String, Method>();
+        private Method builderMethod = null;
+    }
+
+    // Convert Domain
+    public static org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain toMDSALDomain(
+            Domain domain) {
+        try {
+            return (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain) toMDSALObject(
+                    domain, DomainBuilder.class);
+        } catch (Exception err) {
+            LOG.error("Error converting domain to MDSAL object", err);
+            return null;
+        }
+    }
+
+    public static Domain toIDMDomain(
+            org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain domain) {
+        try {
+            return (Domain) fromMDSALObject(domain, Domain.class);
+        } catch (Exception err) {
+            LOG.error("Error converting domain from MDSAL to IDM object", err);
+            return null;
+        }
+    }
+
+    // Convert Role
+    public static org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role toMDSALRole(
+            Role role) {
+        try {
+            return (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role) toMDSALObject(
+                    role, RoleBuilder.class);
+        } catch (Exception err) {
+            LOG.error("Error converting role to MDSAL object", err);
+            return null;
+        }
+    }
+
+    public static Role toIDMRole(
+            org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role role) {
+        try {
+            return (Role) fromMDSALObject(role, Role.class);
+        } catch (Exception err) {
+            LOG.error("Error converting role fom MDSAL to IDM object", err);
+            return null;
+        }
+    }
+
+    // Convert User
+    public static org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User toMDSALUser(
+            User user) {
+        try {
+            return (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User) toMDSALObject(
+                    user, UserBuilder.class);
+        } catch (Exception err) {
+            LOG.error("Error converting user to MDSAL object", err);
+            return null;
+        }
+    }
+
+    public static User toIDMUser(
+            org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User user) {
+        try {
+            return (User) fromMDSALObject(user, User.class);
+        } catch (Exception err) {
+            LOG.error("Error converting user from MDSAL to IDM object", err);
+            return null;
+        }
+    }
+
+    // Convert Grant
+    public static org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant toMDSALGrant(
+            Grant grant) {
+        try {
+            return (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant) toMDSALObject(
+                    grant, GrantBuilder.class);
+        } catch (Exception err) {
+            LOG.error("Error converting grant to MDSAL object", err);
+            return null;
+        }
+    }
+
+    public static Grant toIDMGrant(
+            org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant grant) {
+        try {
+            return (Grant) fromMDSALObject(grant, Grant.class);
+        } catch (Exception err) {
+            LOG.error("Error converting grant from MDSAL to IDM object", err);
+            return null;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMStore.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMStore.java
new file mode 100644
index 00000000..69bc1d52
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/IDMStore.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import java.util.List;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+
+/**
+ * @author Sharon Aicler - saichler@cisco.com
+ *
+ */
+public class IDMStore implements IIDMStore {
+    private final IDMMDSALStore mdsalStore;
+
+    public IDMStore(IDMMDSALStore mdsalStore) {
+        this.mdsalStore = mdsalStore;
+    }
+
+    @Override
+    public Domain writeDomain(Domain domain) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMDomain(mdsalStore.writeDomain(IDMObject2MDSAL.toMDSALDomain(domain)));
+    }
+
+    @Override
+    public Domain readDomain(String domainid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMDomain(mdsalStore.readDomain(domainid));
+    }
+
+    @Override
+    public Domain deleteDomain(String domainid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMDomain(mdsalStore.deleteDomain(domainid));
+    }
+
+    @Override
+    public Domain updateDomain(Domain domain) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMDomain(mdsalStore.updateDomain(IDMObject2MDSAL.toMDSALDomain(domain)));
+    }
+
+    @Override
+    public Domains getDomains() throws IDMStoreException {
+        Domains domains = new Domains();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain> mdSalDomains = mdsalStore.getAllDomains();
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain d : mdSalDomains) {
+            domains.getDomains().add(IDMObject2MDSAL.toIDMDomain(d));
+        }
+        return domains;
+    }
+
+    @Override
+    public Role writeRole(Role role) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMRole(mdsalStore.writeRole(IDMObject2MDSAL.toMDSALRole(role)));
+    }
+
+    @Override
+    public Role readRole(String roleid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMRole(mdsalStore.readRole(roleid));
+    }
+
+    @Override
+    public Role deleteRole(String roleid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMRole(mdsalStore.deleteRole(roleid));
+    }
+
+    @Override
+    public Role updateRole(Role role) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMRole(mdsalStore.writeRole(IDMObject2MDSAL.toMDSALRole(role)));
+    }
+
+    @Override
+    public User writeUser(User user) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMUser(mdsalStore.writeUser(IDMObject2MDSAL.toMDSALUser(user)));
+    }
+
+    @Override
+    public User readUser(String userid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMUser(mdsalStore.readUser(userid));
+    }
+
+    @Override
+    public User deleteUser(String userid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMUser(mdsalStore.deleteUser(userid));
+    }
+
+    @Override
+    public User updateUser(User user) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMUser(mdsalStore.writeUser(IDMObject2MDSAL.toMDSALUser(user)));
+    }
+
+    @Override
+    public Grant writeGrant(Grant grant) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMGrant(mdsalStore.writeGrant(IDMObject2MDSAL.toMDSALGrant(grant)));
+    }
+
+    @Override
+    public Grant readGrant(String grantid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMGrant(mdsalStore.readGrant(grantid));
+    }
+
+    @Override
+    public Grant deleteGrant(String grantid) throws IDMStoreException {
+        return IDMObject2MDSAL.toIDMGrant(mdsalStore.readGrant(grantid));
+    }
+
+    @Override
+    public Roles getRoles() throws IDMStoreException {
+        Roles roles = new Roles();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role> mdSalRoles = mdsalStore.getAllRoles();
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role r : mdSalRoles) {
+            roles.getRoles().add(IDMObject2MDSAL.toIDMRole(r));
+        }
+        return roles;
+    }
+
+    @Override
+    public Users getUsers() throws IDMStoreException {
+        Users users = new Users();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User> mdSalUsers = mdsalStore.getAllUsers();
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User u : mdSalUsers) {
+            users.getUsers().add(IDMObject2MDSAL.toIDMUser(u));
+        }
+        return users;
+    }
+
+    @Override
+    public Users getUsers(String username, String domain) throws IDMStoreException {
+        Users users = new Users();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User> mdSalUsers = mdsalStore.getAllUsers();
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User u : mdSalUsers) {
+            if (u.getDomainid().equals(domain) && u.getName().equals(username)) {
+                users.getUsers().add(IDMObject2MDSAL.toIDMUser(u));
+            }
+        }
+        return users;
+    }
+
+    @Override
+    public Grants getGrants(String domainid, String userid) throws IDMStoreException {
+        Grants grants = new Grants();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant> mdSalGrants = mdsalStore.getAllGrants();
+        String currentGrantUserId, currentGrantDomainId;
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant g : mdSalGrants) {
+            currentGrantUserId = g.getUserid();
+            currentGrantDomainId = g.getDomainid();
+            if (currentGrantUserId.equals(userid) && currentGrantDomainId.equals(domainid)) {
+                grants.getGrants().add(IDMObject2MDSAL.toIDMGrant(g));
+            }
+        }
+        return grants;
+    }
+
+    @Override
+    public Grants getGrants(String userid) throws IDMStoreException {
+        Grants grants = new Grants();
+        List<org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant> mdSalGrants = mdsalStore.getAllGrants();
+        for (org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant g : mdSalGrants) {
+            if (g.getUserid().equals(userid)) {
+                grants.getGrants().add(IDMObject2MDSAL.toIDMGrant(g));
+            }
+        }
+        return grants;
+    }
+
+    @Override
+    public Grant readGrant(String domainid, String userid, String roleid) throws IDMStoreException {
+        return readGrant(IDMStoreUtil.createGrantid(userid, domainid, roleid));
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtil.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtil.java
new file mode 100644
index 00000000..6ef58109
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtil.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store.util;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.TokenCacheTimes;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.Tokencache;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenList;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenListBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenListKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokens;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokensBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokensKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.Claims;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.ClaimsBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.ClaimsKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class AuthNStoreUtil {
+
+    public static InstanceIdentifier<Claims> createInstIdentifierForTokencache(String token) {
+        if (token == null || token.length() == 0)
+            return null;
+
+        InstanceIdentifier<Claims> claims_iid = InstanceIdentifier.builder(Tokencache.class)
+                                                                  .child(Claims.class,
+                                                                          new ClaimsKey(token))
+                                                                  .build();
+        return claims_iid;
+    }
+
+    public static InstanceIdentifier<UserTokens> createInstIdentifierUserTokens(String userId,
+            String token) {
+        if (userId == null || userId.length() == 0 || token == null || token.length() == 0)
+            return null;
+
+        InstanceIdentifier<UserTokens> userTokens_iid = InstanceIdentifier.builder(
+                TokenCacheTimes.class)
+                                                                          .child(TokenList.class,
+                                                                                  new TokenListKey(
+                                                                                          userId))
+                                                                          .child(UserTokens.class,
+                                                                                  new UserTokensKey(
+                                                                                          token))
+                                                                          .build();
+        return userTokens_iid;
+    }
+
+    public static Claims createClaimsRecord(String token, Authentication auth) {
+        if (auth == null || token == null || token.length() == 0)
+            return null;
+
+        ClaimsKey claimsKey = new ClaimsKey(token);
+        ClaimsBuilder claimsBuilder = new ClaimsBuilder();
+        claimsBuilder.setClientId(auth.clientId());
+        claimsBuilder.setDomain(auth.domain());
+        claimsBuilder.setKey(claimsKey);
+        List<String> roles = new ArrayList<String>();
+        roles.addAll(auth.roles());
+        claimsBuilder.setRoles(roles);
+        claimsBuilder.setToken(token);
+        claimsBuilder.setUser(auth.user());
+        claimsBuilder.setUserId(auth.userId());
+        return claimsBuilder.build();
+    }
+
+    public static UserTokens createUserTokens(String token, Long expiration) {
+        if (expiration == null || token == null || token.length() == 0)
+            return null;
+
+        UserTokensBuilder userTokensBuilder = new UserTokensBuilder();
+        userTokensBuilder.setTokenid(token);
+        BigInteger timestamp = BigInteger.valueOf(System.currentTimeMillis());
+        userTokensBuilder.setTimestamp(timestamp);
+        userTokensBuilder.setExpiration(expiration);
+        userTokensBuilder.setKey(new UserTokensKey(token));
+        return userTokensBuilder.build();
+    }
+
+    public static TokenList createTokenList(UserTokens tokens, String userId) {
+        if (tokens == null || userId == null || userId.length() == 0)
+            return null;
+
+        TokenListBuilder tokenListBuilder = new TokenListBuilder();
+        tokenListBuilder.setUserId(userId);
+        tokenListBuilder.setKey(new TokenListKey(userId));
+        List<UserTokens> userTokens = new ArrayList<UserTokens>();
+        userTokens.add(tokens);
+        tokenListBuilder.setUserTokens(userTokens);
+        return tokenListBuilder.build();
+    }
+
+    public static Authentication convertClaimToAuthentication(final Claims claims, Long expiration) {
+        if (claims == null)
+            return null;
+
+        Claim claim = new Claim() {
+            @Override
+            public String clientId() {
+                return claims.getClientId();
+            }
+
+            @Override
+            public String userId() {
+                return claims.getUserId();
+            }
+
+            @Override
+            public String user() {
+                return claims.getUser();
+            }
+
+            @Override
+            public String domain() {
+                return claims.getDomain();
+            }
+
+            @Override
+            public Set<String> roles() {
+                return new HashSet<>(claims.getRoles());
+            }
+        };
+        AuthenticationBuilder authBuilder = new AuthenticationBuilder(claim);
+        authBuilder.setExpiration(expiration);
+        return authBuilder.build();
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModule.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModule.java
new file mode 100644
index 00000000..0631170e
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModule.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ */
+
+package org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.rev141031;
+
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.TokenStore;
+import org.opendaylight.aaa.authn.mdsal.store.AuthNStore;
+import org.opendaylight.aaa.authn.mdsal.store.IDMMDSALStore;
+import org.opendaylight.aaa.authn.mdsal.store.IDMStore;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class AuthNStoreModule
+        extends
+        org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.rev141031.AbstractAuthNStoreModule {
+    private BundleContext bundleContext;
+
+    public AuthNStoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public AuthNStoreModule(
+            org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.rev141031.AuthNStoreModule oldModule,
+            java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+
+        DataBroker dataBrokerService = getDataBrokerDependency();
+        final AuthNStore authNStore = new AuthNStore(dataBrokerService, getPassword());
+        final IDMMDSALStore mdsalStore = new IDMMDSALStore(dataBrokerService);
+        final IDMStore idmStore = new IDMStore(mdsalStore);
+
+        authNStore.setTimeToLive(getTimeToLive());
+
+        // Register the MD-SAL Token store with OSGI
+        final ServiceRegistration<?> serviceRegistration = bundleContext.registerService(
+                TokenStore.class.getName(), authNStore, null);
+        final ServiceRegistration<?> idmServiceRegistration = bundleContext.registerService(
+                IIDMStore.class.getName(), idmStore, null);
+        final class AutoCloseableStore implements AutoCloseable {
+
+            @Override
+            public void close() throws Exception {
+                serviceRegistration.unregister();
+                idmServiceRegistration.unregister();
+                authNStore.close();
+            }
+        }
+
+        return new AutoCloseableStore();
+
+        // return authNStore;
+
+        // throw new java.lang.UnsupportedOperationException();
+    }
+
+    /**
+     * @param bundleContext
+     */
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    /**
+     * @return the bundleContext
+     */
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModuleFactory.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModuleFactory.java
new file mode 100644
index 00000000..b1e278fa
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/mdsal/store/rev141031/AuthNStoreModuleFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ */
+
+/*
+ * Generated file
+ *
+ * Generated from: yang module name: aaa-authn-mdsal-store-cfg yang module local name: aaa-authn-mdsal-store
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Thu Mar 19 18:06:18 CET 2015
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.rev141031;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class AuthNStoreModuleFactory
+        extends
+        org.opendaylight.yang.gen.v1.config.aaa.authn.mdsal.store.rev141031.AbstractAuthNStoreModuleFactory {
+
+    @Override
+    public AuthNStoreModule instantiateModule(String instanceName,
+            DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        AuthNStoreModule module = super.instantiateModule(instanceName, dependencyResolver,
+                bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public AuthNStoreModule instantiateModule(String instanceName,
+            DependencyResolver dependencyResolver, AuthNStoreModule oldModule,
+            AutoCloseable oldInstance, BundleContext bundleContext) {
+        AuthNStoreModule module = super.instantiateModule(instanceName, dependencyResolver,
+                oldModule, oldInstance, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/yang/aaa-authn-mdsal-store-cfg.yang b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/yang/aaa-authn-mdsal-store-cfg.yang
new file mode 100644
index 00000000..eac344b8
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/main/yang/aaa-authn-mdsal-store-cfg.yang
@@ -0,0 +1,77 @@
+module aaa-authn-mdsal-store-cfg {
+
+    yang-version 1;
+    namespace "config:aaa:authn:mdsal:store";
+    prefix "aaa-authn-store-cfg";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+    import opendaylight-md-sal-dom {prefix dom;}
+
+
+    description
+        "This module contains the base YANG definitions for
+        AuthN MD-SAL backed data cache implementation.";
+
+    revision "2014-10-31" {
+        description
+            "Initial revision.";
+    }
+
+    identity token-store-service{
+           base config:service-type;
+           config:java-class "org.opendaylight.aaa.api.TokenStore";
+    }
+
+
+    // This is the definition of the service implementation as a module identity.
+    identity aaa-authn-mdsal-store {
+            base config:module-type;
+            // Specifies the prefix for generated java classes.
+            config:java-name-prefix AuthNStore;
+            config:provided-service token-store-service;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+
+    augment "/config:modules/config:module/config:configuration" {
+        case aaa-authn-mdsal-store {
+            when "/config:modules/config:module/config:type = 'aaa-authn-mdsal-store'";
+
+    //Defines reference to the Bundle context and MD-SAL data broker
+            container dom-broker {
+               uses config:service-ref {
+                   refine type {
+                       mandatory true;
+                       config:required-identity dom:dom-broker-osgi-registry;
+                   }
+               }
+           }
+           container data-broker {
+               uses config:service-ref {
+                   refine type {
+                       mandatory true;
+                       config:required-identity mdsal:binding-async-data-broker;
+
+                   }
+               }
+           }
+
+           leaf timeToLive {
+             description "Time to live for tokens. When set to 0 = never expire";
+             type uint64;
+             default 360000;
+           }
+           leaf timeToWait {
+             description "Time to wait for future from data store. 10 by default = never expire";
+             type uint16;
+             default 10;
+           }
+           leaf password {
+             description "Encryption password for the Store";
+             type string;
+           }
+       }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataBrokerReadMocker.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataBrokerReadMocker.java
new file mode 100644
index 00000000..f821cf16
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataBrokerReadMocker.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DataBrokerReadMocker implements InvocationHandler {
+    private Map<Method, List<StubContainer>> stubs = new HashMap<Method, List<StubContainer>>();
+    private Class<?> mokingClass = null;
+
+    @Override
+    public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
+        List<StubContainer> stList = stubs.get(arg1);
+        if (stList != null) {
+            for (StubContainer sc : stList) {
+                if (sc.fitGeneric(arg2)) {
+                    return sc.returnObject;
+                }
+            }
+        }
+        return null;
+    }
+
+    public DataBrokerReadMocker(Class<?> cls) {
+        this.mokingClass = cls;
+    }
+
+    public static Object addMock(Class<?> cls) {
+        return Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls },
+                new DataBrokerReadMocker(cls));
+    }
+
+    public static DataBrokerReadMocker getMocker(Object o) {
+        return (DataBrokerReadMocker) Proxy.getInvocationHandler(o);
+    }
+
+    public static Method findMethod(Class<?> cls, String name, Object args[]) {
+        Method methods[] = cls.getMethods();
+        for (Method m : methods) {
+            if (m.getName().equals(name)) {
+                if ((m.getParameterTypes() == null || m.getParameterTypes().length == 0)
+                        && args == null) {
+                    return m;
+                }
+                boolean match = true;
+                for (int i = 0; i < m.getParameterTypes().length; i++) {
+                    if (!m.getParameterTypes()[i].isAssignableFrom(args[i].getClass())) {
+                        match = false;
+                    }
+                }
+                if (match)
+                    return m;
+            }
+        }
+        return null;
+    }
+
+    public void addWhen(String methodName, Object[] args, Object returnThis)
+            throws NoSuchMethodException, SecurityException {
+        Method m = findMethod(this.mokingClass, methodName, args);
+        if (m == null)
+            throw new IllegalArgumentException("Unable to find method");
+        StubContainer sc = new StubContainer(args, returnThis);
+        List<StubContainer> lst = stubs.get(m);
+        if (lst == null) {
+            lst = new ArrayList<>();
+        }
+        lst.add(sc);
+        stubs.put(m, lst);
+    }
+
+    private class StubContainer {
+        private Class<?>[] parameters = null;
+        private Class<?>[] generics = null;
+        private Object args[] = null;
+        private Object returnObject;
+
+        public StubContainer(Object[] _args, Object ret) {
+            this.args = _args;
+            this.returnObject = ret;
+        }
+
+        public boolean fitGeneric(Object _args[]) {
+            if (args == null && _args != null)
+                return false;
+            if (args != null && _args == null)
+                return false;
+            if (args == null && _args == null)
+                return true;
+            if (args.length != _args.length)
+                return false;
+            for (int i = 0; i < args.length; i++) {
+                if (!args[i].equals(_args[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypterTest.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypterTest.java
new file mode 100644
index 00000000..eec69bc0
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/DataEncrypterTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.xml.bind.DatatypeConverter;
+import org.junit.Test;
+
+public class DataEncrypterTest {
+
+    @Test
+    public void testEncrypt() {
+        DataEncrypter dataEncry = new DataEncrypter("foo_key_test");
+        String token = "foo_token_test";
+        String eToken = dataEncry.encrypt(token);
+        // check for decryption result
+        String returnToken = dataEncry.decrypt(eToken);
+        String tokenBase64 = DatatypeConverter.printBase64Binary(token.getBytes());
+        assertEquals(tokenBase64, returnToken);
+    }
+
+    @Test
+    public void testDecrypt() {
+        DataEncrypter dataEncry = new DataEncrypter("foo_key_test");
+        String eToken = "foo_etoken_test";
+        assertEquals(dataEncry.decrypt(""), null);
+        // check for encryption Tag
+        assertEquals(eToken, dataEncry.decrypt(eToken));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTest.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTest.java
new file mode 100644
index 00000000..f376dd5f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.SHA256Calculator;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User;
+
+public class IDMStoreTest {
+
+    @Test
+    public void testWriteDomain() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoFordomain();
+        Domain domain = testedObject.writeDomain(util.domain);
+        Assert.assertNotNull(domain);
+        Assert.assertEquals(domain.getDomainid(), util.domain.getName());
+    }
+
+    @Test
+    public void testReadDomain() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoFordomain();
+        Domain domain = testedObject.readDomain(util.domain.getDomainid());
+        Assert.assertNotNull(domain);
+        Assert.assertEquals(domain, util.domain);
+    }
+
+    @Test
+    public void testDeleteDomain() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoFordomain();
+        Domain domain = testedObject.deleteDomain(util.domain.getDomainid());
+        Assert.assertEquals(domain, util.domain);
+    }
+
+    @Test
+    public void testUpdateDomain() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoFordomain();
+        Domain domain = testedObject.updateDomain(util.domain);
+        Assert.assertEquals(domain, util.domain);
+    }
+
+    @Test
+    public void testWriteRole() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForrole();
+        util.addMokitoFordomain();
+        Role role = testedObject.writeRole(util.role);
+        Assert.assertNotNull(role);
+        Assert.assertEquals(role.getRoleid(),
+                IDMStoreUtil.createRoleid(role.getName(), role.getDomainid()));
+    }
+
+    @Test
+    public void testReadRole() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForrole();
+        Role role = testedObject.readRole(util.role.getRoleid());
+        Assert.assertNotNull(role);
+        Assert.assertEquals(role, util.role);
+    }
+
+    @Test
+    public void testDeleteRole() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForrole();
+        Role role = testedObject.deleteRole(util.role.getRoleid());
+        Assert.assertNotNull(role);
+        Assert.assertEquals(role, util.role);
+    }
+
+    @Test
+    public void testUpdateRole() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForrole();
+        Role role = testedObject.updateRole(util.role);
+        Assert.assertNotNull(role);
+        Assert.assertEquals(role, util.role);
+    }
+
+    @Test
+    public void testWriteUser() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForuser();
+        User user = testedObject.writeUser(util.user);
+        Assert.assertNotNull(user);
+        Assert.assertEquals(user.getUserid(),
+                IDMStoreUtil.createUserid(user.getName(), util.user.getDomainid()));
+    }
+
+    @Test
+    public void testReadUser() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForuser();
+        User user = testedObject.readUser(util.user.getUserid());
+        Assert.assertNotNull(user);
+        Assert.assertEquals(user, util.user);
+    }
+
+    @Test
+    public void testDeleteUser() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForuser();
+        User user = testedObject.deleteUser(util.user.getUserid());
+        Assert.assertNotNull(user);
+        Assert.assertEquals(user, util.user);
+    }
+
+    @Test
+    public void testUpdateUser() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForuser();
+        User user = testedObject.updateUser(util.user);
+        Assert.assertNotNull(user);
+        Assert.assertEquals(user.getPassword(),
+                SHA256Calculator.getSHA256(util.user.getPassword(), util.user.getSalt()));
+    }
+
+    @Test
+    public void testWriteGrant() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoFordomain();
+        util.addMokitoForrole();
+        util.addMokitoForuser();
+        util.addMokitoForgrant();
+        Grant grant = testedObject.writeGrant(util.grant);
+        Assert.assertNotNull(grant);
+    }
+
+    @Test
+    public void testReadGrant() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForgrant();
+        Grant grant = testedObject.readGrant(util.grant.getGrantid());
+        Assert.assertNotNull(grant);
+        Assert.assertEquals(grant, util.grant);
+    }
+
+    @Test
+    public void testDeleteGrant() throws Exception {
+        IDMStoreTestUtil util = new IDMStoreTestUtil();
+        IDMMDSALStore testedObject = new IDMMDSALStore(util.dataBroker);
+        util.addMokitoForgrant();
+        Grant grant = testedObject.deleteGrant(util.grant.getGrantid());
+        Assert.assertNotNull(grant);
+        Assert.assertEquals(grant, util.grant);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTestUtil.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTestUtil.java
new file mode 100644
index 00000000..39eeadb4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/IDMStoreTestUtil.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.Authentication;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.DomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.DomainKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.GrantBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.GrantKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.RoleBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.RoleKey;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.UserBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.UserKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class IDMStoreTestUtil {
+    /* DataBroker mocked with Mokito */
+    protected static DataBroker dataBroker = mock(DataBroker.class);
+    protected static WriteTransaction wrt = mock(WriteTransaction.class);
+    protected static ReadOnlyTransaction rot = null;
+
+    static {
+        rot = (ReadOnlyTransaction) DataBrokerReadMocker.addMock(ReadOnlyTransaction.class);
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(rot);
+        when(dataBroker.newWriteOnlyTransaction()).thenReturn(wrt);
+    }
+
+    /* Domain Data Object Instance */
+    public Domain domain = createdomain();
+
+    /* Domain create Method */
+    public Domain createdomain() {
+        /* Start of Domain builder */
+        DomainBuilder domainbuilder = new DomainBuilder();
+        domainbuilder.setName("SETNAME");
+        domainbuilder.setDomainid("SETNAME");
+        domainbuilder.setKey(new DomainKey("SETNAME"));
+        domainbuilder.setDescription("SETDESCRIPTION");
+        domainbuilder.setEnabled(true);
+        /* End of Domain builder */
+        return domainbuilder.build();
+    }
+
+    /* Role Data Object Instance */
+    public Role role = createrole();
+
+    /* Role create Method */
+    public Role createrole() {
+        /* Start of Role builder */
+        RoleBuilder rolebuilder = new RoleBuilder();
+        rolebuilder.setRoleid("SETNAME@SETNAME");
+        rolebuilder.setName("SETNAME");
+        rolebuilder.setKey(new RoleKey(rolebuilder.getRoleid()));
+        rolebuilder.setDomainid(createdomain().getDomainid());
+        rolebuilder.setDescription("SETDESCRIPTION");
+        /* End of Role builder */
+        return rolebuilder.build();
+    }
+
+    /* User Data Object Instance */
+    public User user = createuser();
+
+    /* User create Method */
+    public User createuser() {
+        /* Start of User builder */
+        UserBuilder userbuilder = new UserBuilder();
+        userbuilder.setUserid("SETNAME@SETNAME");
+        userbuilder.setName("SETNAME");
+        userbuilder.setKey(new UserKey(userbuilder.getUserid()));
+        userbuilder.setDomainid(createdomain().getDomainid());
+        userbuilder.setEmail("SETEMAIL");
+        userbuilder.setPassword("SETPASSWORD");
+        userbuilder.setSalt("SETSALT");
+        userbuilder.setEnabled(true);
+        userbuilder.setDescription("SETDESCRIPTION");
+        /* End of User builder */
+        return userbuilder.build();
+    }
+
+    /* Grant Data Object Instance */
+    public Grant grant = creategrant();
+
+    /* Grant create Method */
+    public Grant creategrant() {
+        /* Start of Grant builder */
+        GrantBuilder grantbuilder = new GrantBuilder();
+        grantbuilder.setDomainid(createdomain().getDomainid());
+        grantbuilder.setRoleid(createrole().getRoleid());
+        grantbuilder.setUserid(createuser().getUserid());
+        grantbuilder.setGrantid(IDMStoreUtil.createGrantid(grantbuilder.getUserid(),
+                grantbuilder.getDomainid(), grantbuilder.getRoleid()));
+        grantbuilder.setKey(new GrantKey(grantbuilder.getGrantid()));
+        /* End of Grant builder */
+        return grantbuilder.build();
+    }
+
+    /* InstanceIdentifier for Grant instance grant */
+    public InstanceIdentifier<Grant> grantID = InstanceIdentifier.create(Authentication.class)
+                                                                 .child(Grant.class,
+                                                                         creategrant().getKey());
+
+    /* Mokito DataBroker method for grant Data Object */
+    public void addMokitoForgrant() throws NoSuchMethodException, SecurityException, InterruptedException, ExecutionException {
+        CheckedFuture<Optional<Grant>, ReadFailedException> read = mock(CheckedFuture.class);
+        DataBrokerReadMocker.getMocker(rot).addWhen("read",
+                new Object[] { LogicalDatastoreType.CONFIGURATION, grantID }, read);
+        Optional<Grant> optional = mock(Optional.class);
+        when(read.get()).thenReturn(optional);
+        when(optional.get()).thenReturn(grant);
+        when(optional.isPresent()).thenReturn(true);
+    }
+
+    /* InstanceIdentifier for Domain instance domain */
+    public InstanceIdentifier<Domain> domainID = InstanceIdentifier.create(Authentication.class)
+                                                                   .child(Domain.class,
+                                                                           new DomainKey(
+                                                                                   new String(
+                                                                                           "SETNAME")));
+
+    /* Mokito DataBroker method for domain Data Object */
+    public void addMokitoFordomain() throws NoSuchMethodException, SecurityException, InterruptedException, ExecutionException {
+        CheckedFuture<Optional<Domain>, ReadFailedException> read = mock(CheckedFuture.class);
+        DataBrokerReadMocker.getMocker(rot).addWhen("read",
+                new Object[] { LogicalDatastoreType.CONFIGURATION, domainID }, read);
+        Optional<Domain> optional = mock(Optional.class);
+        when(read.get()).thenReturn(optional);
+        when(optional.get()).thenReturn(domain);
+        when(optional.isPresent()).thenReturn(true);
+    }
+
+    /* InstanceIdentifier for Role instance role */
+    public InstanceIdentifier<Role> roleID = InstanceIdentifier.create(Authentication.class).child(
+            Role.class, createrole().getKey());
+
+    /* Mokito DataBroker method for role Data Object */
+    public void addMokitoForrole() throws NoSuchMethodException, SecurityException, InterruptedException, ExecutionException {
+        CheckedFuture<Optional<Role>, ReadFailedException> read = mock(CheckedFuture.class);
+        DataBrokerReadMocker.getMocker(rot).addWhen("read",
+                new Object[] { LogicalDatastoreType.CONFIGURATION, roleID }, read);
+        Optional<Role> optional = mock(Optional.class);
+        when(read.get()).thenReturn(optional);
+        when(optional.get()).thenReturn(role);
+        when(optional.isPresent()).thenReturn(true);
+    }
+
+    /* InstanceIdentifier for User instance user */
+    public InstanceIdentifier<User> userID = InstanceIdentifier.create(Authentication.class).child(
+            User.class, createuser().getKey());
+
+    /* Mokito DataBroker method for user Data Object */
+    public void addMokitoForuser() throws NoSuchMethodException, SecurityException, InterruptedException, ExecutionException {
+        CheckedFuture<Optional<User>, ReadFailedException> read = mock(CheckedFuture.class);
+        DataBrokerReadMocker.getMocker(rot).addWhen("read",
+                new Object[] { LogicalDatastoreType.CONFIGURATION, userID }, read);
+        Optional<User> optional = mock(Optional.class);
+        when(read.get()).thenReturn(optional);
+        when(optional.get()).thenReturn(user);
+        when(optional.isPresent()).thenReturn(true);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/MDSALConvertTest.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/MDSALConvertTest.java
new file mode 100644
index 00000000..9b7c9712
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/MDSALConvertTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+
+public class MDSALConvertTest {
+    @Test
+    public void testConvertDomain() {
+        Domain d = new Domain();
+        d.setDescription("hello");
+        d.setDomainid("hello");
+        d.setEnabled(true);
+        d.setName("Hello");
+        org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Domain mdsalDomain = IDMObject2MDSAL.toMDSALDomain(d);
+        Assert.assertNotNull(mdsalDomain);
+        Domain d2 = IDMObject2MDSAL.toIDMDomain(mdsalDomain);
+        Assert.assertNotNull(d2);
+        Assert.assertEquals(d, d2);
+    }
+
+    @Test
+    public void testConvertRole() {
+        Role r = new Role();
+        r.setDescription("hello");
+        r.setRoleid("Hello@hello");
+        r.setName("Hello");
+        r.setDomainid("hello");
+        org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Role mdsalRole = IDMObject2MDSAL.toMDSALRole(r);
+        Assert.assertNotNull(mdsalRole);
+        Role r2 = IDMObject2MDSAL.toIDMRole(mdsalRole);
+        Assert.assertNotNull(r2);
+        Assert.assertEquals(r, r2);
+    }
+
+    @Test
+    public void testConvertUser() {
+        User u = new User();
+        u.setDescription("hello");
+        u.setDomainid("hello");
+        u.setUserid("hello@hello");
+        u.setName("Hello");
+        u.setEmail("email");
+        u.setEnabled(true);
+        u.setPassword("pass");
+        u.setSalt("salt");
+        org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.User mdsalUser = IDMObject2MDSAL.toMDSALUser(u);
+        Assert.assertNotNull(mdsalUser);
+        User u2 = IDMObject2MDSAL.toIDMUser(mdsalUser);
+        Assert.assertNotNull(u2);
+        Assert.assertEquals(u, u2);
+    }
+
+    @Test
+    public void testConvertGrant() {
+        Grant g = new Grant();
+        g.setDomainid("hello");
+        g.setUserid("hello@hello");
+        g.setRoleid("hello@hello");
+        g.setGrantid("hello@hello@Hello");
+        org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.authentication.Grant mdsalGrant = IDMObject2MDSAL.toMDSALGrant(g);
+        Assert.assertNotNull(mdsalGrant);
+        Grant g2 = IDMObject2MDSAL.toIDMGrant(mdsalGrant);
+        Assert.assertNotNull(g2);
+        Assert.assertEquals(g, g2);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtilTest.java b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtilTest.java
new file mode 100644
index 00000000..10c18790
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/aaa-authn-mdsal-store-impl/src/test/java/org/opendaylight/aaa/authn/mdsal/store/util/AuthNStoreUtilTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authn.mdsal.store.util;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokens;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.Claims;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.ClaimsBuilder;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.ClaimsKey;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+public class AuthNStoreUtilTest {
+
+    private String token = "foo_token_test";
+    private String userId = "123";
+    private Long expire = new Long(365);
+    @Mock
+    private Authentication auth;
+    @Mock
+    private UserTokens tokens;
+    @Mock
+    private Claims claims;
+
+    @Test
+    public void testCreateInstIdentifierForTokencache() {
+        assertTrue(AuthNStoreUtil.createInstIdentifierForTokencache("") == null);
+        assertNotNull(AuthNStoreUtil.createInstIdentifierForTokencache(token));
+    }
+
+    @Test
+    public void testCreateInstIdentifierUserTokens() {
+        assertTrue(AuthNStoreUtil.createInstIdentifierUserTokens("", "") == null);
+        assertNotNull(AuthNStoreUtil.createInstIdentifierUserTokens(userId, token));
+    }
+
+    @Test
+    public void testCreateClaimsRecord() {
+        assertTrue(AuthNStoreUtil.createClaimsRecord("", null) == null);
+        assertNotNull(AuthNStoreUtil.createClaimsRecord(token, auth));
+    }
+
+    @Test
+    public void testCreateUserTokens() {
+        assertTrue(AuthNStoreUtil.createUserTokens("", null) == null);
+        assertNotNull(AuthNStoreUtil.createUserTokens(token, expire));
+    }
+
+    @Test
+    public void testCreateTokenList() {
+        assertTrue(AuthNStoreUtil.createTokenList(null, "") == null);
+        assertNotNull(AuthNStoreUtil.createTokenList(tokens, userId));
+    }
+
+    @Test
+    public void testConvertClaimToAuthentication() {
+        ClaimsKey claimsKey = new ClaimsKey(token);
+        ClaimsBuilder claimsBuilder = new ClaimsBuilder();
+        claimsBuilder.setClientId("123");
+        claimsBuilder.setDomain("foo_domain");
+        claimsBuilder.setKey(claimsKey);
+        List<String> roles = new ArrayList<String>();
+        roles.add("foo_role");
+        claimsBuilder.setRoles(roles);
+        claimsBuilder.setToken(token);
+        claimsBuilder.setUser("foo_usr");
+        claimsBuilder.setUserId(userId);
+        Claims fooClaims = claimsBuilder.build();
+
+        assertTrue(AuthNStoreUtil.convertClaimToAuthentication(null, expire) == null);
+        assertNotNull(AuthNStoreUtil.convertClaimToAuthentication(fooClaims, expire));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-mdsal-store/pom.xml b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/pom.xml
new file mode 100644
index 00000000..e5e4f92f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-mdsal-store/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>aaa-authn-mdsal-store</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>aaa-authn-mdsal-api</module>
+        <module>aaa-authn-mdsal-config</module>
+        <module>aaa-authn-mdsal-store-impl</module>
+    </modules>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-sssd/pom.xml b/odl-aaa-moon/aaa/aaa-authn-sssd/pom.xml
new file mode 100644
index 00000000..4dc7eac9
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sssd/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-authn-sssd</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-authn</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-authn-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish</groupId>
+      <artifactId>javax.json</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-authn-idpmapping</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-server</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>com.sun.jersey.jersey-test-framework</groupId>
+      <artifactId>jersey-test-framework-grizzly2</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Activator>org.opendaylight.aaa.sssd.Activator</Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/Activator.java b/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/Activator.java
new file mode 100644
index 00000000..b6d5259f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/Activator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sssd;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.osgi.framework.BundleContext;
+
+public class Activator extends DependencyActivatorBase {
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent().setInterface(new String[] { ClaimAuth.class.getName() }, null)
+                                     .setImplementation(SssdClaimAuth.class));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/SssdClaimAuth.java b/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/SssdClaimAuth.java
new file mode 100644
index 00000000..0ae23b48
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sssd/src/main/java/org/opendaylight/aaa/sssd/SssdClaimAuth.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sssd;
+
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import org.apache.felix.dm.Component;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.opendaylight.aaa.idpmapping.RuleProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An SSSD {@link ClaimAuth} implementation.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+public class SssdClaimAuth implements ClaimAuth {
+    private static final Logger LOG = LoggerFactory.getLogger(SssdClaimAuth.class);
+
+    private static final String DEFAULT_MAPPING_RULES_PATHNAME = "etc/idp_mapping_rules.json";
+    private JsonGeneratorFactory generatorFactory = null;
+    private RuleProcessor ruleProcessor = null;
+
+    // Called by DM when all required dependencies are satisfied.
+    void init(Component c) {
+        LOG.info("Initializing SSSD Plugin");
+        Map<String, Object> properties = new HashMap<String, Object>(1);
+        properties.put(JsonGenerator.PRETTY_PRINTING, true);
+        generatorFactory = Json.createGeneratorFactory(properties);
+
+        String mappingRulesFile = DEFAULT_MAPPING_RULES_PATHNAME;
+        if (mappingRulesFile == null || mappingRulesFile.isEmpty()) {
+            LOG.warn("mapping rules file is not configured, " + "SssdClaimAuth will be disabled");
+            return;
+        }
+
+        Path mappingRulesPath = Paths.get(mappingRulesFile);
+
+        if (!Files.exists(mappingRulesPath)) {
+            LOG.warn(String.format("mapping rules file (%s) "
+                    + "does not exist, SssdClaimAuth will be disabled", mappingRulesFile));
+            return;
+        }
+
+        try {
+            ruleProcessor = new RuleProcessor(mappingRulesPath, null);
+        } catch (Exception e) {
+            LOG.error(String.format("mapping rules file (%s) "
+                    + "could not be loaded, SssdClaimAuth will be disabled. " + "error = %s",
+                    mappingRulesFile, e));
+        }
+    }
+
+    /**
+     * Transform a Map of assertions into a {@link Claim} via a set of mapping
+     * rules.
+     *
+     * A set of mapping rules have been previously loaded. the incoming
+     * assertion is converted to a JSON document and presented to the
+     * {@link RuleProcessor}. If the RuleProcessor can successfully transform
+     * the assertion given the site specific set of rules it will return a Map
+     * of values which will then be used to build a {@link Claim}. The rule
+     * should return one or more of the following which will be used to populate
+     * the Claim.
+     *
+     * <dl>
+     * <dt>ClientId</dt>
+     * <dd>A string.
+     *
+     * @see org.opendaylight.aaa.api.Claim#clientId() </dd>
+     *
+     *      <dt>UserId</dt> <dd>A string.
+     * @see org.opendaylight.aaa.api.Claim#userId() </dd>
+     *
+     *      <dt>User</dt> <dd>A string.
+     * @see org.opendaylight.aaa.api.Claim#user() </dd>
+     *
+     *      <dt>Domain</dt> <dd>A string.
+     * @see org.opendaylight.aaa.api.Claim#domain() </dd>
+     *
+     *      <dt>Roles</dt> <dd>An array of strings.
+     * @see org.opendaylight.aaa.api.Claim#roles() </dd>
+     *
+     *      </dl>
+     *
+     * @param assertion
+     *            A Map of name/value assertions provided by an external IdP
+     * @return A {@link Claim} if successful, null otherwise.
+     */
+
+    @Override
+    public Claim transform(Map<String, Object> assertion) {
+        String assertionJson;
+        Map<String, Object> mapped;
+        assertionJson = claimToJson(assertion);
+
+        if (ruleProcessor == null) {
+            LOG.debug("ruleProcessor not configured");
+            return null;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("assertionJson=\n{}", assertionJson);
+        }
+
+        mapped = ruleProcessor.process(assertionJson);
+        if (mapped == null) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("RuleProcessor returned null");
+            }
+            return null;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("RuleProcessor returned: {}", mapped);
+        }
+
+        ClaimBuilder cb = new ClaimBuilder();
+        if (mapped.containsKey("ClientId")) {
+            cb.setClientId((String) mapped.get("ClientId"));
+        }
+        if (mapped.containsKey("UserId")) {
+            cb.setUserId((String) mapped.get("UserId"));
+        }
+        if (mapped.containsKey("User")) {
+            cb.setUser((String) mapped.get("User"));
+        }
+        if (mapped.containsKey("Domain")) {
+            cb.setDomain((String) mapped.get("Domain"));
+        }
+        if (mapped.containsKey("Roles")) {
+            @SuppressWarnings("unchecked")
+            List<String> roles = (List<String>) mapped.get("roles");
+            for (String role : roles) {
+                cb.addRole(role);
+            }
+        }
+        Claim claim = cb.build();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("returns claim = {}", claim.toString());
+        }
+
+        return claim;
+    }
+
+    /**
+     * Convert a Claim Map into a JSON object.
+     *
+     * Given a Map of name/value pairs convert it into a JSON object and return
+     * it as a string. This is not a general purpose routine used to convert any
+     * Map into JSON because a claim has the restriction that each value must be
+     * a scalar and those scalars are restricted to the following types:
+     *
+     * <ul>
+     * <li>String</li>
+     * <li>Integer</li>
+     * <li>Long</li>
+     * <li>Double</li>
+     * <li>Boolean</li>
+     * <li>null</li>
+     * </ul>
+     *
+     * See also {@link ClaimAuth}.
+     *
+     * @param claim
+     *            The Map containing assertion claims to be converted into a
+     *            JSON assertion document.
+     * @return A string formatted as a JSON object.
+     */
+
+    public String claimToJson(Map<String, Object> claim) {
+        StringWriter stringWriter = new StringWriter();
+        JsonGenerator generator = generatorFactory.createGenerator(stringWriter);
+
+        generator.writeStartObject();
+        for (Map.Entry<String, Object> entry : claim.entrySet()) {
+            String name = entry.getKey();
+            Object value = entry.getValue();
+
+            if (value instanceof String) {
+                generator.write(name, (String) value);
+            } else if (value instanceof Integer) {
+                generator.write(name, ((Integer) value).intValue());
+            } else if (value instanceof Long) {
+                generator.write(name, ((Long) value).longValue());
+            } else if (value instanceof Double) {
+                generator.write(name, ((Double) value).doubleValue());
+            } else if (value instanceof Boolean) {
+                generator.write(name, ((Boolean) value).booleanValue());
+            } else if (value == null) {
+                generator.write(name, JsonValue.NULL);
+            } else {
+                LOG.warn(String.format("ignoring claim unsupported value type "
+                        + "entry %s has type %s", name, value.getClass().getSimpleName()));
+            }
+        }
+        generator.writeEnd();
+        generator.close();
+        return stringWriter.toString();
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/pom.xml b/odl-aaa-moon/aaa/aaa-authn-store/pom.xml
new file mode 100644
index 00000000..01fdf252
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-store</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.aaa.store.Activator</Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/tokens.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java b/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java
new file mode 100644
index 00000000..f3299723
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import java.util.Dictionary;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * An activator for the default datastore implementation of {@link TokenStore}.
+ *
+ * @author liemmn
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static final String TOKEN_PID = "org.opendaylight.aaa.tokens";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        DefaultTokenStore ts = new DefaultTokenStore();
+        manager.add(createComponent().setInterface(new String[] { TokenStore.class.getName() },
+                null).setImplementation(ts));
+        context.registerService(ManagedService.class.getName(), ts,
+                addPid(DefaultTokenStore.defaults));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+    private Dictionary<String, ?> addPid(Dictionary<String, String> dict) {
+        dict.put(Constants.SERVICE_PID, TOKEN_PID);
+        return dict;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java b/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java
new file mode 100644
index 00000000..df65be32
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.management.MBeanServer;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.management.ManagementService;
+import org.apache.felix.dm.Component;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A default token store for STS.
+ *
+ * @author liemmn
+ *
+ */
+public class DefaultTokenStore implements TokenStore, ManagedService {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenStore.class);
+    private static final String TOKEN_STORE_CONFIG_ERR = "Token store configuration error";
+
+    private static final String TOKEN_CACHE_MANAGER = "org.opendaylight.aaa";
+    private static final String TOKEN_CACHE = "tokens";
+    private static final String EHCACHE_XML = "etc/ehcache.xml";
+
+    static final String MAX_CACHED_MEMORY = "maxCachedTokensInMemory";
+    static final String MAX_CACHED_DISK = "maxCachedTokensOnDisk";
+    static final String SECS_TO_LIVE = "secondsToLive";
+    static final String SECS_TO_IDLE = "secondsToIdle";
+
+    // Defaults (needed only for non-Karaf deployments)
+    static final Dictionary<String, String> defaults = new Hashtable<>();
+    static {
+        defaults.put(MAX_CACHED_MEMORY, Long.toString(10000));
+        defaults.put(MAX_CACHED_DISK, Long.toString(1000000));
+        defaults.put(SECS_TO_IDLE, Long.toString(3600));
+        defaults.put(SECS_TO_LIVE, Long.toString(3600));
+    }
+
+    // Token cache lock
+    private static final ReentrantLock cacheLock = new ReentrantLock();
+
+    // Token cache
+    private Cache tokens;
+
+    // This should be a singleton
+    DefaultTokenStore() {
+    }
+
+    // Called by DM when all required dependencies are satisfied.
+    void init(Component c) {
+        File ehcache = new File(EHCACHE_XML);
+        CacheManager cm;
+        if (ehcache.exists()) {
+            cm = CacheManager.create(ehcache.getAbsolutePath());
+            tokens = cm.getCache(TOKEN_CACHE);
+            LOG.info("Initialized token store with custom cache config");
+        } else {
+            cm = CacheManager.getInstance();
+            tokens = new Cache(
+                    new CacheConfiguration(TOKEN_CACHE,
+                            Integer.parseInt(defaults.get(MAX_CACHED_MEMORY))).maxEntriesLocalDisk(
+                            Integer.parseInt(defaults.get(MAX_CACHED_DISK)))
+                                                                              .timeToLiveSeconds(
+                                                                                      Long.parseLong(defaults.get(SECS_TO_LIVE)))
+                                                                              .timeToIdleSeconds(
+                                                                                      Long.parseLong(defaults.get(SECS_TO_IDLE))));
+            cm.addCache(tokens);
+            LOG.info("Initialized token store with default cache config");
+        }
+        cm.setName(TOKEN_CACHE_MANAGER);
+
+        // JMX for cache management
+        MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+        ManagementService.registerMBeans(cm, mBeanServer, false, false, false, true);
+    }
+
+    // Called on shutdown
+    void destroy() {
+        LOG.info("Shutting down token store...");
+        CacheManager.getInstance().shutdown();
+    }
+
+    @Override
+    public Authentication get(String token) {
+        Element elem = tokens.get(token);
+        return (Authentication) ((elem != null) ? elem.getObjectValue() : null);
+    }
+
+    @Override
+    public void put(String token, Authentication auth) {
+        tokens.put(new Element(token, auth));
+    }
+
+    @Override
+    public boolean delete(String token) {
+        return tokens.remove(token);
+    }
+
+    @Override
+    public long tokenExpiration() {
+        return tokens.getCacheConfiguration().getTimeToLiveSeconds();
+    }
+
+    @Override
+    public void updated(@SuppressWarnings("rawtypes") Dictionary props)
+            throws ConfigurationException {
+        LOG.info("Updating token store configuration...");
+        if (props == null) {
+            // Someone deleted the configuration, use defaults
+            props = defaults;
+        }
+        reconfig(props);
+    }
+
+    // Refresh cache configuration...
+    private void reconfig(@SuppressWarnings("rawtypes") Dictionary props)
+            throws ConfigurationException {
+        cacheLock.lock();
+        try {
+            long secsToIdle = Long.parseLong(props.get(SECS_TO_IDLE).toString());
+            long secsToLive = Long.parseLong(props.get(SECS_TO_LIVE).toString());
+            int maxMem = Integer.parseInt(props.get(MAX_CACHED_MEMORY).toString());
+            int maxDisk = Integer.parseInt(props.get(MAX_CACHED_DISK).toString());
+            CacheConfiguration config = tokens.getCacheConfiguration();
+            config.setTimeToIdleSeconds(secsToIdle);
+            config.setTimeToLiveSeconds(secsToLive);
+            config.maxEntriesLocalHeap(maxMem);
+            config.maxEntriesLocalDisk(maxDisk);
+        } catch (Throwable t) {
+            throw new ConfigurationException(null, TOKEN_STORE_CONFIG_ERR, t);
+        } finally {
+            cacheLock.unlock();
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 00000000..b88d5c10
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,14 @@
+org.opendaylight.aaa.tokens.name = Opendaylight AAA Token Configuration
+org.opendaylight.aaa.tokens.description = Configuration for AAA tokens
+org.opendaylight.aaa.tokens.maxCachedTokensInMemory.name = Memory Configuration
+org.opendaylight.aaa.tokens.maxCachedTokensInMemory.description = Maximum number of \
+tokens in memory
+org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.name = Disk Configuration
+org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.description = Maximum number of \
+tokens in memory
+org.opendaylight.aaa.tokens.secondsToLive.name = Token Expiration
+org.opendaylight.aaa.tokens.secondsToLive.description = Maximum number of \
+seconds a token can exist regardless of use.  Zero (0) means never expires.
+org.opendaylight.aaa.tokens.secondsToIdle.name = Unused Token Expiration
+org.opendaylight.aaa.tokens.secondsToIdle.description = Maximum number of \
+seconds a token can exist without being accessed.  Zero (0) means never expires.
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml
new file mode 100644
index 00000000..d04874f4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
+    localization="OSGI-INF/metatype/metatype">
+    <OCD id="org.opendaylight.aaa.tokens" name="%org.opendaylight.aaa.tokens.name"
+        description="%org.opendaylight.aaa.tokens.description">
+        <AD id="maxCachedTokensInMemory" type="Long" default="10000"
+            name="%org.opendaylight.aaa.tokens.maxCachedTokensInMemory.name"
+            description="%org.opendaylight.aaa.tokens.maxCachedTokensInMemory.description" />
+        <AD id="maxCachedTokensOnDisk" type="Long" default="1000000"
+            name="%org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.name"
+            description="%org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.description" />
+        <AD id="secondsToLive" type="Long" default="3600"
+            name="%org.opendaylight.aaa.tokens.secondsToLive.name"
+            description="%org.opendaylight.aaa.tokens.secondsToLive.description" />
+        <AD id="secondsToIdle" type="Long" default="3600"
+            name="%org.opendaylight.aaa.tokens.secondsToIdle.name"
+            description="%org.opendaylight.aaa.tokens.secondsToIdle.description" />
+    </OCD>
+    <Designate pid="org.opendaylight.aaa.tokens">
+        <Object ocdref="org.opendaylight.aaa.tokens" />
+    </Designate>
+</metatype:MetaData>
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/tokens.cfg b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/tokens.cfg
new file mode 100644
index 00000000..d3dda90e
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/main/resources/tokens.cfg
@@ -0,0 +1,4 @@
+maxCachedTokensInMemory=10000
+maxCachedTokensOnDisk=1000000
+secondsToLive=3600
+secondsToIdle=3600
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java b/odl-aaa-moon/aaa/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java
new file mode 100644
index 00000000..e5c837bf
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.aaa.store.DefaultTokenStore.MAX_CACHED_DISK;
+import static org.opendaylight.aaa.store.DefaultTokenStore.MAX_CACHED_MEMORY;
+import static org.opendaylight.aaa.store.DefaultTokenStore.SECS_TO_IDLE;
+import static org.opendaylight.aaa.store.DefaultTokenStore.SECS_TO_LIVE;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import org.apache.felix.dm.Component;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.osgi.service.cm.ConfigurationException;
+
+public class DefaultTokenStoreTest {
+    private static final String FOO_TOKEN = "foo_token";
+    private final DefaultTokenStore dts = new DefaultTokenStore();
+    private static final Dictionary<String, String> config = new Hashtable<>();
+    static {
+        config.put(MAX_CACHED_MEMORY, Long.toString(3));
+        config.put(MAX_CACHED_DISK, Long.toString(3));
+        config.put(SECS_TO_IDLE, Long.toString(1));
+        config.put(SECS_TO_LIVE, Long.toString(1));
+    }
+
+    @Before
+    public void setup() throws ConfigurationException {
+        dts.init(mock(Component.class));
+        dts.updated(config);
+    }
+
+    @After
+    public void teardown() {
+        dts.destroy();
+    }
+
+    @Test
+    public void testCache() throws InterruptedException {
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUser("foo")
+                                                                          .setUserId("1234")
+                                                                          .addRole("admin").build()).build();
+        dts.put(FOO_TOKEN, auth);
+        assertEquals(auth, dts.get(FOO_TOKEN));
+        dts.delete(FOO_TOKEN);
+        assertNull(dts.get(FOO_TOKEN));
+        dts.put(FOO_TOKEN, auth);
+        Thread.sleep(1200);
+        assertNull(dts.get(FOO_TOKEN));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/pom.xml b/odl-aaa-moon/aaa/aaa-authn-sts/pom.xml
new file mode 100644
index 00000000..7dbf86ab
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/pom.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn-sts</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.common</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet-tester</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            *,
+                            com.sun.jersey.spi.container.servlet
+                        </Import-Package>
+                        <Web-ContextPath>/oauth2</Web-ContextPath>
+                        <Bundle-Activator>org.opendaylight.aaa.sts.Activator</Bundle-Activator>
+                        <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/Activator.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/Activator.java
new file mode 100644
index 00000000..1bf4591d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/Activator.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.ClaimAuth;
+import org.opendaylight.aaa.api.ClientService;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An activator for the secure token server to inject in a
+ * {@link CredentialAuth} implementation.
+ *
+ * @author liemmn
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    // Definition of several methods called in the ServiceLocator through
+    // Reflection
+    private static final String AUTHENTICATION_SERVICE_REMOVED = "authenticationServiceRemoved";
+    private static final String AUTHENTICATION_SERVICE_ADDED = "authenticationServiceAdded";
+    private static final String TOKEN_STORE_REMOVED = "tokenStoreRemoved";
+    private static final String TOKEN_STORE_ADDED = "tokenStoreAdded";
+    private static final String TOKEN_AUTH_REMOVED = "tokenAuthRemoved";
+    private static final String TOKEN_AUTH_ADDED = "tokenAuthAdded";
+    private static final String CLAIM_AUTH_REMOVED = "claimAuthRemoved";
+    private static final String CLAIM_AUTH_ADDED = "claimAuthAdded";
+    private static final String CREDENTIAL_AUTH_REMOVED = "credentialAuthRemoved";
+    private static final String CREDENTIAL_AUTH_ADDED = "credentialAuthAdded";
+
+    // A collection of all services, which is used for closing ServiceTrackers
+    private ImmutableList<ServiceTracker<?, ?>> services;
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+
+        LOG.info("STS Activator initializing");
+        manager.add(createComponent().setImplementation(ServiceLocator.getInstance())
+                                     .add(createServiceDependency().setService(CredentialAuth.class)
+                                                                   .setRequired(true)
+                                                                   .setCallbacks(
+                                                                           CREDENTIAL_AUTH_ADDED,
+                                                                           CREDENTIAL_AUTH_REMOVED))
+                                     .add(createServiceDependency().setService(ClaimAuth.class)
+                                                                   .setRequired(false)
+                                                                   .setCallbacks(CLAIM_AUTH_ADDED,
+                                                                           CLAIM_AUTH_REMOVED))
+                                     .add(createServiceDependency().setService(TokenAuth.class)
+                                                                   .setRequired(false)
+                                                                   .setCallbacks(TOKEN_AUTH_ADDED,
+                                                                           TOKEN_AUTH_REMOVED))
+                                     .add(createServiceDependency().setService(TokenStore.class)
+                                                                   .setRequired(true)
+                                                                   .setCallbacks(TOKEN_STORE_ADDED,
+                                                                           TOKEN_STORE_REMOVED))
+                                     .add(createServiceDependency().setService(TokenStore.class)
+                                                                   .setRequired(true))
+                                     .add(createServiceDependency().setService(
+                                             AuthenticationService.class)
+                                                                   .setRequired(true)
+                                                                   .setCallbacks(
+                                                                           AUTHENTICATION_SERVICE_ADDED,
+                                                                           AUTHENTICATION_SERVICE_REMOVED))
+                                     .add(createServiceDependency().setService(IdMService.class)
+                                                                   .setRequired(true))
+                                     .add(createServiceDependency().setService(ClientService.class)
+                                                                   .setRequired(true)));
+
+        final Builder<ServiceTracker<?, ?>> servicesBuilder = new ImmutableList.Builder<ServiceTracker<?, ?>>();
+
+        // Async ServiceTrackers to track and load AAA STS bundles
+        final ServiceTracker<AuthenticationService, AuthenticationService> authenticationService = new ServiceTracker<>(
+                context, AuthenticationService.class,
+                new AAAServiceTrackerCustomizer<AuthenticationService>(
+                        new Function<AuthenticationService, Void>() {
+                        @Override
+                        public Void apply(AuthenticationService authenticationService) {
+                            ServiceLocator.getInstance().setAuthenticationService(
+                                    authenticationService);
+                            return null;
+                        }
+                    }));
+        servicesBuilder.add(authenticationService);
+        authenticationService.open();
+
+        final ServiceTracker<IdMService, IdMService> idmService = new ServiceTracker<>(context,
+                IdMService.class, new AAAServiceTrackerCustomizer<IdMService>(
+                        new Function<IdMService, Void>() {
+                            @Override
+                            public Void apply(IdMService idmService) {
+                                ServiceLocator.getInstance().setIdmService(idmService);
+                                return null;
+                            }
+                        }));
+        servicesBuilder.add(idmService);
+        idmService.open();
+
+        final ServiceTracker<TokenAuth, TokenAuth> tokenAuthService = new ServiceTracker<>(context,
+                TokenAuth.class, new AAAServiceTrackerCustomizer<TokenAuth>(
+                        new Function<TokenAuth, Void>() {
+                            @Override
+                            public Void apply(TokenAuth tokenAuth) {
+                                final List<TokenAuth> tokenAuthCollection = (List<TokenAuth>) Lists.newArrayList(tokenAuth);
+                                ServiceLocator.getInstance().setTokenAuthCollection(
+                                        tokenAuthCollection);
+                                return null;
+                            }
+                        }));
+        servicesBuilder.add(tokenAuthService);
+        tokenAuthService.open();
+
+        final ServiceTracker<TokenStore, TokenStore> tokenStoreService = new ServiceTracker<>(
+                context, TokenStore.class, new AAAServiceTrackerCustomizer<TokenStore>(
+                        new Function<TokenStore, Void>() {
+                            @Override
+                            public Void apply(TokenStore tokenStore) {
+                                ServiceLocator.getInstance().setTokenStore(tokenStore);
+                                return null;
+                            }
+                        }));
+        servicesBuilder.add(tokenStoreService);
+        tokenStoreService.open();
+
+        final ServiceTracker<ClientService, ClientService> clientService = new ServiceTracker<>(
+                context, ClientService.class, new AAAServiceTrackerCustomizer<ClientService>(
+                        new Function<ClientService, Void>() {
+                            @Override
+                            public Void apply(ClientService clientService) {
+                                ServiceLocator.getInstance().setClientService(clientService);
+                                return null;
+                            }
+                        }));
+        servicesBuilder.add(clientService);
+        clientService.open();
+
+        services = servicesBuilder.build();
+
+        LOG.info("STS Activator initialized; ServiceTracker may still be processing");
+    }
+
+    /**
+     * Wrapper for AAA generic service loading.
+     *
+     * @param <S>
+     */
+    static final class AAAServiceTrackerCustomizer<S> implements ServiceTrackerCustomizer<S, S> {
+
+        private Function<S, Void> callback;
+
+        public AAAServiceTrackerCustomizer(final Function<S, Void> callback) {
+            this.callback = callback;
+        }
+
+        @Override
+        public S addingService(ServiceReference<S> reference) {
+            S service = reference.getBundle().getBundleContext().getService(reference);
+            LOG.info("Unable to resolve {}", service.getClass());
+            try {
+                callback.apply(service);
+            } catch (Exception e) {
+                LOG.error("Unable to resolve {}", service.getClass(), e);
+            }
+            return service;
+        }
+
+        @Override
+        public void modifiedService(ServiceReference<S> reference, S service) {
+        }
+
+        @Override
+        public void removedService(ServiceReference<S> reference, S service) {
+        }
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+
+        for (ServiceTracker<?, ?> serviceTracker : services) {
+            serviceTracker.close();
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousPasswordValidator.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousPasswordValidator.java
new file mode 100644
index 00000000..55b5b61f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousPasswordValidator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.validators.AbstractValidator;
+
+/**
+ * A password validator that does not enforce client identification.
+ *
+ * @author liemmn
+ *
+ */
+public class AnonymousPasswordValidator extends AbstractValidator<HttpServletRequest> {
+
+    public AnonymousPasswordValidator() {
+        requiredParams.add(OAuth.OAUTH_GRANT_TYPE);
+        requiredParams.add(OAuth.OAUTH_USERNAME);
+        requiredParams.add(OAuth.OAUTH_PASSWORD);
+
+        enforceClientAuthentication = false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousRefreshTokenValidator.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousRefreshTokenValidator.java
new file mode 100644
index 00000000..5b50c7da
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/AnonymousRefreshTokenValidator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.validators.AbstractValidator;
+
+/**
+ * A refresh token validator that does not enforce client identification.
+ *
+ * @author liemmn
+ *
+ */
+public class AnonymousRefreshTokenValidator extends AbstractValidator<HttpServletRequest> {
+
+    public AnonymousRefreshTokenValidator() {
+        requiredParams.add(OAuth.OAUTH_GRANT_TYPE);
+        requiredParams.add(OAuth.OAUTH_REFRESH_TOKEN);
+
+        enforceClientAuthentication = false;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/OAuthRequest.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/OAuthRequest.java
new file mode 100644
index 00000000..2a2b34b6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/OAuthRequest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
+import org.apache.oltu.oauth2.as.validator.UnauthenticatedAuthorizationCodeValidator;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.common.validators.OAuthValidator;
+
+/**
+ * OAuth request wrapper.
+ *
+ * @author liemmn
+ *
+ */
+public class OAuthRequest extends AbstractOAuthTokenRequest {
+
+    public OAuthRequest(HttpServletRequest request) throws OAuthSystemException,
+            OAuthProblemException {
+        super(request);
+    }
+
+    @Override
+    public OAuthValidator<HttpServletRequest> initValidator() throws OAuthProblemException,
+            OAuthSystemException {
+        validators.put(GrantType.PASSWORD.toString(), AnonymousPasswordValidator.class);
+        validators.put(GrantType.REFRESH_TOKEN.toString(), AnonymousRefreshTokenValidator.class);
+        validators.put(GrantType.AUTHORIZATION_CODE.toString(),
+                UnauthenticatedAuthorizationCodeValidator.class);
+        return super.initValidator();
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/ServiceLocator.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/ServiceLocator.java
new file mode 100644
index 00000000..2c1f84c3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/ServiceLocator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import java.util.List;
+import java.util.Vector;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.ClientService;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.opendaylight.aaa.api.TokenStore;
+
+/**
+ * A service locator to bridge between the web world and OSGi world.
+ *
+ * @author liemmn
+ *
+ */
+public class ServiceLocator {
+
+    private static final ServiceLocator instance = new ServiceLocator();
+
+    protected volatile List<TokenAuth> tokenAuthCollection = new Vector<>();
+
+    protected volatile CredentialAuth<PasswordCredentials> credentialAuth;
+
+    protected volatile TokenStore tokenStore;
+
+    protected volatile AuthenticationService authenticationService;
+
+    protected volatile IdMService idmService;
+
+    protected volatile ClientService clientService;
+
+    private ServiceLocator() {
+    }
+
+    public static ServiceLocator getInstance() {
+        return instance;
+    }
+
+    /**
+     * Called through reflection by the sts activator.
+     *
+     * @see org.opendaylight.aaa.sts.Activator
+     * @param ta
+     */
+    protected void tokenAuthAdded(TokenAuth ta) {
+        this.tokenAuthCollection.add(ta);
+    }
+
+    /**
+     * Called through reflection by the sts activator.
+     *
+     * @see org.opendaylight.aaa.sts.Activator
+     * @param ta
+     */
+    protected void tokenAuthRemoved(TokenAuth ta) {
+        this.tokenAuthCollection.remove(ta);
+    }
+
+    protected void tokenStoreAdded(TokenStore ts) {
+        this.tokenStore = ts;
+    }
+
+    protected void tokenStoreRemoved(TokenStore ts) {
+        this.tokenStore = null;
+    }
+
+    protected void authenticationServiceAdded(AuthenticationService as) {
+        this.authenticationService = as;
+    }
+
+    protected void authenticationServiceRemoved(AuthenticationService as) {
+        this.authenticationService = null;
+    }
+
+    protected void credentialAuthAdded(CredentialAuth<PasswordCredentials> da) {
+        this.credentialAuth = da;
+    }
+
+    protected void credentialAuthAddedRemoved(CredentialAuth<PasswordCredentials> da) {
+        this.credentialAuth = null;
+    }
+
+    public List<TokenAuth> getTokenAuthCollection() {
+        return tokenAuthCollection;
+    }
+
+    public void setTokenAuthCollection(List<TokenAuth> tokenAuthCollection) {
+        this.tokenAuthCollection = tokenAuthCollection;
+    }
+
+    public CredentialAuth<PasswordCredentials> getCredentialAuth() {
+        return credentialAuth;
+    }
+
+    public synchronized void setCredentialAuth(CredentialAuth<PasswordCredentials> credentialAuth) {
+        this.credentialAuth = credentialAuth;
+    }
+
+    public TokenStore getTokenStore() {
+        return tokenStore;
+    }
+
+    public void setTokenStore(TokenStore tokenStore) {
+        this.tokenStore = tokenStore;
+    }
+
+    public AuthenticationService getAuthenticationService() {
+        return authenticationService;
+    }
+
+    public void setAuthenticationService(AuthenticationService authenticationService) {
+        this.authenticationService = authenticationService;
+    }
+
+    public IdMService getIdmService() {
+        return idmService;
+    }
+
+    public void setIdmService(IdMService idmService) {
+        this.idmService = idmService;
+    }
+
+    public ClientService getClientService() {
+        return clientService;
+    }
+
+    public void setClientService(ClientService clientService) {
+        this.clientService = clientService;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java
new file mode 100644
index 00000000..3fa7a66c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenAuthFilter.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerRequestFilter;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
+import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.TokenAuth;
+
+/**
+ * A token-based authentication filter for resource providers.
+ *
+ * Deprecated: Use <code>AAAFilter</code> instead.
+ *
+ * @author liemmn
+ *
+ */
+@Deprecated
+public class TokenAuthFilter implements ContainerRequestFilter {
+
+    private final String OPTIONS = "OPTIONS";
+    private final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
+    private final String AUTHORIZATION = "authorization";
+
+    @Context
+    private HttpServletRequest httpRequest;
+
+    @Override
+    public ContainerRequest filter(ContainerRequest request) {
+
+        // Do the CORS check first
+        if (checkCORSOptionRequest(request)) {
+            return request;
+        }
+
+        // Are we up yet?
+        if (ServiceLocator.getInstance().getAuthenticationService() == null) {
+            throw new WebApplicationException(
+                    Response.status(Status.SERVICE_UNAVAILABLE).type(MediaType.APPLICATION_JSON)
+                            .entity("{\"error\":\"Authentication service unavailable\"}").build());
+        }
+
+        // Are we doing authentication or not?
+        if (ServiceLocator.getInstance().getAuthenticationService().isAuthEnabled()) {
+            Map<String, List<String>> headers = request.getRequestHeaders();
+
+            // Go through and invoke other TokenAuth first...
+            List<TokenAuth> tokenAuthCollection = ServiceLocator.getInstance()
+                                                                .getTokenAuthCollection();
+            for (TokenAuth ta : tokenAuthCollection) {
+                try {
+                    Authentication auth = ta.validate(headers);
+                    if (auth != null) {
+                        ServiceLocator.getInstance().getAuthenticationService().set(auth);
+                        return request;
+                    }
+                } catch (AuthenticationException ae) {
+                    throw unauthorized();
+                }
+            }
+
+            // OK, last chance to validate token...
+            try {
+                OAuthAccessResourceRequest or = new OAuthAccessResourceRequest(httpRequest,
+                        ParameterStyle.HEADER);
+                validate(or.getAccessToken());
+            } catch (OAuthSystemException | OAuthProblemException e) {
+                throw unauthorized();
+            }
+        }
+
+        return request;
+    }
+
+    /**
+     * CORS access control : when browser sends cross-origin request, it first
+     * sends the OPTIONS method with a list of access control request headers,
+     * which has a list of custom headers and access control method such as GET.
+     * POST etc. You custom header "Authorization will not be present in request
+     * header, instead it will be present as a value inside
+     * Access-Control-Request-Headers. We should not do any authorization
+     * against such request. for more details :
+     * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
+     */
+
+    private boolean checkCORSOptionRequest(ContainerRequest request) {
+        if (OPTIONS.equals(request.getMethod())) {
+            List<String> headerList = request.getRequestHeader(ACCESS_CONTROL_REQUEST_HEADERS);
+            if (headerList != null && !headerList.isEmpty()) {
+                String header = headerList.get(0);
+                if (header != null && header.toLowerCase().contains(AUTHORIZATION)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // Validate an ODL token...
+    private Authentication validate(final String token) {
+        Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token);
+        if (auth == null) {
+            throw unauthorized();
+        } else {
+            ServiceLocator.getInstance().getAuthenticationService().set(auth);
+        }
+        return auth;
+    }
+
+    // Houston, we got a problem!
+    private static final WebApplicationException unauthorized() {
+        ServiceLocator.getInstance().getAuthenticationService().clear();
+        return new UnauthorizedException();
+    }
+
+    // A custom 401 web exception that handles http basic response as well
+    static final class UnauthorizedException extends WebApplicationException {
+        private static final long serialVersionUID = -1732363804773027793L;
+        static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+        static final Object OPENDAYLIGHT = "Basic realm=\"opendaylight\"";
+        private static final Response response = Response.status(Status.UNAUTHORIZED)
+                                                         .header(WWW_AUTHENTICATE, OPENDAYLIGHT)
+                                                         .build();
+
+        public UnauthorizedException() {
+            super(response);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java
new file mode 100644
index 00000000..a456d702
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/java/org/opendaylight/aaa/sts/TokenEndpoint.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import static javax.servlet.http.HttpServletResponse.SC_NOT_IMPLEMENTED;
+import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
+import org.apache.oltu.oauth2.as.issuer.UUIDValueGenerator;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.PasswordCredentialBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.PasswordCredentials;
+
+/**
+ * Secure Token Service (STS) endpoint.
+ *
+ * @author liemmn
+ *
+ */
+public class TokenEndpoint extends HttpServlet {
+    private static final long serialVersionUID = 8272453849539659999L;
+
+    private static final String DOMAIN_SCOPE_REQUIRED = "Domain scope required";
+    private static final String NOT_IMPLEMENTED = "not_implemented";
+    private static final String UNAUTHORIZED = "unauthorized";
+
+    static final String TOKEN_GRANT_ENDPOINT = "/token";
+    static final String TOKEN_REVOKE_ENDPOINT = "/revoke";
+    static final String TOKEN_VALIDATE_ENDPOINT = "/validate";
+
+    private transient OAuthIssuer oi;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        oi = new OAuthIssuerImpl(new UUIDValueGenerator());
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        try {
+            if (req.getServletPath().equals(TOKEN_GRANT_ENDPOINT)) {
+                createAccessToken(req, resp);
+            } else if (req.getServletPath().equals(TOKEN_REVOKE_ENDPOINT)) {
+                deleteAccessToken(req, resp);
+            } else if (req.getServletPath().equals(TOKEN_VALIDATE_ENDPOINT)) {
+                validateToken(req, resp);
+            }
+        } catch (AuthenticationException e) {
+            error(resp, SC_UNAUTHORIZED, e.getMessage());
+        } catch (OAuthProblemException oe) {
+            error(resp, oe);
+        } catch (Exception e) {
+            error(resp, e);
+        }
+    }
+
+    private void validateToken(HttpServletRequest req, HttpServletResponse resp)
+            throws IOException, OAuthSystemException {
+        String token = req.getReader().readLine();
+        if (token != null) {
+            Authentication authn = ServiceLocator.getInstance().getTokenStore().get(token.trim());
+            if (authn == null) {
+                throw new AuthenticationException(UNAUTHORIZED);
+            } else {
+                ServiceLocator.getInstance().getAuthenticationService().set(authn);
+                resp.setStatus(SC_OK);
+            }
+        } else {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+    }
+
+    // Delete an access token
+    private void deleteAccessToken(HttpServletRequest req, HttpServletResponse resp)
+            throws IOException {
+        String token = req.getReader().readLine();
+        if (token != null) {
+            if (ServiceLocator.getInstance().getTokenStore().delete(token.trim())) {
+                resp.setStatus(SC_NO_CONTENT);
+            } else {
+                throw new AuthenticationException(UNAUTHORIZED);
+            }
+        } else {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+    }
+
+    // Create an access token
+    private void createAccessToken(HttpServletRequest req, HttpServletResponse resp)
+            throws OAuthSystemException, OAuthProblemException, IOException {
+        Claim claim = null;
+        String clientId = null;
+
+        OAuthRequest oauthRequest = new OAuthRequest(req);
+        // Any client credentials?
+        clientId = oauthRequest.getClientId();
+        if (clientId != null) {
+            ServiceLocator.getInstance().getClientService()
+                          .validate(clientId, oauthRequest.getClientSecret());
+        }
+
+        // Credential request...
+        if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.PASSWORD.toString())) {
+            String domain = oauthRequest.getScopes().iterator().next();
+            PasswordCredentials pc = new PasswordCredentialBuilder().setUserName(
+                    oauthRequest.getUsername()).setPassword(oauthRequest.getPassword())
+                                                                    .setDomain(domain).build();
+            if (!oauthRequest.getScopes().isEmpty()) {
+                claim = ServiceLocator.getInstance().getCredentialAuth().authenticate(pc);
+            }
+        } else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(
+                GrantType.REFRESH_TOKEN.toString())) {
+            // Refresh token...
+            String token = oauthRequest.getRefreshToken();
+            if (!oauthRequest.getScopes().isEmpty()) {
+                String domain = oauthRequest.getScopes().iterator().next();
+                // Authenticate...
+                Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token);
+                if (auth != null && domain != null) {
+                    List<String> roles = ServiceLocator.getInstance().getIdmService()
+                                                       .listRoles(auth.userId(), domain);
+                    if (!roles.isEmpty()) {
+                        ClaimBuilder cb = new ClaimBuilder(auth);
+                        cb.setDomain(domain); // scope domain
+                        // Add roles for the scoped domain
+                        for (String role : roles) {
+                            cb.addRole(role);
+                        }
+                        claim = cb.build();
+                    }
+                }
+            } else {
+                error(resp, SC_BAD_REQUEST, DOMAIN_SCOPE_REQUIRED);
+            }
+        } else {
+            // Support authorization code later...
+            error(resp, SC_NOT_IMPLEMENTED, NOT_IMPLEMENTED);
+        }
+
+        // Respond with OAuth token
+        oauthAccessTokenResponse(resp, claim, clientId);
+    }
+
+    // Build OAuth access token response from the given claim
+    private void oauthAccessTokenResponse(HttpServletResponse resp, Claim claim, String clientId)
+            throws OAuthSystemException, IOException {
+        if (claim == null) {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+        String token = oi.accessToken();
+
+        // Cache this token...
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder(claim).setClientId(
+                clientId).build()).setExpiration(tokenExpiration()).build();
+        ServiceLocator.getInstance().getTokenStore().put(token, auth);
+
+        OAuthResponse r = OAuthASResponse.tokenResponse(SC_CREATED).setAccessToken(token)
+                                         .setTokenType(TokenType.BEARER.toString())
+                                         .setExpiresIn(Long.toString(auth.expiration()))
+                                         .buildJSONMessage();
+        write(resp, r);
+    }
+
+    // Token expiration
+    private long tokenExpiration() {
+        return ServiceLocator.getInstance().getTokenStore().tokenExpiration();
+    }
+
+    // Emit an error OAuthResponse with the given HTTP code
+    private void error(HttpServletResponse resp, int httpCode, String error) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(httpCode).setError(error)
+                                           .buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    // Emit an error OAuthResponse for the given OAuth-related exception
+    private void error(HttpServletResponse resp, OAuthProblemException e) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(SC_BAD_REQUEST).error(e)
+                                           .buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    // Emit an error OAuthResponse for the given generic exception
+    private void error(HttpServletResponse resp, Exception e) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(SC_INTERNAL_SERVER_ERROR)
+                                           .setError(e.getClass().getName())
+                                           .setErrorDescription(e.getMessage()).buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    // Write out an OAuthResponse
+    private void write(HttpServletResponse resp, OAuthResponse r) throws IOException {
+        resp.setStatus(r.getResponseStatus());
+        PrintWriter pw = resp.getWriter();
+        pw.print(r.getBody());
+        pw.flush();
+        pw.close();
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/main/resources/WEB-INF/web.xml b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/resources/WEB-INF/web.xml
new file mode 100644
index 00000000..83a9fa51
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/main/resources/WEB-INF/web.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+    version="3.0">
+
+    <servlet>
+        <servlet-name>STS</servlet-name>
+        <servlet-class>org.opendaylight.aaa.sts.TokenEndpoint</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>STS</servlet-name>
+        <url-pattern>/token</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>STS</servlet-name>
+        <url-pattern>/revoke</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>STS</servlet-name>
+        <url-pattern>/validate</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/RestFixture.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/RestFixture.java
new file mode 100644
index 00000000..0f806d91
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/RestFixture.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+
+/**
+ * Fixture for testing RESTful stuff.
+ *
+ * @author liemmn
+ *
+ */
+@Path("test")
+public class RestFixture {
+
+    @Context
+    private HttpServletRequest httpRequest;
+
+    @GET
+    @Produces("text/plain")
+    public String msg() {
+        return "ok";
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenAuthTest.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenAuthTest.java
new file mode 100644
index 00000000..7f888455
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenAuthTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.opendaylight.aaa.api.TokenStore;
+import org.opendaylight.aaa.sts.TokenAuthFilter.UnauthorizedException;
+
+public class TokenAuthTest extends JerseyTest {
+
+    private static final String RS_PACKAGES = "org.opendaylight.aaa.sts";
+    private static final String JERSEY_FILTERS = "com.sun.jersey.spi.container.ContainerRequestFilters";
+    private static final String AUTH_FILTERS = TokenAuthFilter.class.getName();
+
+    private static Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUserId(
+            "1234").setUser("Bob").addRole("admin").addRole("user").setDomain("tenantX").build()).setExpiration(
+            System.currentTimeMillis() + 1000).build();
+
+    private static final String GOOD_TOKEN = "9b01b7cf-8a49-346d-8c47-6a61193e2b60";
+    private static final String BAD_TOKEN = "9b01b7cf-8a49-346d-8c47-6a611badbeef";
+
+    public TokenAuthTest() throws Exception {
+        super(new WebAppDescriptor.Builder(RS_PACKAGES).initParam(JERSEY_FILTERS, AUTH_FILTERS)
+                                                       .build());
+    }
+
+    @BeforeClass
+    public static void init() {
+        ServiceLocator.getInstance().setAuthenticationService(mock(AuthenticationService.class));
+        ServiceLocator.getInstance().setTokenStore(mock(TokenStore.class));
+        when(ServiceLocator.getInstance().getTokenStore().get(GOOD_TOKEN)).thenReturn(auth);
+        when(ServiceLocator.getInstance().getTokenStore().get(BAD_TOKEN)).thenReturn(null);
+        when(ServiceLocator.getInstance().getAuthenticationService().isAuthEnabled()).thenReturn(
+                Boolean.TRUE);
+    }
+
+    @Test()
+    public void testGetUnauthorized() {
+        try {
+            resource().path("test").get(String.class);
+            fail("Shoulda failed with 401!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(401, resp.getStatus());
+            assertTrue(resp.getHeaders().get(UnauthorizedException.WWW_AUTHENTICATE)
+                           .contains(UnauthorizedException.OPENDAYLIGHT));
+        }
+    }
+
+    @Test
+    public void testGet() {
+        String resp = resource().path("test").header("Authorization", "Bearer " + GOOD_TOKEN)
+                                .get(String.class);
+        assertEquals("ok", resp);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetWithValidator() {
+        try {
+            // Mock a laxed tokenauth...
+            TokenAuth ta = mock(TokenAuth.class);
+            when(ta.validate(anyMap())).thenReturn(auth);
+            ServiceLocator.getInstance().getTokenAuthCollection().add(ta);
+            testGet();
+        } finally {
+            ServiceLocator.getInstance().getTokenAuthCollection().clear();
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenEndpointTest.java b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenEndpointTest.java
new file mode 100644
index 00000000..06dd6302
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn-sts/src/test/java/org/opendaylight/aaa/sts/TokenEndpointTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.sts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import org.eclipse.jetty.testing.HttpTester;
+import org.eclipse.jetty.testing.ServletTester;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.ClientService;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.opendaylight.aaa.api.TokenStore;
+
+/**
+ * A unit test for token endpoint.
+ *
+ * @author liemmn
+ *
+ */
+public class TokenEndpointTest {
+    private static final long TOKEN_TIMEOUT_SECS = 10;
+    private static final String CONTEXT = "/oauth2";
+    private static final String DIRECT_AUTH = "grant_type=password&username=admin&password=admin&scope=pepsi&client_id=dlux&client_secret=secrete";
+    private static final String REFRESH_TOKEN = "grant_type=refresh_token&refresh_token=whateverisgood&scope=pepsi";
+
+    private static final Claim claim = new ClaimBuilder().setUser("bob").setUserId("1234")
+                                                         .addRole("admin").build();
+    private final static ServletTester server = new ServletTester();
+
+    @BeforeClass
+    public static void init() throws Exception {
+        // Set up server
+        server.setContextPath(CONTEXT);
+
+        // Add our servlet under test
+        server.addServlet(TokenEndpoint.class, "/revoke");
+        server.addServlet(TokenEndpoint.class, "/token");
+
+        // Let's do dis
+        server.start();
+    }
+
+    @AfterClass
+    public static void shutdown() throws Exception {
+        server.stop();
+    }
+
+    @Before
+    public void setup() {
+        mockServiceLocator();
+        when(ServiceLocator.getInstance().getTokenStore().tokenExpiration()).thenReturn(
+                TOKEN_TIMEOUT_SECS);
+    }
+
+    @After
+    public void teardown() {
+        ServiceLocator.getInstance().getTokenAuthCollection().clear();
+    }
+
+    @Test
+    public void testCreateToken401() throws Exception {
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+        req.setContent(DIRECT_AUTH);
+        req.setURI(CONTEXT + TokenEndpoint.TOKEN_GRANT_ENDPOINT);
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(401, resp.getStatus());
+    }
+
+    @Test
+    public void testCreateTokenWithPassword() throws Exception {
+        when(
+                ServiceLocator.getInstance().getCredentialAuth()
+                              .authenticate(any(PasswordCredentials.class))).thenReturn(claim);
+
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+        req.setContent(DIRECT_AUTH);
+        req.setURI(CONTEXT + TokenEndpoint.TOKEN_GRANT_ENDPOINT);
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(201, resp.getStatus());
+        assertTrue(resp.getContent().contains("expires_in\":10"));
+        assertTrue(resp.getContent().contains("Bearer"));
+    }
+
+    @Test
+    public void testCreateTokenWithRefreshToken() throws Exception {
+        when(ServiceLocator.getInstance().getTokenStore().get(anyString())).thenReturn(
+                new AuthenticationBuilder(claim).build());
+        when(ServiceLocator.getInstance().getIdmService().listRoles(anyString(), anyString())).thenReturn(
+                Arrays.asList("admin", "user"));
+
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+        req.setContent(REFRESH_TOKEN);
+        req.setURI(CONTEXT + TokenEndpoint.TOKEN_GRANT_ENDPOINT);
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(201, resp.getStatus());
+        assertTrue(resp.getContent().contains("expires_in\":10"));
+        assertTrue(resp.getContent().contains("Bearer"));
+    }
+
+    @Test
+    public void testDeleteToken() throws Exception {
+        when(ServiceLocator.getInstance().getTokenStore().delete("token_to_be_deleted")).thenReturn(
+                true);
+
+        HttpTester req = new HttpTester();
+        req.setMethod("POST");
+        req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+        req.setContent("token_to_be_deleted");
+        req.setURI(CONTEXT + TokenEndpoint.TOKEN_REVOKE_ENDPOINT);
+        req.setVersion("HTTP/1.0");
+
+        HttpTester resp = new HttpTester();
+        resp.parse(server.getResponses(req.generate()));
+        assertEquals(204, resp.getStatus());
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void mockServiceLocator() {
+        ServiceLocator.getInstance().setClientService(mock(ClientService.class));
+        ServiceLocator.getInstance().setIdmService(mock(IdMService.class));
+        ServiceLocator.getInstance().setAuthenticationService(mock(AuthenticationService.class));
+        ServiceLocator.getInstance().setTokenStore(mock(TokenStore.class));
+        ServiceLocator.getInstance().setCredentialAuth(mock(CredentialAuth.class));
+        ServiceLocator.getInstance().getTokenAuthCollection().add(mock(TokenAuth.class));
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/pom.xml b/odl-aaa-moon/aaa/aaa-authn/pom.xml
new file mode 100644
index 00000000..01f1c99c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/pom.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2014-2015 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authn</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.aaa.Activator</Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/authn.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/Activator.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/Activator.java
new file mode 100644
index 00000000..cfe27ef0
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/Activator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import java.util.Dictionary;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.ClientService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * Activator to register {@link AuthenticationService} with OSGi.
+ *
+ * @author liemmn
+ *
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static final String AUTHN_PID = "org.opendaylight.aaa.authn";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent().setInterface(
+                new String[] { AuthenticationService.class.getName() }, null).setImplementation(
+                AuthenticationManager.instance()));
+
+        ClientManager cm = new ClientManager();
+        manager.add(createComponent().setInterface(new String[] { ClientService.class.getName() },
+                null).setImplementation(cm));
+        context.registerService(ManagedService.class.getName(), cm, addPid(ClientManager.defaults));
+        context.registerService(ManagedService.class.getName(), AuthenticationManager.instance(),
+                addPid(AuthenticationManager.defaults));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+    private Dictionary<String, ?> addPid(Dictionary<String, String> dict) {
+        dict.put(Constants.SERVICE_PID, AUTHN_PID);
+        return dict;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationBuilder.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationBuilder.java
new file mode 100644
index 00000000..948cbac6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import static org.opendaylight.aaa.EqualUtil.areEqual;
+import static org.opendaylight.aaa.HashCodeUtil.hash;
+
+import java.io.Serializable;
+import java.util.Set;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.Claim;
+
+/**
+ * A builder for the authentication context.
+ *
+ * The expiration defaults to 0.
+ *
+ * @author liemmn
+ *
+ */
+public class AuthenticationBuilder {
+
+    private long expiration = 0L;
+    private Claim claim;
+
+    public AuthenticationBuilder(Claim claim) {
+        this.claim = claim;
+    }
+
+    public AuthenticationBuilder setExpiration(long expiration) {
+        this.expiration = expiration;
+        return this;
+    }
+
+    public Authentication build() {
+        return new ImmutableAuthentication(this);
+    }
+
+    private static final class ImmutableAuthentication implements Authentication, Serializable {
+        private static final long serialVersionUID = 4919078164955609987L;
+        private int hashCode = 0;
+        long expiration = 0L;
+        Claim claim;
+
+        private ImmutableAuthentication(AuthenticationBuilder base) {
+            if (base.claim == null) {
+                throw new IllegalStateException("The Claim is null.");
+            }
+            claim = new ClaimBuilder(base.claim).build();
+            expiration = base.expiration;
+
+            if (base.expiration < 0) {
+                throw new IllegalStateException("The expiration is less than 0.");
+            }
+        }
+
+        @Override
+        public long expiration() {
+            return expiration;
+        }
+
+        @Override
+        public String clientId() {
+            return claim.clientId();
+        }
+
+        @Override
+        public String userId() {
+            return claim.userId();
+        }
+
+        @Override
+        public String user() {
+            return claim.user();
+        }
+
+        @Override
+        public String domain() {
+            return claim.domain();
+        }
+
+        @Override
+        public Set<String> roles() {
+            return claim.roles();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof Authentication)) {
+                return false;
+            }
+            Authentication a = (Authentication) o;
+            return areEqual(expiration, a.expiration()) && areEqual(claim.roles(), a.roles())
+                    && areEqual(claim.domain(), a.domain()) && areEqual(claim.userId(), a.userId())
+                    && areEqual(claim.user(), a.user()) && areEqual(claim.clientId(), a.clientId());
+        }
+
+        @Override
+        public int hashCode() {
+            if (hashCode == 0) {
+                int result = HashCodeUtil.SEED;
+                result = hash(result, expiration);
+                result = hash(result, claim.hashCode());
+                hashCode = result;
+            }
+            return hashCode;
+        }
+
+        @Override
+        public String toString() {
+            return "expiration:" + expiration + "," + claim.toString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationManager.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationManager.java
new file mode 100644
index 00000000..5f6420a3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/AuthenticationManager.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * An {@link InheritableThreadLocal}-based {@link AuthenticationService}.
+ *
+ * @author liemmn
+ */
+public class AuthenticationManager implements AuthenticationService, ManagedService {
+    private static final String AUTH_ENABLED_ERR = "Error setting authEnabled";
+
+    static final String AUTH_ENABLED = "authEnabled";
+    static final Dictionary<String, String> defaults = new Hashtable<>();
+    static {
+        defaults.put(AUTH_ENABLED, Boolean.FALSE.toString());
+    }
+
+    // In non-Karaf environments, authEnabled is set to false by default
+    private static volatile boolean authEnabled = false;
+
+    private final static AuthenticationManager am = new AuthenticationManager();
+    private final ThreadLocal<Authentication> auth = new InheritableThreadLocal<>();
+
+    private AuthenticationManager() {
+    }
+
+    static AuthenticationManager instance() {
+        return am;
+    }
+
+    @Override
+    public Authentication get() {
+        return auth.get();
+    }
+
+    @Override
+    public void set(Authentication a) {
+        auth.set(a);
+    }
+
+    @Override
+    public void clear() {
+        auth.remove();
+    }
+
+    @Override
+    public boolean isAuthEnabled() {
+        return authEnabled;
+    }
+
+    @Override
+    public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+        if (properties == null) {
+            return;
+        }
+
+        String propertyValue = (String) properties.get(AUTH_ENABLED);
+        boolean isTrueString = Boolean.parseBoolean(propertyValue);
+        if (!isTrueString && !"false".equalsIgnoreCase(propertyValue)) {
+            throw new ConfigurationException(AUTH_ENABLED, AUTH_ENABLED_ERR);
+        }
+        authEnabled = isTrueString;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClaimBuilder.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClaimBuilder.java
new file mode 100644
index 00000000..4e4a8ef3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClaimBuilder.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import static org.opendaylight.aaa.EqualUtil.areEqual;
+import static org.opendaylight.aaa.HashCodeUtil.hash;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import java.io.Serializable;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.opendaylight.aaa.api.Claim;
+
+/**
+ * Builder for a {@link Claim}. The userId, user, and roles information is
+ * mandatory.
+ *
+ * @author liemmn
+ *
+ */
+public class ClaimBuilder {
+    private String userId = "";
+    private String user = "";
+    private Set<String> roles = new LinkedHashSet<>();
+    private String clientId = "";
+    private String domain = "";
+
+    public ClaimBuilder() {
+    }
+
+    public ClaimBuilder(Claim claim) {
+        clientId = claim.clientId();
+        userId = claim.userId();
+        user = claim.user();
+        domain = claim.domain();
+        roles.addAll(claim.roles());
+    }
+
+    public ClaimBuilder setClientId(String clientId) {
+        this.clientId = Strings.nullToEmpty(clientId).trim();
+        return this;
+    }
+
+    public ClaimBuilder setUserId(String userId) {
+        this.userId = Strings.nullToEmpty(userId).trim();
+        return this;
+    }
+
+    public ClaimBuilder setUser(String userName) {
+        user = Strings.nullToEmpty(userName).trim();
+        return this;
+    }
+
+    public ClaimBuilder setDomain(String domain) {
+        this.domain = Strings.nullToEmpty(domain).trim();
+        return this;
+    }
+
+    public ClaimBuilder addRoles(Set<String> roles) {
+        for (String role : roles) {
+            addRole(role);
+        }
+        return this;
+    }
+
+    public ClaimBuilder addRole(String role) {
+        roles.add(Strings.nullToEmpty(role).trim());
+        return this;
+    }
+
+    public Claim build() {
+        return new ImmutableClaim(this);
+    }
+
+    protected static class ImmutableClaim implements Claim, Serializable {
+        private static final long serialVersionUID = -8115027645190209129L;
+        private int hashCode = 0;
+        protected String clientId;
+        protected String userId;
+        protected String user;
+        protected String domain;
+        protected ImmutableSet<String> roles;
+
+        protected ImmutableClaim(ClaimBuilder base) {
+            clientId = base.clientId;
+            userId = base.userId;
+            user = base.user;
+            domain = base.domain;
+            roles = ImmutableSet.<String> builder().addAll(base.roles).build();
+
+            if (userId.isEmpty() || user.isEmpty() || roles.isEmpty() || roles.contains("")) {
+                throw new IllegalStateException(
+                        "The Claim is missing one or more of the required fields.");
+            }
+        }
+
+        @Override
+        public String clientId() {
+            return clientId;
+        }
+
+        @Override
+        public String userId() {
+            return userId;
+        }
+
+        @Override
+        public String user() {
+            return user;
+        }
+
+        @Override
+        public String domain() {
+            return domain;
+        }
+
+        @Override
+        public Set<String> roles() {
+            return roles;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (!(o instanceof Claim))
+                return false;
+            Claim a = (Claim) o;
+            return areEqual(roles, a.roles()) && areEqual(domain, a.domain())
+                    && areEqual(userId, a.userId()) && areEqual(user, a.user())
+                    && areEqual(clientId, a.clientId());
+        }
+
+        @Override
+        public int hashCode() {
+            if (hashCode == 0) {
+                int result = HashCodeUtil.SEED;
+                result = hash(result, clientId);
+                result = hash(result, userId);
+                result = hash(result, user);
+                result = hash(result, domain);
+                result = hash(result, roles);
+                hashCode = result;
+            }
+            return hashCode;
+        }
+
+        @Override
+        public String toString() {
+            return "clientId:" + clientId + "," + "userId:" + userId + "," + "userName:" + user
+                    + "," + "domain:" + domain + "," + "roles:" + roles;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClientManager.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClientManager.java
new file mode 100644
index 00000000..e7e51424
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/ClientManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.felix.dm.Component;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.ClientService;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * A configuration-based client manager.
+ *
+ * @author liemmn
+ *
+ */
+public class ClientManager implements ClientService, ManagedService {
+    static final String CLIENTS = "authorizedClients";
+    private static final String CLIENTS_FORMAT_ERR = "Clients are space-delimited in the form of <client_id>:<client_secret>";
+    private static final String UNAUTHORIZED_CLIENT_ERR = "Unauthorized client";
+
+    // Defaults (needed only for non-Karaf deployments)
+    static final Dictionary<String, String> defaults = new Hashtable<>();
+    static {
+        defaults.put(CLIENTS, "dlux:secrete");
+    }
+
+    private final Map<String, String> clients = new ConcurrentHashMap<>();
+
+    // This should be a singleton
+    ClientManager() {
+    }
+
+    // Called by DM when all required dependencies are satisfied.
+    void init(Component c) throws ConfigurationException {
+        reconfig(defaults);
+    }
+
+    @Override
+    public void validate(String clientId, String clientSecret) throws AuthenticationException {
+        // TODO: Post-Helium, we will support a CRUD API
+        if (!clients.containsKey(clientId)) {
+            throw new AuthenticationException(UNAUTHORIZED_CLIENT_ERR);
+        }
+        if (!clients.get(clientId).equals(clientSecret)) {
+            throw new AuthenticationException(UNAUTHORIZED_CLIENT_ERR);
+        }
+    }
+
+    @Override
+    public void updated(Dictionary<String, ?> props) throws ConfigurationException {
+        if (props == null) {
+            props = defaults;
+        }
+        reconfig(props);
+    }
+
+    // Reconfigure the client map...
+    private void reconfig(@SuppressWarnings("rawtypes") Dictionary props)
+            throws ConfigurationException {
+        try {
+            String authorizedClients = (String) props.get(CLIENTS);
+            Map<String, String> newClients = new HashMap<>();
+            if (authorizedClients != null) {
+                for (String client : authorizedClients.split(" ")) {
+                    String[] aClient = client.split(":");
+                    newClients.put(aClient[0], aClient[1]);
+                }
+            }
+            clients.clear();
+            clients.putAll(newClients);
+        } catch (Throwable t) {
+            throw new ConfigurationException(null, CLIENTS_FORMAT_ERR);
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/EqualUtil.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/EqualUtil.java
new file mode 100644
index 00000000..17204d0e
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/EqualUtil.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+/**
+ * Simple class to aide in implementing equals.
+ * <p>
+ *
+ * <em>Arrays are not handled by this class</em>. This is because the
+ * <code>Arrays.equals</code> methods should be used for array fields.
+ */
+public final class EqualUtil {
+    static public boolean areEqual(boolean aThis, boolean aThat) {
+        return aThis == aThat;
+    }
+
+    static public boolean areEqual(char aThis, char aThat) {
+        return aThis == aThat;
+    }
+
+    static public boolean areEqual(long aThis, long aThat) {
+        return aThis == aThat;
+    }
+
+    static public boolean areEqual(float aThis, float aThat) {
+        return Float.floatToIntBits(aThis) == Float.floatToIntBits(aThat);
+    }
+
+    static public boolean areEqual(double aThis, double aThat) {
+        return Double.doubleToLongBits(aThis) == Double.doubleToLongBits(aThat);
+    }
+
+    static public boolean areEqual(Object aThis, Object aThat) {
+        return aThis == null ? aThat == null : aThis.equals(aThat);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/HashCodeUtil.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/HashCodeUtil.java
new file mode 100644
index 00000000..c295b3ed
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/HashCodeUtil.java
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *****************************************************************************/
+
+package org.opendaylight.aaa;
+
+import java.lang.reflect.Array;
+
+/**
+ * Collected methods which allow easy implementation of <tt>hashCode</tt>.
+ *
+ * Example use case:
+ *
+ * <pre>
+ * public int hashCode() {
+ *     int result = HashCodeUtil.SEED;
+ *     // collect the contributions of various fields
+ *     result = HashCodeUtil.hash(result, fPrimitive);
+ *     result = HashCodeUtil.hash(result, fObject);
+ *     result = HashCodeUtil.hash(result, fArray);
+ *     return result;
+ * }
+ * </pre>
+ */
+public final class HashCodeUtil {
+
+    /**
+     * An initial value for a <tt>hashCode</tt>, to which is added contributions
+     * from fields. Using a non-zero value decreases collisions of
+     * <tt>hashCode</tt> values.
+     */
+    public static final int SEED = 23;
+
+    /** booleans. */
+    public static int hash(int aSeed, boolean aBoolean) {
+        return firstTerm(aSeed) + (aBoolean ? 1 : 0);
+    }
+
+    /*** chars. */
+    public static int hash(int aSeed, char aChar) {
+        return firstTerm(aSeed) + aChar;
+    }
+
+    /** ints. */
+    public static int hash(int aSeed, int aInt) {
+        return firstTerm(aSeed) + aInt;
+    }
+
+    /** longs. */
+    public static int hash(int aSeed, long aLong) {
+        return firstTerm(aSeed) + (int) (aLong ^ (aLong >>> 32));
+    }
+
+    /** floats. */
+    public static int hash(int aSeed, float aFloat) {
+        return hash(aSeed, Float.floatToIntBits(aFloat));
+    }
+
+    /** doubles. */
+    public static int hash(int aSeed, double aDouble) {
+        return hash(aSeed, Double.doubleToLongBits(aDouble));
+    }
+
+    /**
+     * <tt>aObject</tt> is a possibly-null object field, and possibly an array.
+     *
+     * If <tt>aObject</tt> is an array, then each element may be a primitive or
+     * a possibly-null object.
+     */
+    public static int hash(int aSeed, Object aObject) {
+        int result = aSeed;
+        if (aObject == null) {
+            result = hash(result, 0);
+        } else if (!isArray(aObject)) {
+            result = hash(result, aObject.hashCode());
+        } else {
+            int length = Array.getLength(aObject);
+            for (int idx = 0; idx < length; ++idx) {
+                Object item = Array.get(aObject, idx);
+                // if an item in the array references the array itself, prevent
+                // infinite looping
+                if (!(item == aObject)) {
+                    result = hash(result, item);
+                }
+            }
+        }
+        return result;
+    }
+
+    // PRIVATE
+    private static final int fODD_PRIME_NUMBER = 37;
+
+    private static int firstTerm(int aSeed) {
+        return fODD_PRIME_NUMBER * aSeed;
+    }
+
+    private static boolean isArray(Object aObject) {
+        return aObject.getClass().isArray();
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/PasswordCredentialBuilder.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/PasswordCredentialBuilder.java
new file mode 100644
index 00000000..d8a2e87a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/PasswordCredentialBuilder.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import static org.opendaylight.aaa.EqualUtil.areEqual;
+import static org.opendaylight.aaa.HashCodeUtil.hash;
+
+import org.opendaylight.aaa.api.PasswordCredentials;
+
+/**
+ * {@link PasswordCredentials} builder.
+ *
+ * @author liemmn
+ *
+ */
+public class PasswordCredentialBuilder {
+    private final MutablePasswordCredentials pc = new MutablePasswordCredentials();
+
+    public PasswordCredentialBuilder setUserName(String username) {
+        pc.username = username;
+        return this;
+    }
+
+    public PasswordCredentialBuilder setPassword(String password) {
+        pc.password = password;
+        return this;
+    }
+
+    public PasswordCredentialBuilder setDomain(String domain) {
+        pc.domain = domain;
+        return this;
+    }
+
+    public PasswordCredentials build() {
+        return pc;
+    }
+
+    private static class MutablePasswordCredentials implements PasswordCredentials {
+        private int hashCode = 0;
+        private String username;
+        private String password;
+        private String domain;
+
+        @Override
+        public String username() {
+            return username;
+        }
+
+        @Override
+        public String password() {
+            return password;
+        }
+
+        @Override
+        public String domain() {
+            return domain;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof PasswordCredentials)) {
+                return false;
+            }
+            PasswordCredentials p = (PasswordCredentials) o;
+            return areEqual(username, p.username()) && areEqual(password, p.password());
+        }
+
+        @Override
+        public int hashCode() {
+            if (hashCode == 0) {
+                int result = HashCodeUtil.SEED;
+                result = hash(result, username);
+                result = hash(result, password);
+                hashCode = result;
+            }
+            return hashCode;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/SecureBlockingQueue.java b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/SecureBlockingQueue.java
new file mode 100644
index 00000000..3ded52da
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/java/org/opendaylight/aaa/SecureBlockingQueue.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.aaa.api.Authentication;
+
+/**
+ * A {@link BlockingQueue} decorator with injected security context.
+ *
+ * @author liemmn
+ *
+ * @param <T>
+ *            queue element type
+ */
+public class SecureBlockingQueue<T> implements BlockingQueue<T> {
+    private final BlockingQueue<SecureData<T>> queue;
+
+    /**
+     * Constructor.
+     *
+     * @param queue
+     *            blocking queue implementation to use
+     */
+    public SecureBlockingQueue(BlockingQueue<SecureData<T>> queue) {
+        this.queue = queue;
+    }
+
+    @Override
+    public T remove() {
+        return setAuth(queue.remove());
+    }
+
+    @Override
+    public T poll() {
+        return setAuth(queue.poll());
+    }
+
+    @Override
+    public T element() {
+        return setAuth(queue.element());
+    }
+
+    @Override
+    public T peek() {
+        return setAuth(queue.peek());
+    }
+
+    @Override
+    public int size() {
+        return queue.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return queue.isEmpty();
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return new Iterator<T>() {
+            Iterator<SecureData<T>> it = queue.iterator();
+
+            @Override
+            public boolean hasNext() {
+                return it.hasNext();
+            }
+
+            @Override
+            public T next() {
+                return it.next().data;
+            }
+
+            @Override
+            public void remove() {
+                it.remove();
+            }
+        };
+    }
+
+    @Override
+    public Object[] toArray() {
+        return toData().toArray();
+    }
+
+    @SuppressWarnings("hiding")
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return toData().toArray(a);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return toData().containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> c) {
+        return queue.addAll(fromData(c));
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        return queue.removeAll(fromData(c));
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        return queue.retainAll(fromData(c));
+    }
+
+    @Override
+    public void clear() {
+        queue.clear();
+    }
+
+    @Override
+    public boolean add(T e) {
+        return queue.add(new SecureData<>(e));
+    }
+
+    @Override
+    public boolean offer(T e) {
+        return queue.offer(new SecureData<>(e));
+    }
+
+    @Override
+    public void put(T e) throws InterruptedException {
+        queue.put(new SecureData<T>(e));
+    }
+
+    @Override
+    public boolean offer(T e, long timeout, TimeUnit unit) throws InterruptedException {
+        return queue.offer(new SecureData<>(e), timeout, unit);
+    }
+
+    @Override
+    public T take() throws InterruptedException {
+        return setAuth(queue.take());
+    }
+
+    @Override
+    public T poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return setAuth(queue.poll(timeout, unit));
+    }
+
+    @Override
+    public int remainingCapacity() {
+        return queue.remainingCapacity();
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        Iterator<SecureData<T>> it = queue.iterator();
+        while (it.hasNext()) {
+            SecureData<T> sd = it.next();
+            if (sd.data.equals(o)) {
+                return queue.remove(sd);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        Iterator<SecureData<T>> it = queue.iterator();
+        while (it.hasNext()) {
+            SecureData<T> sd = it.next();
+            if (sd.data.equals(o)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int drainTo(Collection<? super T> c) {
+        Collection<SecureData<T>> sd = new ArrayList<>();
+        int n = queue.drainTo(sd);
+        c.addAll(toData(sd));
+        return n;
+    }
+
+    @Override
+    public int drainTo(Collection<? super T> c, int maxElements) {
+        Collection<SecureData<T>> sd = new ArrayList<>();
+        int n = queue.drainTo(sd, maxElements);
+        c.addAll(toData(sd));
+        return n;
+    }
+
+    // Rehydrate security context
+    private T setAuth(SecureData<T> i) {
+        AuthenticationManager.instance().set(i.auth);
+        return i.data;
+    }
+
+    // Construct secure data collection from a plain old data collection
+    @SuppressWarnings("unchecked")
+    private Collection<SecureData<T>> fromData(Collection<?> c) {
+        Collection<SecureData<T>> sd = new ArrayList<>(c.size());
+        for (Object d : c) {
+            sd.add((SecureData<T>) new SecureData<>(d));
+        }
+        return sd;
+    }
+
+    // Extract the data portion out from the secure data
+    @SuppressWarnings("unchecked")
+    private Collection<T> toData() {
+        return toData(Arrays.<SecureData<T>> asList(queue.toArray(new SecureData[0])));
+    }
+
+    // Extract the data portion out from the secure data
+    private Collection<T> toData(Collection<SecureData<T>> secureData) {
+        Collection<T> data = new ArrayList<>(secureData.size());
+        Iterator<SecureData<T>> it = secureData.iterator();
+        while (it.hasNext()) {
+            data.add(it.next().data);
+        }
+        return data;
+    }
+
+    // Inject security context
+    public static final class SecureData<T> {
+        private final T data;
+        private final Authentication auth;
+
+        private SecureData(T data) {
+            this.data = data;
+            this.auth = AuthenticationManager.instance().get();
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        public boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            return (o instanceof SecureData) ? data.equals(((SecureData) o).data) : false;
+        }
+
+        @Override
+        public int hashCode() {
+            return data.hashCode();
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.properties b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 00000000..75537f6b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,12 @@
+org.opendaylight.aaa.authn.name = Opendaylight AAA Authentication Configuration
+org.opendaylight.aaa.authn.description = Configuration for AAA authorized clients
+org.opendaylight.aaa.authn.authorizedClients.name = Authorized Clients
+org.opendaylight.aaa.authn.authorizedClients.description = Space-delimited list of authorized \
+ clients, with client id and client password separated by a ':'. \
+ Example:  dlux:secrete <client_id:client_secret>
+org.opendaylight.aaa.authn.authEnabled.name = Enable authentication
+org.opendaylight.aaa.authn.authEnabled.description = Enable authentication by setting it \
+to the value 'true', or 'false' if bypassing authentication. \
+Note that bypassing authentication may result in your controller being more \
+vulnerable to unauthorized accesses.  Authorization, if enabled, will not work if \
+authentication is disabled.
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.xml b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.xml
new file mode 100644
index 00000000..10150587
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
+    localization="OSGI-INF/metatype/metatype">
+    <OCD id="org.opendaylight.aaa.authn" name="%org.opendaylight.aaa.authn.name"
+        description="%org.opendaylight.aaa.authn.description">
+        <AD id="authorizedClients" type="String" default="dlux:secrete"
+            name="%org.opendaylight.aaa.authn.authorizedClients.name"
+            description="%org.opendaylight.aaa.authn.authorizedClients.description" />
+        <AD id="authEnabled" type="String" default="true"
+            name="%org.opendaylight.aaa.authn.authEnabled.name"
+            description="%org.opendaylight.aaa.authn.authEnabled.description" />
+    </OCD>
+    <Designate pid="org.opendaylight.aaa.authn">
+        <Object ocdref="org.opendaylight.aaa.authn" />
+    </Designate>
+</metatype:MetaData>
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/main/resources/authn.cfg b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/authn.cfg
new file mode 100644
index 00000000..e7326f86
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/main/resources/authn.cfg
@@ -0,0 +1,2 @@
+authorizedClients=dlux:secrete
+authEnabled=true
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationBuilderTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationBuilderTest.java
new file mode 100644
index 00000000..2f69fe5b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationBuilderTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.Claim;
+
+public class AuthenticationBuilderTest {
+    private Set<String> roles = new LinkedHashSet<>(Arrays.asList("role1", "role2"));
+    private Claim validClaim = new ClaimBuilder().setDomain("aName").setUserId("1")
+            .setClientId("2222").setUser("bob").addRole("foo").addRoles(roles).build();
+
+    @Test
+    public void testBuildWithExpiration() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertEquals(1, a1.expiration());
+        assertEquals("aName", a1.domain());
+        assertEquals("1", a1.userId());
+        assertEquals("2222", a1.clientId());
+        assertEquals("bob", a1.user());
+        assertTrue(a1.roles().contains("foo"));
+        assertTrue(a1.roles().containsAll(roles));
+        assertEquals(3, a1.roles().size());
+        Authentication a2 = new AuthenticationBuilder(a1).build();
+        assertNotEquals(a1, a2);
+        Authentication a3 = new AuthenticationBuilder(a1).setExpiration(1).build();
+        assertEquals(a1, a3);
+    }
+
+    @Test
+    public void testBuildWithoutExpiration() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).build();
+        assertEquals(0, a1.expiration());
+        assertEquals("aName", a1.domain());
+        assertEquals("1", a1.userId());
+        assertEquals("2222", a1.clientId());
+        assertEquals("bob", a1.user());
+        assertTrue(a1.roles().contains("foo"));
+        assertTrue(a1.roles().containsAll(roles));
+        assertEquals(3, a1.roles().size());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithNegativeExpiration() {
+        AuthenticationBuilder a1 = new AuthenticationBuilder(validClaim).setExpiration(-1);
+        a1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithNullClaim() {
+        AuthenticationBuilder a1 = new AuthenticationBuilder(null);
+        a1.build();
+    }
+
+    @Test
+    public void testToString() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertEquals(
+                "expiration:1,clientId:2222,userId:1,userName:bob,domain:aName,roles:[foo, role1, role2]",
+                a1.toString());
+    }
+
+    @Test
+    public void testEquals() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertTrue(a1.equals(a1));
+        Authentication a2 = new AuthenticationBuilder(a1).setExpiration(1).build();
+        assertTrue(a1.equals(a2));
+        assertTrue(a2.equals(a1));
+        Authentication a3 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertTrue(a1.equals(a3));
+        assertTrue(a3.equals(a2));
+        assertTrue(a1.equals(a2));
+    }
+
+    @Test
+    public void testNotEquals() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertFalse(a1.equals(null));
+        assertFalse(a1.equals("wrong object"));
+        Authentication a2 = new AuthenticationBuilder(a1).build();
+        assertFalse(a1.equals(a2));
+        assertFalse(a2.equals(a1));
+        Authentication a3 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertFalse(a1.equals(a2));
+        assertTrue(a1.equals(a3));
+        assertFalse(a2.equals(a3));
+        Authentication a4 = new AuthenticationBuilder(validClaim).setExpiration(9).build();
+        assertFalse(a1.equals(a4));
+        assertFalse(a4.equals(a1));
+        Authentication a5 = new AuthenticationBuilder(a1).setExpiration(9).build();
+        assertFalse(a1.equals(a5));
+        assertFalse(a5.equals(a1));
+    }
+
+    @Test
+    public void testHashCode() {
+        Authentication a1 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertEquals(a1.hashCode(), a1.hashCode());
+        Authentication a2 = new AuthenticationBuilder(a1).setExpiration(1).build();
+        assertTrue(a1.equals(a2));
+        assertEquals(a1.hashCode(), a2.hashCode());
+        Authentication a3 = new AuthenticationBuilder(validClaim).setExpiration(1).build();
+        assertTrue(a1.equals(a3));
+        assertEquals(a1.hashCode(), a3.hashCode());
+        assertEquals(a2.hashCode(), a3.hashCode());
+        Authentication a4 = new AuthenticationBuilder(a1).setExpiration(9).build();
+        assertFalse(a1.equals(a4));
+        assertNotEquals(a1.hashCode(), a4.hashCode());
+        Authentication a5 = new AuthenticationBuilder(a1).build();
+        assertFalse(a1.equals(a5));
+        assertNotEquals(a1.hashCode(), a5.hashCode());
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationManagerTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationManagerTest.java
new file mode 100644
index 00000000..540df287
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/AuthenticationManagerTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Test;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.osgi.service.cm.ConfigurationException;
+
+public class AuthenticationManagerTest {
+    @Test
+    public void testAuthenticationCrudSameThread() {
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUser("Bob")
+                .setUserId("1234").addRole("admin").addRole("guest").build()).build();
+        AuthenticationService as = AuthenticationManager.instance();
+
+        assertNotNull(as);
+
+        as.set(auth);
+        assertEquals(auth, as.get());
+
+        as.clear();
+        assertNull(as.get());
+    }
+
+    @Test
+    public void testAuthenticationCrudSpawnedThread() throws InterruptedException,
+            ExecutionException {
+        AuthenticationService as = AuthenticationManager.instance();
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUser("Bob")
+                .setUserId("1234").addRole("admin").addRole("guest").build()).build();
+
+        as.set(auth);
+        Future<Authentication> f = Executors.newSingleThreadExecutor().submit(new Worker());
+        assertEquals(auth, f.get());
+
+        as.clear();
+        f = Executors.newSingleThreadExecutor().submit(new Worker());
+        assertNull(f.get());
+    }
+
+    @Test
+    public void testAuthenticationCrudSpawnedThreadPool() throws InterruptedException,
+            ExecutionException {
+        AuthenticationService as = AuthenticationManager.instance();
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUser("Bob")
+                .setUserId("1234").addRole("admin").addRole("guest").build()).build();
+
+        as.set(auth);
+        List<Future<Authentication>> fs = Executors.newFixedThreadPool(2).invokeAll(
+                Arrays.asList(new Worker(), new Worker()));
+        for (Future<Authentication> f : fs) {
+            assertEquals(auth, f.get());
+        }
+
+        as.clear();
+        fs = Executors.newFixedThreadPool(2).invokeAll(Arrays.asList(new Worker(), new Worker()));
+        for (Future<Authentication> f : fs) {
+            assertNull(f.get());
+        }
+    }
+
+    @Test
+    public void testUpdatedValid() throws ConfigurationException {
+        Dictionary<String, String> props = new Hashtable<>();
+        AuthenticationManager as = AuthenticationManager.instance();
+
+        assertFalse(as.isAuthEnabled());
+
+        props.put(AuthenticationManager.AUTH_ENABLED, "TrUe");
+        as.updated(props);
+        assertTrue(as.isAuthEnabled());
+
+        props.put(AuthenticationManager.AUTH_ENABLED, "FaLsE");
+        as.updated(props);
+        assertFalse(as.isAuthEnabled());
+    }
+
+    @Test
+    public void testUpdatedNullProperty() throws ConfigurationException {
+        AuthenticationManager as = AuthenticationManager.instance();
+
+        assertFalse(as.isAuthEnabled());
+        as.updated(null);
+        assertFalse(as.isAuthEnabled());
+    }
+
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedInvalidValue() throws ConfigurationException {
+        AuthenticationManager as = AuthenticationManager.instance();
+        Dictionary<String, String> props = new Hashtable<>();
+
+        props.put(AuthenticationManager.AUTH_ENABLED, "yes");
+        as.updated(props);
+    }
+
+    @Test(expected = ConfigurationException.class)
+    public void testUpdatedInvalidKey() throws ConfigurationException {
+        AuthenticationManager as = AuthenticationManager.instance();
+        Dictionary<String, String> props = new Hashtable<>();
+
+        props.put("Invalid Key", "true");
+        as.updated(props);
+    }
+
+    private class Worker implements Callable<Authentication> {
+        @Override
+        public Authentication call() throws Exception {
+            AuthenticationService as = AuthenticationManager.instance();
+            return as.get();
+        }
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClaimBuilderTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClaimBuilderTest.java
new file mode 100644
index 00000000..372eb6d2
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClaimBuilderTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import org.junit.Test;
+import org.opendaylight.aaa.api.Claim;
+
+/**
+ *
+ * @author liemmn
+ *
+ */
+public class ClaimBuilderTest {
+    @Test
+    public void testBuildWithAll() {
+        Claim c1 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").addRole("foo2")
+                .addRoles(new HashSet<>(Arrays.asList("foo", "bar"))).build();
+        assertEquals("dlux", c1.clientId());
+        assertEquals("pepsi", c1.domain());
+        assertEquals("john", c1.user());
+        assertEquals("1234", c1.userId());
+        assertTrue(c1.roles().contains("foo"));
+        assertTrue(c1.roles().contains("foo2"));
+        assertTrue(c1.roles().contains("bar"));
+        assertEquals(3, c1.roles().size());
+        Claim c2 = new ClaimBuilder(c1).build();
+        assertEquals(c1, c2);
+    }
+
+    @Test
+    public void testBuildWithRequired() {
+        Claim c1 = new ClaimBuilder().setUser("john").setUserId("1234").addRole("foo").build();
+        assertEquals("john", c1.user());
+        assertEquals("1234", c1.userId());
+        assertTrue(c1.roles().contains("foo"));
+        assertEquals(1, c1.roles().size());
+        assertEquals("", c1.domain());
+        assertEquals("", c1.clientId());
+    }
+
+    @Test
+    public void testBuildWithEmptyOptional() {
+        Claim c1 = new ClaimBuilder().setDomain("  ").setClientId("  ").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertEquals("", c1.domain());
+        assertEquals("", c1.clientId());
+        assertEquals("john", c1.user());
+        assertEquals("1234", c1.userId());
+        assertTrue(c1.roles().contains("foo"));
+        assertEquals(1, c1.roles().size());
+    }
+
+    @Test
+    public void testBuildWithNullOptional() {
+        Claim c1 = new ClaimBuilder().setDomain(null).setClientId(null).setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertEquals("", c1.domain());
+        assertEquals("", c1.clientId());
+        assertEquals("john", c1.user());
+        assertEquals("1234", c1.userId());
+        assertTrue(c1.roles().contains("foo"));
+        assertEquals(1, c1.roles().size());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithDefault() {
+        ClaimBuilder c1 = new ClaimBuilder();
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithoutUser() {
+        ClaimBuilder c1 = new ClaimBuilder().setUserId("1234").addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithNullUser() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser(null).setUserId("1234").addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithEmptyUser() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("  ").setUserId("1234").addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithoutUserId() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithNullUserId() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").setUserId(null).addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithEmptyUserId() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").setUserId("  ").addRole("foo");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithoutRole() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").setUserId("1234");
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithNullRole() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").setUserId("1234").addRole(null);
+        c1.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuildWithEmptyRole() {
+        ClaimBuilder c1 = new ClaimBuilder().setUser("john").setUserId("1234").addRole("  ");
+        c1.build();
+    }
+
+    @Test
+    public void testEquals() {
+        Claim c1 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertTrue(c1.equals(c1));
+        Claim c2 = new ClaimBuilder(c1).addRole("foo").build();
+        assertTrue(c1.equals(c2));
+        assertTrue(c2.equals(c1));
+        Claim c3 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertTrue(c1.equals(c3));
+        assertTrue(c3.equals(c2));
+        assertTrue(c1.equals(c2));
+    }
+
+    @Test
+    public void testNotEquals() {
+        Claim c1 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertFalse(c1.equals(null));
+        assertFalse(c1.equals("wrong object"));
+        Claim c2 = new ClaimBuilder(c1).addRoles(new HashSet<>(Arrays.asList("foo", "bar")))
+                .build();
+        assertEquals(2, c2.roles().size());
+        assertFalse(c1.equals(c2));
+        assertFalse(c2.equals(c1));
+        Claim c3 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertFalse(c1.equals(c2));
+        assertTrue(c1.equals(c3));
+        assertFalse(c2.equals(c3));
+        Claim c5 = new ClaimBuilder().setUser("john").setUserId("1234").addRole("foo").build();
+        assertFalse(c1.equals(c5));
+        assertFalse(c5.equals(c1));
+    }
+
+    @Test
+    public void testHash() {
+        Claim c1 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertEquals(c1.hashCode(), c1.hashCode());
+        Claim c2 = new ClaimBuilder(c1).addRole("foo").build();
+        assertTrue(c1.equals(c2));
+        assertEquals(c1.hashCode(), c2.hashCode());
+        Claim c3 = new ClaimBuilder(c1).addRoles(new HashSet<>(Arrays.asList("foo", "bar")))
+                .build();
+        assertFalse(c1.equals(c3));
+        assertNotEquals(c1.hashCode(), c3.hashCode());
+        Claim c4 = new ClaimBuilder().setClientId("dlux").setDomain("pepsi").setUser("john")
+                .setUserId("1234").addRole("foo").build();
+        assertTrue(c1.equals(c4));
+        assertEquals(c1.hashCode(), c4.hashCode());
+        assertEquals(c2.hashCode(), c4.hashCode());
+        Claim c5 = new ClaimBuilder().setUser("john").setUserId("1234").addRole("foo").build();
+        assertFalse(c1.equals(c5));
+        assertNotEquals(c1.hashCode(), c5.hashCode());
+    }
+
+    @Test
+    public void testToString() {
+        Claim c1 = new ClaimBuilder().setUser("john").setUserId("1234").addRole("foo").build();
+        assertEquals("clientId:,userId:1234,userName:john,domain:,roles:[foo]", c1.toString());
+        c1 = new ClaimBuilder(c1).setClientId("dlux").setDomain("pepsi").build();
+        assertEquals("clientId:dlux,userId:1234,userName:john,domain:pepsi,roles:[foo]",
+                c1.toString());
+        c1 = new ClaimBuilder(c1).addRole("bar").build();
+        assertEquals("clientId:dlux,userId:1234,userName:john,domain:pepsi,roles:[foo, bar]",
+                c1.toString());
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClientManagerTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClientManagerTest.java
new file mode 100644
index 00000000..059ba9a3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/ClientManagerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.fail;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.osgi.service.cm.ConfigurationException;
+
+/**
+ *
+ * @author liemmn
+ *
+ */
+public class ClientManagerTest {
+    private static final ClientManager cm = new ClientManager();
+
+    @Before
+    public void setup() throws ConfigurationException {
+        cm.init(null);
+    }
+
+    @Test
+    public void testValidate() {
+        cm.validate("dlux", "secrete");
+    }
+
+    @Test(expected = AuthenticationException.class)
+    public void testFailValidate() {
+        cm.validate("dlux", "what?");
+    }
+
+    @Test
+    public void testUpdate() throws ConfigurationException {
+        Dictionary<String, String> configs = new Hashtable<>();
+        configs.put(ClientManager.CLIENTS, "aws:amazon dlux:xxx");
+        cm.updated(configs);
+        cm.validate("aws", "amazon");
+        cm.validate("dlux", "xxx");
+    }
+
+    @Test
+    public void testFailUpdate() {
+        Dictionary<String, String> configs = new Hashtable<>();
+        configs.put(ClientManager.CLIENTS, "aws:amazon dlux");
+        try {
+            cm.updated(configs);
+            fail("Shoulda failed updating bad configuration");
+        } catch (ConfigurationException ce) {
+            // Expected
+        }
+        cm.validate("dlux", "secrete");
+        try {
+            cm.validate("aws", "amazon");
+            fail("Shoulda failed updating bad configuration");
+        } catch (AuthenticationException ae) {
+            // Expected
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/PasswordCredentialTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/PasswordCredentialTest.java
new file mode 100644
index 00000000..2dabb77b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/PasswordCredentialTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashSet;
+import org.junit.Test;
+import org.opendaylight.aaa.api.PasswordCredentials;
+
+public class PasswordCredentialTest {
+
+    @Test
+    public void testBuilder() {
+        PasswordCredentials pc1 = new PasswordCredentialBuilder().setUserName("bob")
+                .setPassword("secrete").build();
+        assertEquals("bob", pc1.username());
+        assertEquals("secrete", pc1.password());
+
+        PasswordCredentials pc2 = new PasswordCredentialBuilder().setUserName("bob")
+                .setPassword("secrete").build();
+        assertEquals(pc1, pc2);
+
+        PasswordCredentials pc3 = new PasswordCredentialBuilder().setUserName("bob")
+                .setPassword("secret").build();
+        HashSet<PasswordCredentials> pcs = new HashSet<>();
+        pcs.add(pc1);
+        pcs.add(pc2);
+        pcs.add(pc3);
+        assertEquals(2, pcs.size());
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/SecureBlockingQueueTest.java b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/SecureBlockingQueueTest.java
new file mode 100644
index 00000000..16627d9f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authn/src/test/java/org/opendaylight/aaa/SecureBlockingQueueTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.aaa.SecureBlockingQueue.SecureData;
+import org.opendaylight.aaa.api.Authentication;
+
+public class SecureBlockingQueueTest {
+    private final int MAX_TASKS = 100;
+
+    @Before
+    public void setup() {
+        AuthenticationManager.instance().clear();
+    }
+
+    @Test
+    public void testSecureThreadPoolExecutor() throws InterruptedException, ExecutionException {
+        BlockingQueue<Runnable> queue = new SecureBlockingQueue<>(
+                new ArrayBlockingQueue<SecureData<Runnable>>(10));
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 500, TimeUnit.MILLISECONDS,
+                queue);
+        executor.prestartAllCoreThreads();
+        for (int cnt = 1; cnt <= MAX_TASKS; cnt++) {
+            assertEquals(Integer.toString(cnt),
+                    executor.submit(new Task(Integer.toString(cnt), "1111", "user")).get().user());
+        }
+        executor.shutdown();
+    }
+
+    @Test
+    public void testNormalThreadPoolExecutor() throws InterruptedException, ExecutionException {
+        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10);
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 500, TimeUnit.MILLISECONDS,
+                queue);
+        executor.prestartAllCoreThreads();
+        for (int cnt = 1; cnt <= MAX_TASKS; cnt++) {
+            assertNull(executor.submit(new Task(Integer.toString(cnt), "1111", "user")).get());
+        }
+        executor.shutdown();
+    }
+
+    @Test
+    public void testQueueOps() throws InterruptedException, ExecutionException {
+        BlockingQueue<String> queue = new SecureBlockingQueue<>(
+                new ArrayBlockingQueue<SecureData<String>>(3));
+        ExecutorService es = Executors.newFixedThreadPool(3);
+        es.submit(new Producer("foo", "1111", "user", queue)).get();
+        assertEquals(1, queue.size());
+        assertEquals("foo", es.submit(new Consumer(queue)).get());
+        es.submit(new Producer("bar", "2222", "user", queue)).get();
+        assertEquals("bar", queue.peek());
+        assertEquals("bar", queue.element());
+        assertEquals(1, queue.size());
+        assertEquals("bar", queue.poll());
+        assertTrue(queue.isEmpty());
+        es.shutdown();
+    }
+
+    @Test
+    public void testCollectionOps() throws InterruptedException, ExecutionException {
+        BlockingQueue<String> queue = new SecureBlockingQueue<>(
+                new ArrayBlockingQueue<SecureData<String>>(6));
+        for (int i = 1; i <= 3; i++)
+            queue.add("User" + i);
+        Iterator<String> it = queue.iterator();
+        while (it.hasNext())
+            assertTrue(it.next().startsWith("User"));
+        assertEquals(3, queue.toArray().length);
+        List<String> actual = Arrays.asList(queue.toArray(new String[0]));
+        assertEquals("User1", actual.iterator().next());
+        assertTrue(queue.containsAll(actual));
+        queue.addAll(actual);
+        assertEquals(6, queue.size());
+        queue.retainAll(Arrays.asList(new String[] { "User2" }));
+        assertEquals(2, queue.size());
+        assertEquals("User2", queue.iterator().next());
+        queue.removeAll(actual);
+        assertTrue(queue.isEmpty());
+        queue.add("hello");
+        assertEquals(1, queue.size());
+        queue.clear();
+        assertTrue(queue.isEmpty());
+    }
+
+    @Test
+    public void testBlockingQueueOps() throws InterruptedException {
+        BlockingQueue<String> queue = new SecureBlockingQueue<>(
+                new ArrayBlockingQueue<SecureData<String>>(3));
+        queue.offer("foo");
+        assertEquals(1, queue.size());
+        queue.offer("bar", 500, TimeUnit.MILLISECONDS);
+        assertEquals(2, queue.size());
+        assertEquals("foo", queue.poll());
+        assertTrue(queue.contains("bar"));
+        queue.remove("bar");
+        assertEquals(3, queue.remainingCapacity());
+        queue.addAll(Arrays.asList(new String[] { "foo", "bar", "tom" }));
+        assertEquals(3, queue.size());
+        assertEquals("foo", queue.poll(500, TimeUnit.MILLISECONDS));
+        assertEquals(2, queue.size());
+        List<String> drain = new LinkedList<>();
+        queue.drainTo(drain);
+        assertTrue(queue.isEmpty());
+        assertEquals(2, drain.size());
+        queue.addAll(Arrays.asList(new String[] { "foo", "bar", "tom" }));
+        drain.clear();
+        queue.drainTo(drain, 1);
+        assertEquals(2, queue.size());
+        assertEquals(1, drain.size());
+    }
+
+    // Task to run in a ThreadPoolExecutor
+    private class Task implements Callable<Authentication> {
+        Task(String name, String userId, String role) {
+            // Mock that each task has its original authentication context
+            AuthenticationManager.instance().set(
+                    new AuthenticationBuilder(new ClaimBuilder().setUser(name).setUserId(userId)
+                            .addRole(role).build()).build());
+        }
+
+        @Override
+        public Authentication call() throws Exception {
+            return AuthenticationManager.instance().get();
+        }
+    }
+
+    // Producer sets auth context
+    private class Producer implements Callable<String> {
+        private final String name;
+        private final String userId;
+        private final String role;
+        private final BlockingQueue<String> queue;
+
+        Producer(String name, String userId, String role, BlockingQueue<String> queue) {
+            this.name = name;
+            this.userId = userId;
+            this.role = role;
+            this.queue = queue;
+        }
+
+        @Override
+        public String call() throws InterruptedException {
+            AuthenticationManager.instance().set(
+                    new AuthenticationBuilder(new ClaimBuilder().setUser(name).setUserId(userId)
+                            .addRole(role).build()).build());
+            queue.put(name);
+            return name;
+        }
+    }
+
+    // Consumer gets producer's auth context via data element in queue
+    private class Consumer implements Callable<String> {
+        private final BlockingQueue<String> queue;
+
+        Consumer(BlockingQueue<String> queue) {
+            this.queue = queue;
+        }
+
+        @Override
+        public String call() {
+            queue.remove();
+            Authentication auth = AuthenticationManager.instance().get();
+            return (auth == null) ? null : auth.user();
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/pom.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/pom.xml
new file mode 100644
index 00000000..42237e41
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>authz-service-config</artifactId>
+    <description>AuthZ Service Configuration files </description>
+    <packaging>jar</packaging>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/initial/${config.authz.service.configfile}</file>
+                                    <type>xml</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/src/main/resources/initial/08-authz-config.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/src/main/resources/initial/08-authz-config.xml
new file mode 100644
index 00000000..5b59ca20
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-config/src/main/resources/initial/08-authz-config.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+                <!-- defines an implementation module -->
+                <module>
+                    <type xmlns:authz="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">authz:aaa-authz-service</type>
+                    <name>aaa-authz-service</name>
+
+                    <dom-broker>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                        <name>dom-broker</name>
+                    </dom-broker>
+
+                    <data-broker>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                        <name>binding-data-broker</name>
+                    </data-broker>
+
+                    <policies xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">
+                        <service xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">RestConfService</service>
+                        <action xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">Any</action>
+                        <resource xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">*</resource>
+                        <role xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv">admin</role>
+                    </policies>
+
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                    <instance>
+                        <name>authz-connector-default</name>
+                        <provider>
+                            /modules/module[type='aaa-authz-service'][name='aaa-authz-service']
+                        </provider>
+                    </instance>
+                </service>
+            </services>
+
+        </data>
+
+
+    </configuration>
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv?module=aaa-authz-service-impl&amp;revision=2014-07-01</capability>
+    </required-capabilities>
+
+</snapshot>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/pom.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/pom.xml
new file mode 100644
index 00000000..ee6108bd
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authz-model</artifactId>
+    <name>${project.artifactId}</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>yang-ext</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <stylesheet>maven</stylesheet>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>aggregate</goal>
+                        </goals>
+                        <phase>site</phase>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+    <packaging>bundle</packaging>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/src/main/yang/authorization-schema.yang b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/src/main/yang/authorization-schema.yang
new file mode 100644
index 00000000..2e0cf9cb
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-model/src/main/yang/authorization-schema.yang
@@ -0,0 +1,190 @@
+module authorization-schema {
+  yang-version 1;
+  namespace "urn:aaa:yang:authz:ds";
+  prefix "authz";
+  organization "TBD";
+
+  contact "wdec@cisco.com";
+
+  revision 2014-07-22 {
+    description
+      "Initial revision.";
+  }
+
+  //Main module begins
+
+  //TODO: Refactor service type as URI
+
+  //Define the servicetype; Service is used to identify the requestors' name, which would correspond to an ODL component eg Restconf. Possibly
+  //the naming will derive from the OSGi bundle name of the AuthZ requesting party.
+
+  typedef service-type {
+    type string;
+  }
+
+  //Resource denotes the actual resource that is the subject of the AuthZ request.
+
+  typedef resource-type {
+    type string;
+    default "*";
+
+    //Examples of resources:
+    //Data : /operational/opendaylight-inventory:nodes/node/openflow:1/node-connector/openflow:1:1
+    //Wildcarded data: /operational/opendaylight-inventory:nodes/node/*/node-connector/*
+    //RPC: /operations/example-ops:reboot
+    //Wildcarded RPC: /operations/example-ops:*
+    //Notification: /notifications/example-ops:startup
+  }
+
+  //Role denotes the normalized role that is attributed to the AuthZ requestor, eg "admin"
+
+  typedef role-type {
+    type string;
+  }
+
+  //Domain denotes the customer domain that is the attributed of the AuthZ requestor, eg cisco.com
+
+  typedef domain-type {
+    type string;
+  }
+
+  //Action denotes the requested AuthZ action on the resource
+  //TODO: Refactor as identities to allow for augmentation.
+
+  typedef action-type {
+    type enumeration {
+      enum put;
+      enum commit;
+      enum exists;
+      enum getIdentifier;
+      enum read;
+      enum cancel;
+      enum submit;
+      enum delete;
+      enum merge;
+      enum any;
+    }
+    default "any";
+  }
+
+  typedef authorization-response-type {
+    type enumeration {
+        enum not-authorized { value 0; }
+        enum authorized { value 1; }
+    }
+  }
+
+  typedef authorization-duration-type {
+    type uint32;
+  }
+
+  // Following grouping is the core AuthZ policy permissions data-structure, dual keyed by service and action.
+  // Permissions will be set-up per application. NOTE: Group and role can be equivalent. do we need both?
+
+  grouping authorization-grp {
+    list policies {
+      key "service";
+      leaf service {
+        type service-type;
+      }
+      leaf action {
+        type action-type;
+      }
+      leaf resource {
+        type resource-type;
+        mandatory true;
+      }
+      leaf role {
+        type role-type;
+        mandatory true;
+      }
+      leaf authorization {
+        type authorization-response-type;
+      }
+    }
+  }
+
+  // Following container provides the simple, non-domain specific AuthZ policy data-structure, dual keyed by service and action.
+
+  container simple-authorization {
+    uses authorization-grp;
+  }
+
+  // Following container provides the domain AuthZ policy data-structure. Each Policy is extended with a authz-domain-chain,
+  // which contains a prioritized list of the leafrefs to additional domain policies that also apply to this domain.
+  // The construct allows the chaining of policies like foo.com -> customer.sp.com -> customer.carrier.com.
+
+
+  container domain-authorization {
+    list domains {
+      key "domain-name";
+      leaf domain-name {
+        type domain-type;
+      }
+      uses authorization-grp;
+      list authz-domain-chain {
+        key "priority";
+        leaf priority {
+        type uint32;
+      }
+      leaf domain-name {
+        type leafref  {
+          path "/additional-domain-authz/domains/domain-name";
+        }
+      }
+    }
+  }
+}
+
+container additional-domain-authz {
+  list domains {
+    key "domain-name";
+    leaf domain-name {
+      type domain-type;
+       }
+      uses authorization-grp;
+     }
+  }
+
+
+
+  /* The following is the AuthZ RPC definition */
+
+  rpc req-authorization {
+    description
+      "Check Authorization for a given combination of action and role.
+      A not-authorized  will be returned if unsuccessful.";
+
+    input {
+      leaf domain-name {
+        type domain-type;
+      }
+      leaf service {
+        type service-type;
+      }
+      leaf action {
+        type action-type;
+        mandatory true;
+      }
+
+      leaf resource {
+        type resource-type;
+        mandatory true;
+      }
+      leaf role {
+        type role-type;
+        mandatory true;
+      }
+
+    }
+
+    output {
+
+      leaf authorization-response {
+        type authorization-response-type;
+        mandatory true;
+      }
+
+    }
+  }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/pom.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/pom.xml
new file mode 100644
index 00000000..6104be4b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>authz-restconf-config</artifactId>
+
+    <description>AuthZ Restconf Connector Configuration file </description>
+    <packaging>jar</packaging>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/initial/${config.restconf.configfile}</file>
+                                    <type>xml</type>
+                                     <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/src/main/resources/initial/09-rest-connector.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/src/main/resources/initial/09-rest-connector.xml
new file mode 100644
index 00000000..deba6558
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-restconf-config/src/main/resources/initial/09-rest-connector.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v1.0 which accompanies this distribution,
+and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+                <module>
+                    <type xmlns:rest="urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector">rest:rest-connector-impl</type>
+                    <name>rest-connector-default-impl</name>
+                    <websocket-port>8185</websocket-port>
+                    <dom-broker>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                        <name>authz-connector-default</name>
+                    </dom-broker>
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:rest="urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector">rest:rest-connector</type>
+                    <instance>
+                        <name>rest-connector-default</name>
+                        <provider>
+                            /modules/module[type='rest-connector-impl'][name='rest-connector-default-impl']
+                        </provider>
+                    </instance>
+                </service>
+            </services>
+
+        </data>
+    </configuration>
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector?module=opendaylight-rest-connector&amp;revision=2014-07-24</capability>
+    </required-capabilities>
+</snapshot>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/pom.xml b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/pom.xml
new file mode 100644
index 00000000..2c150ce7
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/pom.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+    ~ ~ This program and the accompanying materials are made available under
+    the ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+    ~ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>aaa-authz-service</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authz-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-core-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-core-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>jaxrs-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <!-- <Bundle-Activator>org.opendaylight.aaa.authz.srv.AuthzProvider</Bundle-Activator> -->
+                        <Export-Package>org.opendaylight.aaa.config.yang.aaa_srv,</Export-Package>
+                    </instructions>
+                </configuration>
+                <!-- <configuration> <Export-Package> </Export-Package> </configuration> -->
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java
new file mode 100644
index 00000000..d4ac79af
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import java.util.Collection;
+
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Created by wdec on 26/08/2014.
+ */
+public class AuthzBrokerImpl implements Broker, AutoCloseable, Provider {
+
+    private Broker broker;
+    private ProviderSession providerSession;
+    private AuthenticationService authenticationService;
+
+    public void setBroker(Broker broker) {
+        this.broker = broker;
+    }
+
+    @Override
+    public void close() throws Exception {
+
+    }
+
+    // Implements AuthzBroker handling of registering consumers or providers.
+    @Override
+    public ConsumerSession registerConsumer(Consumer consumer) {
+
+        ConsumerSession realSession = broker.registerConsumer(new ConsumerWrapper(consumer));
+        AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl(realSession,
+                this);
+        consumer.onSessionInitiated(authzConsumerContext);
+        return authzConsumerContext;
+    }
+
+    @Override
+    public ConsumerSession registerConsumer(Consumer consumer, BundleContext bundleContext) {
+
+        ConsumerSession realSession = broker.registerConsumer(new ConsumerWrapper(consumer),
+                bundleContext);
+        AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl(realSession,
+                this);
+        consumer.onSessionInitiated(authzConsumerContext);
+        return authzConsumerContext;
+    }
+
+    @Override
+    public ProviderSession registerProvider(Provider provider) {
+
+        ProviderSession realSession = broker.registerProvider(new ProviderWrapper(provider));
+        AuthzProviderContextImpl authzProviderContext = new AuthzProviderContextImpl(realSession,
+                this);
+        provider.onSessionInitiated(authzProviderContext);
+        return authzProviderContext;
+    }
+
+    @Override
+    public ProviderSession registerProvider(Provider provider, BundleContext bundleContext) {
+
+        // Allow the real broker to do its thing, while providing a wrapped
+        // callback
+        ProviderSession realSession = broker.registerProvider(new ProviderWrapper(provider),
+                bundleContext);
+
+        // Create Authz ProviderContext
+        AuthzProviderContextImpl authzProviderContext = new AuthzProviderContextImpl(realSession,
+                this);
+
+        // Run onsessionInitiated on injected provider with the AuthZ provider
+        // context.
+        provider.onSessionInitiated(authzProviderContext);
+        return authzProviderContext;
+
+    }
+
+    // Handle the AuthZBroker registration with the real broker
+    @Override
+    public void onSessionInitiated(ProviderSession providerSession) {
+
+        // Get now the real DOMDataBroker and register it with the
+        // AuthzDOMBroker together with the provider session
+        final DOMDataBroker domDataBroker = providerSession.getService(DOMDataBroker.class);
+        AuthzDomDataBroker.getInstance().setProviderSession(providerSession);
+        AuthzDomDataBroker.getInstance().setDomDataBroker(domDataBroker);
+        AuthzDomDataBroker.getInstance().setAuthService(this.authenticationService);
+    }
+
+    @Override
+    public Collection<ProviderFunctionality> getProviderFunctionality() {
+        return null;
+    }
+
+    public void setAuthenticationService(AuthenticationService authenticationService) {
+        this.authenticationService = authenticationService;
+    }
+
+    // Wrapper for Provider
+
+    public static class ProviderWrapper implements Provider {
+        private final Provider provider;
+
+        public ProviderWrapper(Provider provider) {
+            this.provider = provider;
+        }
+
+        @Override
+        public void onSessionInitiated(ProviderSession providerSession) {
+            // Do a Noop when the real broker calls back
+        }
+
+        @Override
+        public Collection<ProviderFunctionality> getProviderFunctionality() {
+            // Allow the RestconfImpl to respond to this
+            return provider.getProviderFunctionality();
+        }
+    }
+
+    // Wrapper for Consumer
+    public static class ConsumerWrapper implements Consumer {
+
+        private final Consumer consumer;
+
+        public ConsumerWrapper(Consumer consumer) {
+            this.consumer = consumer;
+        }
+
+        @Override
+        public void onSessionInitiated(ConsumerSession consumerSession) {
+            // Do a Noop when the real broker calls back
+        }
+
+        @Override
+        public Collection<ConsumerFunctionality> getConsumerFunctionality() {
+            return consumer.getConsumerFunctionality();
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java
new file mode 100644
index 00000000..07ba51cd
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.spi.ForwardingConsumerSession;
+
+/**
+ * Created by wdec on 28/08/2014.
+ */
+public class AuthzConsumerContextImpl extends ForwardingConsumerSession {
+
+    private final Broker.ConsumerSession realSession;
+
+    public AuthzConsumerContextImpl(Broker.ConsumerSession realSession, AuthzBrokerImpl authzBroker) {
+        this.realSession = realSession;
+    }
+
+    @Override
+    protected ConsumerSession delegate() {
+        return realSession;
+    }
+
+    @Override
+    public <T extends BrokerService> T getService(Class<T> tClass) {
+        T t;
+        // Check for class and return Authz broker only for DOMBroker
+        if (tClass == DOMDataBroker.class) {
+            t = (T) AuthzDomDataBroker.getInstance();
+        } else {
+            t = realSession.getService(tClass);
+        }
+        // AuthzDomDataBroker.getInstance().setDomDataBroker((DOMDataBroker)t);
+        return t;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java
new file mode 100644
index 00000000..4cc232bc
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Created by wdec on 26/08/2014.
+ */
+public class AuthzDataReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+    private final DOMDataReadWriteTransaction domDataReadWriteTransaction;
+
+    public AuthzDataReadWriteTransaction(DOMDataReadWriteTransaction domDataReadWriteTransaction) {
+        this.domDataReadWriteTransaction = domDataReadWriteTransaction;
+    }
+
+    @Override
+    public boolean cancel() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Cancel)) {
+            return domDataReadWriteTransaction.cancel();
+        }
+        return false;
+    }
+
+    @Override
+    public void delete(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Delete)) {
+            domDataReadWriteTransaction.delete(logicalDatastoreType, yangInstanceIdentifier);
+        }
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Submit)) {
+            return domDataReadWriteTransaction.submit();
+        }
+        TransactionCommitFailedException e = new TransactionCommitFailedException(
+                "Unauthorized User");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Deprecated
+    @Override
+    public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Commit)) {
+            return domDataReadWriteTransaction.commit();
+        }
+        TransactionCommitFailedException e = new TransactionCommitFailedException(
+                "Unauthorized User");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+            LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Read)) {
+            return domDataReadWriteTransaction.read(logicalDatastoreType, yangInstanceIdentifier);
+        }
+        ReadFailedException e = new ReadFailedException("Authorization Failed");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public CheckedFuture<Boolean, ReadFailedException> exists(
+            LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Exists)) {
+            return domDataReadWriteTransaction.exists(logicalDatastoreType, yangInstanceIdentifier);
+        }
+        ReadFailedException e = new ReadFailedException("Authorization Failed");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public void put(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Put)) {
+            domDataReadWriteTransaction.put(logicalDatastoreType, yangInstanceIdentifier,
+                    normalizedNode);
+        }
+    }
+
+    @Override
+    public void merge(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Merge)) {
+            domDataReadWriteTransaction.merge(logicalDatastoreType, yangInstanceIdentifier,
+                    normalizedNode);
+        }
+    }
+
+    @Override
+    public Object getIdentifier() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) {
+            return domDataReadWriteTransaction.getIdentifier();
+        }
+        return null;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java
new file mode 100644
index 00000000..911f5a48
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import java.util.Map;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+/**
+ * Created by wdec on 26/08/2014.
+ */
+public class AuthzDomDataBroker implements BrokerService, DOMDataBroker {
+
+    private DOMDataBroker domDataBroker;
+    private Broker.ProviderSession providerSession;
+
+    private volatile AuthenticationService authService;
+
+    final static AuthzDomDataBroker INSTANCE = new AuthzDomDataBroker();
+
+    public static AuthzDomDataBroker getInstance() {
+        return INSTANCE;
+    }
+
+    public void setDomDataBroker(DOMDataBroker domDataBroker) {
+        this.domDataBroker = domDataBroker;
+    }
+
+    public void setProviderSession(Broker.ProviderSession providerSession) {
+        this.providerSession = providerSession;
+    }
+
+    public void setAuthService(AuthenticationService authService) {
+        this.authService = authService;
+    }
+
+    public AuthenticationService getAuthService() {
+        return this.authService;
+    }
+
+    @Override
+    public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+        // new Authz transaction + inject real DOM Transaction
+        DOMDataReadOnlyTransaction ro = domDataBroker.newReadOnlyTransaction();
+
+        // return domDataBroker.newReadOnlyTransaction(); //Return original
+        return new AuthzReadOnlyTransaction(ro);
+    }
+
+    @Override
+    public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
+        return domDataBroker.getSupportedExtensions();
+    }
+
+    @Override
+    public DOMDataReadWriteTransaction newReadWriteTransaction() {
+        // return new Authz transaction + inject real DOM Transaction
+        DOMDataReadWriteTransaction rw = domDataBroker.newReadWriteTransaction();
+        return new AuthzDataReadWriteTransaction(rw);
+    }
+
+    @Override
+    public DOMDataWriteTransaction newWriteOnlyTransaction() {
+        DOMDataWriteTransaction wo = domDataBroker.newWriteOnlyTransaction();
+        return new AuthzWriteOnlyTransaction(wo);
+    }
+
+    @Override
+    public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(
+            LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier,
+            DOMDataChangeListener domDataChangeListener, DataChangeScope dataChangeScope) {
+        return domDataBroker.registerDataChangeListener(logicalDatastoreType,
+                yangInstanceIdentifier, domDataChangeListener, dataChangeScope);
+    }
+
+    @Override
+    public DOMTransactionChain createTransactionChain(
+            TransactionChainListener transactionChainListener) {
+        return domDataBroker.createTransactionChain(transactionChainListener);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java
new file mode 100644
index 00000000..dbfea6ed
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.spi.ForwardingProviderSession;
+
+/**
+ * Created by wdec on 28/08/2014.
+ */
+public class AuthzProviderContextImpl extends ForwardingProviderSession {
+
+    private final Broker.ProviderSession realSession;
+
+    public AuthzProviderContextImpl(Broker.ProviderSession providerSession,
+            AuthzBrokerImpl authzBroker) {
+        this.realSession = providerSession;
+    }
+
+    @Override
+    protected ProviderSession delegate() {
+        // TODO Auto-generated method stub
+        return realSession;
+    }
+
+    @Override
+    public <T extends BrokerService> T getService(Class<T> tClass) {
+        T t;
+        // Check for class and return Authz broker only for DOMBroker
+        if (tClass == DOMDataBroker.class) {
+            t = (T) AuthzDomDataBroker.getInstance();
+        } else {
+            t = realSession.getService(tClass);
+        }
+        // AuthzDomDataBroker.getInstance().setDomDataBroker((DOMDataBroker)t);
+        return t;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java
new file mode 100644
index 00000000..c46ffe7c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Created by wdec on 28/08/2014.
+ */
+
+public class AuthzReadOnlyTransaction implements DOMDataReadOnlyTransaction {
+
+    private final DOMDataReadOnlyTransaction ro;
+
+    public AuthzReadOnlyTransaction(DOMDataReadOnlyTransaction ro) {
+        this.ro = ro;
+    }
+
+    @Override
+    public void close() {
+        ro.close();
+    }
+
+    @Override
+    public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+            LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Read)) {
+            return ro.read(logicalDatastoreType, yangInstanceIdentifier);
+        }
+        ReadFailedException e = new ReadFailedException("Authorization Failed");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public CheckedFuture<Boolean, ReadFailedException> exists(
+            LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(ActionType.Exists)) {
+            return ro.exists(logicalDatastoreType, yangInstanceIdentifier);
+        }
+        ReadFailedException e = new ReadFailedException("Authorization Failed");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public Object getIdentifier() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) {
+            return ro.getIdentifier();
+        }
+        return null;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java
new file mode 100644
index 00000000..fb344812
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import java.util.List;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.controller.config.yang.config.aaa_authz.srv.Policies;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.AuthorizationResponseType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+/**
+ * @author lmukkama Date: 9/2/14
+ */
+public class AuthzServiceImpl {
+
+    private static List<Policies> listPolicies;
+
+    private static final String WILDCARD_TOKEN = "*";
+
+    public static boolean isAuthorized(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier, ActionType actionType) {
+
+        AuthorizationResponseType authorizationResponseType = AuthzServiceImpl.reqAuthorization(
+                actionType, logicalDatastoreType, yangInstanceIdentifier);
+        return authorizationResponseType.equals(AuthorizationResponseType.Authorized);
+    }
+
+    public static boolean isAuthorized(ActionType actionType) {
+        AuthorizationResponseType authorizationResponseType = AuthzServiceImpl
+                .reqAuthorization(actionType);
+        return authorizationResponseType.equals(AuthorizationResponseType.Authorized);
+    }
+
+    public static void setPolicies(List<Policies> policies) {
+
+        AuthzServiceImpl.listPolicies = policies;
+    }
+
+    public static AuthorizationResponseType reqAuthorization(ActionType actionType) {
+
+        AuthenticationService authenticationService = AuthzDomDataBroker.getInstance()
+                .getAuthService();
+        if (authenticationService != null && AuthzServiceImpl.listPolicies != null
+                && AuthzServiceImpl.listPolicies.size() > 0) {
+            Authentication authentication = authenticationService.get();
+            if (authentication != null && authentication.roles() != null
+                    && authentication.roles().size() > 0) {
+                return checkAuthorization(actionType, authentication);
+            }
+        }
+        return AuthorizationResponseType.NotAuthorized;
+    }
+
+    public static AuthorizationResponseType reqAuthorization(ActionType actionType,
+            LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) {
+
+        AuthenticationService authenticationService = AuthzDomDataBroker.getInstance()
+                .getAuthService();
+
+        if (authenticationService != null && AuthzServiceImpl.listPolicies != null
+                && AuthzServiceImpl.listPolicies.size() > 0) {
+            // Authentication Service exists. Can do authorization checks
+            Authentication authentication = authenticationService.get();
+
+            if (authentication != null && authentication.roles() != null
+                    && authentication.roles().size() > 0) {
+                // Authentication claim object exists with atleast one role
+                return checkAuthorization(actionType, authentication, logicalDatastoreType,
+                        yangInstanceIdentifier);
+            }
+        }
+
+        return AuthorizationResponseType.Authorized;
+    }
+
+    private static AuthorizationResponseType checkAuthorization(ActionType actionType,
+            Authentication authentication, LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier) {
+
+        for (Policies policy : AuthzServiceImpl.listPolicies) {
+
+            // Action type is compared as string, since its type is string in
+            // the config yang. Comparison is case insensitive
+            if (authentication.roles().contains(policy.getRole().getValue())
+                    && (policy.getResource().getValue().equals(WILDCARD_TOKEN) || policy
+                            .getResource().getValue().equals(yangInstanceIdentifier.toString()))
+                    && (policy.getAction().toLowerCase()
+                            .equals(ActionType.Any.name().toLowerCase()) || actionType.name()
+                            .toLowerCase().equals(policy.getAction().toLowerCase()))) {
+
+                return AuthorizationResponseType.Authorized;
+            }
+
+        }
+
+        // For helium release we unauthorize other requests.
+        return AuthorizationResponseType.NotAuthorized;
+    }
+
+    private static AuthorizationResponseType checkAuthorization(ActionType actionType,
+            Authentication authentication) {
+
+        for (Policies policy : AuthzServiceImpl.listPolicies) {
+            if (authentication.roles().contains(policy.getRole().getValue())
+                    && (policy.getAction().equalsIgnoreCase(ActionType.Any.name()) || policy
+                            .getAction().equalsIgnoreCase(actionType.name()))) {
+                return AuthorizationResponseType.Authorized;
+            }
+        }
+        return AuthorizationResponseType.NotAuthorized;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java
new file mode 100644
index 00000000..1123b928
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Created by wdec on 02/09/2014.
+ */
+public class AuthzWriteOnlyTransaction implements DOMDataWriteTransaction {
+
+    private final DOMDataWriteTransaction domDataWriteTransaction;
+
+    public AuthzWriteOnlyTransaction(DOMDataWriteTransaction wo) {
+        this.domDataWriteTransaction = wo;
+    }
+
+    @Override
+    public void put(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Put)) {
+            domDataWriteTransaction.put(logicalDatastoreType, yangInstanceIdentifier,
+                    normalizedNode);
+        }
+    }
+
+    @Override
+    public void merge(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Merge)) {
+            domDataWriteTransaction.merge(logicalDatastoreType, yangInstanceIdentifier,
+                    normalizedNode);
+        }
+    }
+
+    @Override
+    public boolean cancel() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Cancel)) {
+            return domDataWriteTransaction.cancel();
+        }
+        return false;
+    }
+
+    @Override
+    public void delete(LogicalDatastoreType logicalDatastoreType,
+            YangInstanceIdentifier yangInstanceIdentifier) {
+
+        if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier,
+                ActionType.Delete)) {
+            domDataWriteTransaction.delete(logicalDatastoreType, yangInstanceIdentifier);
+        }
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Submit)) {
+            return domDataWriteTransaction.submit();
+        }
+        TransactionCommitFailedException e = new TransactionCommitFailedException(
+                "Unauthorized User");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Deprecated
+    @Override
+    public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.Commit)) {
+            return domDataWriteTransaction.commit();
+        }
+        TransactionCommitFailedException e = new TransactionCommitFailedException(
+                "Unauthorized User");
+        return Futures.immediateFailedCheckedFuture(e);
+    }
+
+    @Override
+    public Object getIdentifier() {
+        if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) {
+            return domDataWriteTransaction.getIdentifier();
+        }
+        return null;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java
new file mode 100644
index 00000000..a590b982
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.config.aaa_authz.srv;
+
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.authz.srv.AuthzBrokerImpl;
+import org.opendaylight.aaa.authz.srv.AuthzServiceImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthzSrvModule extends
+        org.opendaylight.controller.config.yang.config.aaa_authz.srv.AbstractAuthzSrvModule {
+    private static final Logger LOG = LoggerFactory.getLogger(AuthzSrvModule.class);
+    private static boolean simple_config_switch;
+    private BundleContext bundleContext;
+
+    public AuthzSrvModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public AuthzSrvModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            org.opendaylight.controller.config.yang.config.aaa_authz.srv.AuthzSrvModule oldModule,
+            java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // checkNotNull(getDomBroker(), domBrokerJmxAttribute);
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+
+        // Get new AuthZ Broker
+        final AuthzBrokerImpl authzBrokerImpl = new AuthzBrokerImpl();
+
+        // Provide real broker to the new Authz broker
+        authzBrokerImpl.setBroker(getDomBrokerDependency());
+
+        // Get AuthN service reference and register it with the authzBroker
+        ServiceReference<AuthenticationService> authServiceReference = bundleContext
+                .getServiceReference(AuthenticationService.class);
+        AuthenticationService as = bundleContext.getService(authServiceReference);
+        authzBrokerImpl.setAuthenticationService(as);
+
+        // Set the policies list to authz serviceimpl
+        AuthzServiceImpl.setPolicies(getPolicies());
+
+        // Register AuthZ broker with the real Broker as a provider; triggers
+        // "onSessionInitiated" in AuthzBrokerImpl
+        getDomBrokerDependency().registerProvider(authzBrokerImpl);
+        // TODO ActionType is of type string, not ENUM due to improper
+        // serialization of ENUMs by config/netconf subsystem. This needs to be
+        // fixed as soon as config/netconf fixes the problem.
+        getAction();
+
+        LOG.info("AuthZ Service Initialized from Config subsystem");
+        return authzBrokerImpl;
+
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java
new file mode 100644
index 00000000..3ff67f54
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/*
+ * Generated file
+ *
+ * Generated from: yang module name: aaa-authz-service-impl yang module local name: aaa-authz-service
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Thu Jul 24 11:19:40 CEST 2014
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.config.aaa_authz.srv;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+public class AuthzSrvModuleFactory extends
+        org.opendaylight.controller.config.yang.config.aaa_authz.srv.AbstractAuthzSrvModuleFactory {
+
+    @Override
+    public org.opendaylight.controller.config.spi.Module createModule(String instanceName,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            org.osgi.framework.BundleContext bundleContext) {
+
+        final AuthzSrvModule module = (AuthzSrvModule) super.createModule(instanceName,
+                dependencyResolver, bundleContext);
+
+        module.setBundleContext(bundleContext);
+
+        return module;
+
+    }
+
+    @Override
+    public Module createModule(final String instanceName,
+            final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old,
+            final BundleContext bundleContext) throws Exception {
+        final AuthzSrvModule module = (AuthzSrvModule) super.createModule(instanceName,
+                dependencyResolver, old, bundleContext);
+
+        module.setBundleContext(bundleContext);
+
+        return module;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang
new file mode 100644
index 00000000..954d0480
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang
@@ -0,0 +1,115 @@
+module aaa-authz-service-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv";
+    prefix "aaa-authz-srv-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+    import opendaylight-md-sal-dom {prefix dom;}
+    import authorization-schema { prefix authzs; revision-date 2014-07-22; }
+    import ietf-inet-types {prefix inet; revision-date 2010-09-24;}
+
+    description
+        "This module contains the base YANG definitions for
+        AuthZ  implementation.";
+
+    revision "2014-07-01" {
+        description
+            "Initial revision.";
+    }
+
+
+    // This is the definition of the service implementation as a module identity.
+    identity aaa-authz-service {
+            base config:module-type;
+            // Specifies the prefix for generated java classes.
+            config:java-name-prefix AuthzSrv;
+            config:provided-service dom:dom-broker-osgi-registry;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+
+    augment "/config:modules/config:module/config:configuration" {
+        case aaa-authz-service {
+            when "/config:modules/config:module/config:type = 'aaa-authz-service'";
+
+//Defines reference to the intended broker under the AuthZ broker
+
+            container dom-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dom:dom-broker-osgi-registry;
+                    }
+                }
+            }
+
+            container data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-data-broker;
+
+                    }
+                }
+            }
+
+//Simple Authz data leafs:
+
+                leaf authz-role {
+                    type string;
+                }
+                leaf service {
+                  type authzs:service-type;
+                }
+
+                // ENUMs cannot be used right now (config subsystem + netconf cannot properly serialize enums), using strings instead
+                // In the generated module use Enum.valueOf from that string.
+                // Expected values are following strnigs: create, read, update, delete, execute, subscribe, any;
+                leaf action {
+                  type string;
+                  description "String representation of enum authzs:action-type expecting following values create, read, update, delete, execute, subscribe, any";
+                  //type authzs:action-type;
+
+                }
+                leaf resource {
+                  type authzs:resource-type;
+
+                }
+                leaf role {
+                  type authzs:role-type;
+                }
+
+
+
+                  //TODO: Check why uses below doesn't make the outer list be part of the source name-space in yang code generator.
+                  //uses authzs:authorization-grp;
+                     list policies {
+                                 key "service";
+                                 leaf service {
+                                   type authzs:service-type;
+                                 }
+                                 // Grouping uses ENUMs and enums are not correctly serialized in Config + Netconf
+                                 // Same as with action one level ip
+                                 leaf action {
+                                   type string;
+                                   description "String representation of enum authzs:action-type expecting following values create, read, update, delete, execute, subscribe, any";
+                                   //type authzs:action-type;
+                                 }
+                                 leaf resource {
+                                   type authzs:resource-type;
+
+                                 }
+                                 leaf role {
+                                   type authzs:role-type;
+
+                                 }
+                       }
+
+
+            }
+        }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java
new file mode 100644
index 00000000..fb033341
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.authz.srv;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+
+public class AuthzConsumerContextImplTest {
+
+    private Broker.ConsumerSession realconsumercontext;
+    private Provider realprovidercontext;
+    private AuthzBrokerImpl authzBroker;
+    private Broker realbroker;
+
+    @Before
+    public void beforeTest() {
+        realconsumercontext = Mockito.mock(Broker.ConsumerSession.class);
+        realprovidercontext = Mockito.mock(Provider.class);
+        realbroker = Mockito.mock(Broker.class);
+        realbroker.registerProvider(realprovidercontext);
+        authzBroker = Mockito.mock(AuthzBrokerImpl.class);
+    }
+
+    @org.junit.Test
+    public void testGetService() throws Exception {
+        AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl(
+                realconsumercontext, authzBroker);
+
+        Assert.assertEquals("Expected Authz session context",
+                authzConsumerContext.getService(DOMDataBroker.class).getClass(),
+                AuthzDomDataBroker.class);
+        // Assert.assertEquals("Expected Authz session context",
+        // authzConsumerContext.getService(SchemaService.class).getClass(),
+        // SchemaService.class);
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-authz/pom.xml b/odl-aaa-moon/aaa/aaa-authz/pom.xml
new file mode 100644
index 00000000..a5e37680
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-authz/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-authz</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>aaa-authz-model</module>
+        <module>aaa-authz-service</module>
+        <module>aaa-authz-config</module>
+        <module>aaa-authz-restconf-config</module>
+    </modules>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-credential-store-api/pom.xml b/odl-aaa-moon/aaa/aaa-credential-store-api/pom.xml
new file mode 100644
index 00000000..b43ac11c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-credential-store-api/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+(c) Copyright 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v1.0 which accompanies this distribution,
+and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.8.2-Beryllium-SR2</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.aaa</groupId>
+  <artifactId>aaa-credential-store-api</artifactId>
+  <version>0.3.2-Beryllium-SR2</version>
+  <packaging>bundle</packaging>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-credential-store-api/src/main/yang/credential-model.yang b/odl-aaa-moon/aaa/aaa-credential-store-api/src/main/yang/credential-model.yang
new file mode 100644
index 00000000..7d1f55a3
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-credential-store-api/src/main/yang/credential-model.yang
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+module credential-store {
+    namespace "urn:opendaylight:params:xml:ns:yang:aaa:credential-store";
+    prefix "cs";
+
+    description "Defines and extensible model for storing various types of security credentials.";
+
+    revision "2015-02-26" { description "Initial revision."; }
+
+    identity credential-type {
+        description
+          "Credential base type.  All credential types must be derived from this identity.";
+    }
+
+    typedef credential-type-ref {
+        description "reference to an entry in the credential store based on id.";
+        type instance-identifier;
+    }
+
+    container credential-store {
+        list credential {
+            key "id";
+
+            leaf id {
+                description "Unique identifier for this credential entry.";
+                type string;
+            }
+
+            leaf type {
+                description "The type of credential represented in this entry.";
+                type identityref {
+                    base credential-type;
+                }
+            }
+
+            choice value {
+                description "Extension point. Contains the data specific to the credential type.";
+            }
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/.gitignore b/odl-aaa-moon/aaa/aaa-h2-store/.gitignore
new file mode 100644
index 00000000..1dd33310
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/.gitignore
@@ -0,0 +1,2 @@
+/target/
+/target/
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/pom.xml b/odl-aaa-moon/aaa/aaa-h2-store/pom.xml
new file mode 100644
index 00000000..d40f8858
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/pom.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-h2-store</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- JDBC -->
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>com.google.*,org.opendaylight.aaa.api.*,org.apache.felix.*,org.slf4j.*,org.opendaylight.*,org.osgi.*,org.apache.commons.lang3</Import-Package>
+                        <Private-Package>org.h2.*</Private-Package>
+                        <Embed-Dependency>h2</Embed-Dependency>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                        <type>jar</type>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/initial/08-aaa-h2-store-config.xml</file>
+                                    <type>xml</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/config/IdmLightConfig.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/config/IdmLightConfig.java
new file mode 100644
index 00000000..a35ca48f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/config/IdmLightConfig.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for providing configuration properties for the IDMLight/H2
+ * data store implementation.
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+public class IdmLightConfig {
+
+    private static final Logger LOG = LoggerFactory.getLogger(IdmLightConfig.class);
+
+    /**
+     * The default timeout for db connections in seconds.
+     */
+    private static final int DEFAULT_DB_TIMEOUT = 3;
+
+    /**
+     * The default password for the database
+     */
+    private static final String DEFAULT_PASSWORD = "bar";
+
+    /**
+     * The default username for the database
+     */
+    private static final String DEFAULT_USERNAME = "foo";
+
+    /**
+     * The default driver for the databse is H2;  a pure-java implementation
+     * of JDBC.
+     */
+    private static final String DEFAULT_JDBC_DRIVER = "org.h2.Driver";
+
+    /**
+     * The default connection string includes the intention to use h2 as
+     * the JDBC driver, and the path for the file is located relative to
+     * KARAF_HOME.
+     */
+    private static final String DEFAULT_CONNECTION_STRING = "jdbc:h2:./";
+
+    /**
+     * The default filename for the database file.
+     */
+    private static final String DEFAULT_IDMLIGHT_DB_FILENAME = "idmlight.db";
+
+    /**
+     * The database filename
+     */
+    private String dbName;
+
+    /**
+     * the database connection string
+     */
+    private String dbPath;
+
+    /**
+     * The database driver (i.e., H2)
+     */
+    private String dbDriver;
+
+    /**
+     * The database password.  This is not the same as AAA credentials!
+     */
+    private String dbUser;
+
+    /**
+     * The database username.  This is not the same as AAA credentials!
+     */
+    private String dbPwd;
+
+    /**
+     * Timeout for database connections in seconds
+     */
+    private int dbValidTimeOut;
+
+    /**
+     * Creates an valid database configuration using default values.
+     */
+    public IdmLightConfig() {
+        // TODO make this configurable
+        dbName = DEFAULT_IDMLIGHT_DB_FILENAME;
+        dbPath = DEFAULT_CONNECTION_STRING + dbName;
+        dbDriver = DEFAULT_JDBC_DRIVER;
+        dbUser = DEFAULT_USERNAME;
+        dbPwd = DEFAULT_PASSWORD;
+        dbValidTimeOut = DEFAULT_DB_TIMEOUT;
+    }
+
+    /**
+     * Outputs some debugging information surrounding idmlight config
+     */
+    public void log() {
+        LOG.info("DB Path                 : {}", dbPath);
+        LOG.info("DB Driver               : {}", dbDriver);
+        LOG.info("DB Valid Time Out       : {}", dbValidTimeOut);
+    }
+
+    public String getDbName() {
+        return this.dbName;
+    }
+
+    public String getDbPath() {
+        return this.dbPath;
+    }
+
+    public String getDbDriver() {
+        return this.dbDriver;
+    }
+
+    public String getDbUser() {
+        return this.dbUser;
+    }
+
+    public String getDbPwd() {
+        return this.dbPwd;
+    }
+
+    public int getDbValidTimeOut() {
+        return this.dbValidTimeOut;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java
new file mode 100644
index 00000000..ba00eb84
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright © 2016 Red Hat, Inc. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.h2.persistence;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for H2 stores.
+ */
+abstract class AbstractStore<T> {
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractStore.class);
+
+    /**
+     * The name of the table used to represent this store.
+     */
+    private final String tableName;
+
+    /**
+     * Database connection, only used for tests.
+     */
+    Connection dbConnection = null;
+
+    /**
+     * Table types we're interested in (when checking tables' existence).
+     */
+    public static final String[] TABLE_TYPES = new String[] { "TABLE" };
+
+    /**
+     * Creates an instance.
+     *
+     * @param tableName The name of the table being managed.
+     */
+    protected AbstractStore(String tableName) {
+        this.tableName = tableName;
+    }
+
+    /**
+     * Returns a database connection. It is the caller's responsibility to close it. If the managed table does not
+     * exist, it will be created (using {@link #getTableCreationStatement()}).
+     *
+     * @return A database connection.
+     *
+     * @throws StoreException if an error occurs.
+     */
+    protected Connection dbConnect() throws StoreException {
+        Connection conn = H2Store.getConnection(dbConnection);
+        try {
+            // Ensure table check/creation is atomic
+            synchronized (this) {
+                DatabaseMetaData dbm = conn.getMetaData();
+                try (ResultSet rs = dbm.getTables(null, null, tableName, TABLE_TYPES)) {
+                    if (rs.next()) {
+                        LOG.debug("Table {} already exists", tableName);
+                    } else {
+                        LOG.info("Table {} does not exist, creating it", tableName);
+                        try (Statement stmt = conn.createStatement()) {
+                            stmt.executeUpdate(getTableCreationStatement());
+                        }
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            LOG.error("Error connecting to the H2 database", e);
+            throw new StoreException("Cannot connect to database server", e);
+        }
+        return conn;
+    }
+
+    /**
+     * Empties the store.
+     *
+     * @throws StoreException if a connection error occurs.
+     */
+    protected void dbClean() throws StoreException {
+        try (Connection c = dbConnect()) {
+            // The table name can't be a parameter in a prepared statement
+            String sql = "DELETE FROM " + tableName;
+            c.createStatement().execute(sql);
+        } catch (SQLException e) {
+            LOG.error("Error clearing table {}", tableName, e);
+            throw new StoreException("Error clearing table " + tableName, e);
+        }
+    }
+
+    /**
+     * Returns the SQL code required to create the managed table.
+     *
+     * @return The SQL table creation statement.
+     */
+    protected abstract String getTableCreationStatement();
+
+    /**
+     * Lists all the stored items.
+     *
+     * @return The stored item.
+     *
+     * @throws StoreException if an error occurs.
+     */
+    protected List<T> listAll() throws StoreException {
+        List<T> result = new ArrayList<>();
+        String query = "SELECT * FROM " + tableName;
+        try (Connection conn = dbConnect();
+             Statement stmt = conn.createStatement();
+             ResultSet rs = stmt.executeQuery(query)) {
+            while (rs.next()) {
+                result.add(fromResultSet(rs));
+            }
+        } catch (SQLException e) {
+            LOG.error("Error listing all items from {}", tableName, e);
+            throw new StoreException(e);
+        }
+        return result;
+    }
+
+    /**
+     * Lists the stored items returned by the given statement.
+     *
+     * @param ps The statement (which must be ready for execution). It is the caller's reponsibility to close this.
+     *
+     * @return The stored items.
+     *
+     * @throws StoreException if an error occurs.
+     */
+    protected List<T> listFromStatement(PreparedStatement ps) throws StoreException {
+        List<T> result = new ArrayList<>();
+        try (ResultSet rs = ps.executeQuery()) {
+            while (rs.next()) {
+                result.add(fromResultSet(rs));
+            }
+        } catch (SQLException e) {
+            LOG.error("Error listing matching items from {}", tableName, e);
+            throw new StoreException(e);
+        }
+        return result;
+    }
+
+    /**
+     * Extracts the first item returned by the given statement, if any.
+     *
+     * @param ps The statement (which must be ready for execution). It is the caller's reponsibility to close this.
+     *
+     * @return The first item, or {@code null} if none.
+     *
+     * @throws StoreException if an error occurs.
+     */
+    protected T firstFromStatement(PreparedStatement ps) throws StoreException {
+        try (ResultSet rs = ps.executeQuery()) {
+            if (rs.next()) {
+                return fromResultSet(rs);
+            } else {
+                return null;
+            }
+        } catch (SQLException e) {
+            LOG.error("Error listing first matching item from {}", tableName, e);
+            throw new StoreException(e);
+        }
+    }
+
+    /**
+     * Converts a single row in a result set to an instance of the managed type.
+     *
+     * @param rs The result set (which is ready for extraction; {@link ResultSet#next()} must <b>not</b> be called).
+     *
+     * @return The corresponding instance.
+     *
+     * @throws SQLException if an error occurs.
+     */
+    protected abstract T fromResultSet(ResultSet rs) throws SQLException;
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/DomainStore.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/DomainStore.java
new file mode 100644
index 00000000..aa8f4b30
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/DomainStore.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import com.google.common.base.Preconditions;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+public class DomainStore extends AbstractStore<Domain> {
+    private static final Logger LOG = LoggerFactory.getLogger(DomainStore.class);
+
+    protected final static String SQL_ID = "domainid";
+    protected final static String SQL_NAME = "name";
+    protected final static String SQL_DESCR = "description";
+    protected final static String SQL_ENABLED = "enabled";
+    private static final String TABLE_NAME = "DOMAINS";
+
+    protected DomainStore() {
+        super(TABLE_NAME);
+    }
+
+    @Override
+    protected String getTableCreationStatement() {
+        return "CREATE TABLE DOMAINS "
+                + "(domainid   VARCHAR(128)      PRIMARY KEY,"
+                + "name        VARCHAR(128)      UNIQUE NOT NULL, "
+                + "description VARCHAR(128)      , "
+                + "enabled     INTEGER           NOT NULL)";
+    }
+
+    @Override
+    protected Domain fromResultSet(ResultSet rs) throws SQLException {
+        Domain domain = new Domain();
+        domain.setDomainid(rs.getString(SQL_ID));
+        domain.setName(rs.getString(SQL_NAME));
+        domain.setDescription(rs.getString(SQL_DESCR));
+        domain.setEnabled(rs.getInt(SQL_ENABLED) == 1);
+        return domain;
+    }
+
+    protected Domains getDomains() throws StoreException {
+        Domains domains = new Domains();
+        domains.setDomains(listAll());
+        return domains;
+    }
+
+    protected Domains getDomains(String domainName) throws StoreException {
+        LOG.debug("getDomains for: {}", domainName);
+        Domains domains = new Domains();
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM DOMAINS WHERE name = ?")) {
+            pstmt.setString(1, domainName);
+            LOG.debug("query string: {}", pstmt.toString());
+            domains.setDomains(listFromStatement(pstmt));
+        } catch (SQLException e) {
+            LOG.error("Error listing domains matching {}", domainName, e);
+            throw new StoreException("Error listing domains", e);
+        }
+        return domains;
+    }
+
+    protected Domain getDomain(String id) throws StoreException {
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM DOMAINS WHERE domainid = ? ")) {
+            pstmt.setString(1, id);
+            LOG.debug("query string: {}", pstmt.toString());
+            return firstFromStatement(pstmt);
+        } catch (SQLException e) {
+            LOG.error("Error retrieving domain {}", id, e);
+            throw new StoreException("Error loading domain", e);
+        }
+    }
+
+    protected Domain createDomain(Domain domain) throws StoreException {
+        Preconditions.checkNotNull(domain);
+        Preconditions.checkNotNull(domain.getName());
+        Preconditions.checkNotNull(domain.isEnabled());
+        String query = "insert into DOMAINS (domainid,name,description,enabled) values(?, ?, ?, ?)";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            statement.setString(1, domain.getName());
+            statement.setString(2, domain.getName());
+            statement.setString(3, domain.getDescription());
+            statement.setInt(4, domain.isEnabled() ? 1 : 0);
+            int affectedRows = statement.executeUpdate();
+            if (affectedRows == 0) {
+                throw new StoreException("Creating domain failed, no rows affected.");
+            }
+            domain.setDomainid(domain.getName());
+            return domain;
+        } catch (SQLException e) {
+            LOG.error("Error creating domain {}", domain.getName(), e);
+            throw new StoreException("Error creating domain", e);
+        }
+    }
+
+    protected Domain putDomain(Domain domain) throws StoreException {
+        Domain savedDomain = this.getDomain(domain.getDomainid());
+        if (savedDomain == null) {
+            return null;
+        }
+
+        if (domain.getDescription() != null) {
+            savedDomain.setDescription(domain.getDescription());
+        }
+        if (domain.getName() != null) {
+            savedDomain.setName(domain.getName());
+        }
+        if (domain.isEnabled() != null) {
+            savedDomain.setEnabled(domain.isEnabled());
+        }
+
+        String query = "UPDATE DOMAINS SET description = ?, enabled = ? WHERE domainid = ?";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            statement.setString(1, savedDomain.getDescription());
+            statement.setInt(2, savedDomain.isEnabled() ? 1 : 0);
+            statement.setString(3, savedDomain.getDomainid());
+            statement.executeUpdate();
+        } catch (SQLException e) {
+            LOG.error("Error updating domain {}", domain.getDomainid(), e);
+            throw new StoreException("Error updating domain", e);
+        }
+
+        return savedDomain;
+    }
+
+    protected Domain deleteDomain(String domainid) throws StoreException {
+        domainid = StringEscapeUtils.escapeHtml4(domainid);
+        Domain deletedDomain = this.getDomain(domainid);
+        if (deletedDomain == null) {
+            return null;
+        }
+        String query = String.format("DELETE FROM DOMAINS WHERE domainid = '%s'", domainid);
+        try (Connection conn = dbConnect();
+             Statement statement = conn.createStatement()) {
+            int deleteCount = statement.executeUpdate(query);
+            LOG.debug("deleted {} records", deleteCount);
+            return deletedDomain;
+        } catch (SQLException e) {
+            LOG.error("Error deleting domain {}", domainid, e);
+            throw new StoreException("Error deleting domain", e);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/GrantStore.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/GrantStore.java
new file mode 100644
index 00000000..ee86e0ba
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/GrantStore.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+public class GrantStore extends AbstractStore<Grant> {
+    private static final Logger LOG = LoggerFactory.getLogger(GrantStore.class);
+
+    protected final static String SQL_ID = "grantid";
+    protected final static String SQL_TENANTID = "domainid";
+    protected final static String SQL_USERID = "userid";
+    protected final static String SQL_ROLEID = "roleid";
+    private static final String TABLE_NAME = "GRANTS";
+
+    protected GrantStore() {
+        super(TABLE_NAME);
+    }
+
+    @Override
+    protected String getTableCreationStatement() {
+        return "CREATE TABLE GRANTS "
+                + "(grantid    VARCHAR(128) PRIMARY KEY,"
+                + "domainid    VARCHAR(128)         NOT NULL, "
+                + "userid      VARCHAR(128)         NOT NULL, "
+                + "roleid      VARCHAR(128)         NOT NULL)";
+    }
+
+    protected Grant fromResultSet(ResultSet rs) throws SQLException {
+        Grant grant = new Grant();
+        try {
+            grant.setGrantid(rs.getString(SQL_ID));
+            grant.setDomainid(rs.getString(SQL_TENANTID));
+            grant.setUserid(rs.getString(SQL_USERID));
+            grant.setRoleid(rs.getString(SQL_ROLEID));
+        } catch (SQLException sqle) {
+            LOG.error("SQL Exception: ", sqle);
+            throw sqle;
+        }
+        return grant;
+    }
+
+    protected Grants getGrants(String did, String uid) throws StoreException {
+        Grants grants = new Grants();
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn
+                     .prepareStatement("SELECT * FROM grants WHERE domainid = ? AND userid = ?")) {
+            pstmt.setString(1, did);
+            pstmt.setString(2, uid);
+            LOG.debug("query string: {}", pstmt.toString());
+            grants.setGrants(listFromStatement(pstmt));
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+        return grants;
+    }
+
+    protected Grants getGrants(String userid) throws StoreException {
+        Grants grants = new Grants();
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM GRANTS WHERE userid = ? ")) {
+            pstmt.setString(1, userid);
+            LOG.debug("query string: {}", pstmt.toString());
+            grants.setGrants(listFromStatement(pstmt));
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+        return grants;
+    }
+
+    protected Grant getGrant(String id) throws StoreException {
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM GRANTS WHERE grantid = ? ")) {
+            pstmt.setString(1, id);
+            LOG.debug("query string: ", pstmt.toString());
+            return firstFromStatement(pstmt);
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected Grant getGrant(String did, String uid, String rid) throws StoreException {
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn
+                     .prepareStatement("SELECT * FROM GRANTS WHERE domainid = ? AND userid = ? AND roleid = ? ")) {
+            pstmt.setString(1, did);
+            pstmt.setString(2, uid);
+            pstmt.setString(3, rid);
+            LOG.debug("query string: {}", pstmt.toString());
+            return firstFromStatement(pstmt);
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected Grant createGrant(Grant grant) throws StoreException {
+        String query = "insert into grants  (grantid,domainid,userid,roleid) values(?,?,?,?)";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            statement.setString(
+                    1,
+                    IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(),
+                            grant.getRoleid()));
+            statement.setString(2, grant.getDomainid());
+            statement.setString(3, grant.getUserid());
+            statement.setString(4, grant.getRoleid());
+            int affectedRows = statement.executeUpdate();
+            if (affectedRows == 0) {
+                throw new StoreException("Creating grant failed, no rows affected.");
+            }
+            grant.setGrantid(IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(),
+                    grant.getRoleid()));
+            return grant;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected Grant deleteGrant(String grantid) throws StoreException {
+        grantid = StringEscapeUtils.escapeHtml4(grantid);
+        Grant savedGrant = this.getGrant(grantid);
+        if (savedGrant == null) {
+            return null;
+        }
+
+        String query = String.format("DELETE FROM GRANTS WHERE grantid = '%s'", grantid);
+        try (Connection conn = dbConnect();
+             Statement statement = conn.createStatement()) {
+            int deleteCount = statement.executeUpdate(query);
+            LOG.debug("deleted {} records", deleteCount);
+            return savedGrant;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/H2Store.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/H2Store.java
new file mode 100644
index 00000000..da40a17b
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/H2Store.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2015 Cisco Systems and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.aaa.h2.config.IdmLightConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class H2Store implements IIDMStore {
+
+    private static final Logger LOG = LoggerFactory.getLogger(H2Store.class);
+
+    private static IdmLightConfig config = new IdmLightConfig();
+    private DomainStore domainStore = new DomainStore();
+    private UserStore userStore = new UserStore();
+    private RoleStore roleStore = new RoleStore();
+    private GrantStore grantStore = new GrantStore();
+
+    public H2Store() {
+    }
+
+    public static Connection getConnection(Connection existingConnection) throws StoreException {
+        Connection connection = existingConnection;
+        try {
+            if (existingConnection == null || existingConnection.isClosed()) {
+                new org.h2.Driver();
+                connection = DriverManager.getConnection(config.getDbPath(), config.getDbUser(),
+                        config.getDbPwd());
+            }
+        } catch (Exception e) {
+            throw new StoreException("Cannot connect to database server" + e);
+        }
+
+        return connection;
+    }
+
+    public static IdmLightConfig getConfig() {
+        return config;
+    }
+
+    @Override
+    public Domain writeDomain(Domain domain) throws IDMStoreException {
+        try {
+            return domainStore.createDomain(domain);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while writing domain", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Domain readDomain(String domainid) throws IDMStoreException {
+        try {
+            return domainStore.getDomain(domainid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading domain", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Domain deleteDomain(String domainid) throws IDMStoreException {
+        try {
+            return domainStore.deleteDomain(domainid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while deleting domain", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Domain updateDomain(Domain domain) throws IDMStoreException {
+        try {
+            return domainStore.putDomain(domain);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while updating domain", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Domains getDomains() throws IDMStoreException {
+        try {
+            return domainStore.getDomains();
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading domains", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Role writeRole(Role role) throws IDMStoreException {
+        try {
+            return roleStore.createRole(role);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while writing role", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Role readRole(String roleid) throws IDMStoreException {
+        try {
+            return roleStore.getRole(roleid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading role", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Role deleteRole(String roleid) throws IDMStoreException {
+        try {
+            return roleStore.deleteRole(roleid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while deleting role", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Role updateRole(Role role) throws IDMStoreException {
+        try {
+            return roleStore.putRole(role);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while updating role", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Roles getRoles() throws IDMStoreException {
+        try {
+            return roleStore.getRoles();
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while getting roles", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public User writeUser(User user) throws IDMStoreException {
+        try {
+            return userStore.createUser(user);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while writing user", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public User readUser(String userid) throws IDMStoreException {
+        try {
+            return userStore.getUser(userid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading user", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public User deleteUser(String userid) throws IDMStoreException {
+        try {
+            return userStore.deleteUser(userid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while deleting user", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public User updateUser(User user) throws IDMStoreException {
+        try {
+            return userStore.putUser(user);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while updating user", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Users getUsers(String username, String domain) throws IDMStoreException {
+        try {
+            return userStore.getUsers(username, domain);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading users", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Users getUsers() throws IDMStoreException {
+        try {
+            return userStore.getUsers();
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading users", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grant writeGrant(Grant grant) throws IDMStoreException {
+        try {
+            return grantStore.createGrant(grant);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while writing grant", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grant readGrant(String grantid) throws IDMStoreException {
+        try {
+            return grantStore.getGrant(grantid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while reading grant", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grant deleteGrant(String grantid) throws IDMStoreException {
+        try {
+            return grantStore.deleteGrant(grantid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while deleting grant", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grants getGrants(String domainid, String userid) throws IDMStoreException {
+        try {
+            return grantStore.getGrants(domainid, userid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while getting grants", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grants getGrants(String userid) throws IDMStoreException {
+        try {
+            return grantStore.getGrants(userid);
+        } catch (StoreException e) {
+            LOG.error("StoreException encountered while getting grants", e);
+            throw new IDMStoreException(e);
+        }
+    }
+
+    @Override
+    public Grant readGrant(String domainid, String userid, String roleid) throws IDMStoreException {
+        return readGrant(IDMStoreUtil.createGrantid(userid, domainid, roleid));
+    }
+
+    public static Domain createDomain(String domainName, boolean enable) throws StoreException {
+        DomainStore ds = new DomainStore();
+        Domain d = new Domain();
+        d.setName(domainName);
+        d.setEnabled(enable);
+        return ds.createDomain(d);
+    }
+
+    public static User createUser(String name, String password, String domain, String description,
+            String email, boolean enabled, String SALT) throws StoreException {
+        UserStore us = new UserStore();
+        User u = new User();
+        u.setName(name);
+        u.setDomainid(domain);
+        u.setDescription(description);
+        u.setEmail(email);
+        u.setEnabled(enabled);
+        u.setPassword(password);
+        u.setSalt(SALT);
+        return us.createUser(u);
+    }
+
+    public static Role createRole(String name, String domain, String description)
+            throws StoreException {
+        RoleStore rs = new RoleStore();
+        Role r = new Role();
+        r.setDescription(description);
+        r.setName(name);
+        r.setDomainid(domain);
+        return rs.createRole(r);
+    }
+
+    public static Grant createGrant(String domain, String user, String role) throws StoreException {
+        GrantStore gs = new GrantStore();
+        Grant g = new Grant();
+        g.setDomainid(domain);
+        g.setRoleid(role);
+        g.setUserid(user);
+        return gs.createGrant(g);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/RoleStore.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/RoleStore.java
new file mode 100644
index 00000000..e7defa4a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/RoleStore.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import com.google.common.base.Preconditions;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+public class RoleStore extends AbstractStore<Role> {
+    private static final Logger LOG = LoggerFactory.getLogger(RoleStore.class);
+
+    protected final static String SQL_ID = "roleid";
+    protected final static String SQL_DOMAIN_ID = "domainid";
+    protected final static String SQL_NAME = "name";
+    protected final static String SQL_DESCR = "description";
+    private static final String TABLE_NAME = "ROLES";
+
+    protected RoleStore() {
+        super(TABLE_NAME);
+    }
+
+    @Override
+    protected String getTableCreationStatement() {
+        return "CREATE TABLE ROLES "
+                + "(roleid     VARCHAR(128)   PRIMARY KEY,"
+                + "name        VARCHAR(128)   NOT NULL, "
+                + "domainid    VARCHAR(128)   NOT NULL, "
+                + "description VARCHAR(128)      NOT NULL)";
+    }
+
+    protected Role fromResultSet(ResultSet rs) throws SQLException {
+        Role role = new Role();
+        try {
+            role.setRoleid(rs.getString(SQL_ID));
+            role.setDomainid(rs.getString(SQL_DOMAIN_ID));
+            role.setName(rs.getString(SQL_NAME));
+            role.setDescription(rs.getString(SQL_DESCR));
+        } catch (SQLException sqle) {
+            LOG.error("SQL Exception: ", sqle);
+            throw sqle;
+        }
+        return role;
+    }
+
+    protected Roles getRoles() throws StoreException {
+        Roles roles = new Roles();
+        roles.setRoles(listAll());
+        return roles;
+    }
+
+    protected Role getRole(String id) throws StoreException {
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn
+                     .prepareStatement("SELECT * FROM ROLES WHERE roleid = ? ")) {
+            pstmt.setString(1, id);
+            LOG.debug("query string: {}", pstmt.toString());
+            return firstFromStatement(pstmt);
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception: " + s);
+        }
+    }
+
+    protected Role createRole(Role role) throws StoreException {
+        Preconditions.checkNotNull(role);
+        Preconditions.checkNotNull(role.getName());
+        Preconditions.checkNotNull(role.getDomainid());
+        String query = "insert into roles (roleid,domainid,name,description) values(?,?,?,?)";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            role.setRoleid(IDMStoreUtil.createRoleid(role.getName(), role.getDomainid()));
+            statement.setString(1, role.getRoleid());
+            statement.setString(2, role.getDomainid());
+            statement.setString(3, role.getName());
+            statement.setString(4, role.getDescription());
+            int affectedRows = statement.executeUpdate();
+            if (affectedRows == 0) {
+                throw new StoreException("Creating role failed, no rows affected.");
+            }
+            return role;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected Role putRole(Role role) throws StoreException {
+
+        Role savedRole = this.getRole(role.getRoleid());
+        if (savedRole == null) {
+            return null;
+        }
+
+        if (role.getDescription() != null) {
+            savedRole.setDescription(role.getDescription());
+        }
+        if (role.getName() != null) {
+            savedRole.setName(role.getName());
+        }
+
+        String query = "UPDATE roles SET description = ? WHERE roleid = ?";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            statement.setString(1, savedRole.getDescription());
+            statement.setString(2, savedRole.getRoleid());
+            statement.executeUpdate();
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+
+        return savedRole;
+    }
+
+    protected Role deleteRole(String roleid) throws StoreException {
+        roleid = StringEscapeUtils.escapeHtml4(roleid);
+        Role savedRole = this.getRole(roleid);
+        if (savedRole == null) {
+            return null;
+        }
+
+        String query = String.format("DELETE FROM ROLES WHERE roleid = '%s'", roleid);
+        try (Connection conn = dbConnect();
+             Statement statement = conn.createStatement()) {
+            int deleteCount = statement.executeUpdate(query);
+            LOG.debug("deleted {} records", deleteCount);
+            return savedRole;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/StoreException.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/StoreException.java
new file mode 100644
index 00000000..7d2f2b9a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/StoreException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+/**
+ * Exception indicating an error in an H2 data store.
+ *
+ * @author peter.mellquist@hp.com
+ */
+
+public class StoreException extends Exception {
+    public StoreException(String message) {
+        super(message);
+    }
+
+    public StoreException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public StoreException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/UserStore.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/UserStore.java
new file mode 100644
index 00000000..96b8013f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/UserStore.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import com.google.common.base.Preconditions;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.SHA256Calculator;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+public class UserStore extends AbstractStore<User> {
+    private static final Logger LOG = LoggerFactory.getLogger(UserStore.class);
+
+    protected final static String SQL_ID = "userid";
+    protected final static String SQL_DOMAIN_ID = "domainid";
+    protected final static String SQL_NAME = "name";
+    protected final static String SQL_EMAIL = "email";
+    protected final static String SQL_PASSWORD = "password";
+    protected final static String SQL_DESCR = "description";
+    protected final static String SQL_ENABLED = "enabled";
+    protected final static String SQL_SALT = "salt";
+    private static final String TABLE_NAME = "USERS";
+
+    protected UserStore() {
+        super(TABLE_NAME);
+    }
+
+    @Override
+    protected String getTableCreationStatement() {
+        return "CREATE TABLE users "
+                + "(userid    VARCHAR(128) PRIMARY KEY,"
+                + "name       VARCHAR(128)      NOT NULL, "
+                + "domainid   VARCHAR(128)      NOT NULL, "
+                + "email      VARCHAR(128)      NOT NULL, "
+                + "password   VARCHAR(128)      NOT NULL, "
+                + "description VARCHAR(128)     NOT NULL, "
+                + "salt        VARCHAR(15)      NOT NULL, "
+                + "enabled     INTEGER          NOT NULL)";
+    }
+
+    @Override
+    protected User fromResultSet(ResultSet rs) throws SQLException {
+        User user = new User();
+        try {
+            user.setUserid(rs.getString(SQL_ID));
+            user.setDomainid(rs.getString(SQL_DOMAIN_ID));
+            user.setName(rs.getString(SQL_NAME));
+            user.setEmail(rs.getString(SQL_EMAIL));
+            user.setPassword(rs.getString(SQL_PASSWORD));
+            user.setDescription(rs.getString(SQL_DESCR));
+            user.setEnabled(rs.getInt(SQL_ENABLED) == 1);
+            user.setSalt(rs.getString(SQL_SALT));
+        } catch (SQLException sqle) {
+            LOG.error("SQL Exception: ", sqle);
+            throw sqle;
+        }
+        return user;
+    }
+
+    protected Users getUsers() throws StoreException {
+        Users users = new Users();
+        users.setUsers(listAll());
+        return users;
+    }
+
+    protected Users getUsers(String username, String domain) throws StoreException {
+        LOG.debug("getUsers for: {} in domain {}", username, domain);
+
+        Users users = new Users();
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM USERS WHERE userid = ? ")) {
+            pstmt.setString(1, IDMStoreUtil.createUserid(username, domain));
+            LOG.debug("query string: {}", pstmt.toString());
+            users.setUsers(listFromStatement(pstmt));
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+        return users;
+    }
+
+    protected User getUser(String id) throws StoreException {
+        try (Connection conn = dbConnect();
+             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM USERS WHERE userid = ? ")) {
+            pstmt.setString(1, id);
+            LOG.debug("query string: {}", pstmt.toString());
+            return firstFromStatement(pstmt);
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected User createUser(User user) throws StoreException {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(user.getName());
+        Preconditions.checkNotNull(user.getDomainid());
+
+        user.setSalt(SHA256Calculator.generateSALT());
+        String query = "insert into users (userid,domainid,name,email,password,description,enabled,salt) values(?,?,?,?,?,?,?,?)";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            user.setUserid(IDMStoreUtil.createUserid(user.getName(), user.getDomainid()));
+            statement.setString(1, user.getUserid());
+            statement.setString(2, user.getDomainid());
+            statement.setString(3, user.getName());
+            statement.setString(4, user.getEmail());
+            statement.setString(5, SHA256Calculator.getSHA256(user.getPassword(), user.getSalt()));
+            statement.setString(6, user.getDescription());
+            statement.setInt(7, user.isEnabled() ? 1 : 0);
+            statement.setString(8, user.getSalt());
+            int affectedRows = statement.executeUpdate();
+            if (affectedRows == 0) {
+                throw new StoreException("Creating user failed, no rows affected.");
+            }
+            return user;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+
+    protected User putUser(User user) throws StoreException {
+
+        User savedUser = this.getUser(user.getUserid());
+        if (savedUser == null) {
+            return null;
+        }
+
+        if (user.getDescription() != null) {
+            savedUser.setDescription(user.getDescription());
+        }
+        if (user.getName() != null) {
+            savedUser.setName(user.getName());
+        }
+        if (user.isEnabled() != null) {
+            savedUser.setEnabled(user.isEnabled());
+        }
+        if (user.getEmail() != null) {
+            savedUser.setEmail(user.getEmail());
+        }
+        if (user.getPassword() != null) {
+            // If a new salt is provided, use it.  Otherwise, derive salt from existing.
+            String salt = user.getSalt();
+            if (salt == null) {
+                salt = savedUser.getSalt();
+            }
+            savedUser.setPassword(SHA256Calculator.getSHA256(user.getPassword(), salt));
+        }
+
+        String query = "UPDATE users SET email = ?, password = ?, description = ?, enabled = ? WHERE userid = ?";
+        try (Connection conn = dbConnect();
+             PreparedStatement statement = conn.prepareStatement(query)) {
+            statement.setString(1, savedUser.getEmail());
+            statement.setString(2, savedUser.getPassword());
+            statement.setString(3, savedUser.getDescription());
+            statement.setInt(4, savedUser.isEnabled() ? 1 : 0);
+            statement.setString(5, savedUser.getUserid());
+            statement.executeUpdate();
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+
+        return savedUser;
+    }
+
+    protected User deleteUser(String userid) throws StoreException {
+        userid = StringEscapeUtils.escapeHtml4(userid);
+        User savedUser = this.getUser(userid);
+        if (savedUser == null) {
+            return null;
+        }
+
+        String query = String.format("DELETE FROM USERS WHERE userid = '%s'", userid);
+        try (Connection conn = dbConnect();
+             Statement statement = conn.createStatement()) {
+            int deleteCount = statement.executeUpdate(query);
+            LOG.debug("deleted {} records", deleteCount);
+            return savedUser;
+        } catch (SQLException s) {
+            throw new StoreException("SQL Exception : " + s);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModule.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModule.java
new file mode 100644
index 00000000..fe7dd2a6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModule.java
@@ -0,0 +1,49 @@
+package org.opendaylight.yang.gen.v1.config.aaa.authn.h2.store.rev151128;
+
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.h2.persistence.H2Store;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AAAH2StoreModule extends org.opendaylight.yang.gen.v1.config.aaa.authn.h2.store.rev151128.AbstractAAAH2StoreModule {
+
+    private BundleContext bundleContext;
+    private static final Logger LOG = LoggerFactory.getLogger(AAAH2StoreModule.class);
+
+    public AAAH2StoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public AAAH2StoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.config.aaa.authn.h2.store.rev151128.AAAH2StoreModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final H2Store h2Store = new H2Store();
+        final ServiceRegistration<?> serviceRegistration = bundleContext.registerService(IIDMStore.class.getName(), h2Store, null);
+        LOG.info("AAA H2 Store Initialized");
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                serviceRegistration.unregister();
+            }
+        };
+    }
+
+    /**
+     * @param bundleContext
+     */
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    /**
+     * @return the bundleContext
+     */
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModuleFactory.java b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModuleFactory.java
new file mode 100644
index 00000000..dc9e7f99
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/h2/store/rev151128/AAAH2StoreModuleFactory.java
@@ -0,0 +1,29 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: aaa-h2-store yang module local name: aaa-h2-store
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Sat Nov 28 11:00:15 PST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.config.aaa.authn.h2.store.rev151128;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class AAAH2StoreModuleFactory extends org.opendaylight.yang.gen.v1.config.aaa.authn.h2.store.rev151128.AbstractAAAH2StoreModuleFactory {
+    @Override
+    public AAAH2StoreModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, AAAH2StoreModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+        AAAH2StoreModule module =  super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public AAAH2StoreModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        AAAH2StoreModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/resources/initial/08-aaa-h2-store-config.xml b/odl-aaa-moon/aaa/aaa-h2-store/src/main/resources/initial/08-aaa-h2-store-config.xml
new file mode 100644
index 00000000..cfe60812
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/resources/initial/08-aaa-h2-store-config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:authn="config:aaa:authn:h2:store">authn:aaa-h2-store</type>
+                    <name>aaa-h2-store</name>
+                </module>
+            </modules>
+        </data>
+    </configuration>
+    <required-capabilities>
+        <capability>config:aaa:authn:h2:store?module=aaa-h2-store&amp;revision=2015-11-28</capability>
+    </required-capabilities>
+
+</snapshot>
+
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/main/yang/aaa-h2-store.yang b/odl-aaa-moon/aaa/aaa-h2-store/src/main/yang/aaa-h2-store.yang
new file mode 100644
index 00000000..af2d9bdc
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/main/yang/aaa-h2-store.yang
@@ -0,0 +1,28 @@
+module aaa-h2-store {
+  yang-version 1;
+  namespace "config:aaa:authn:h2:store";
+  prefix "aaa-h2-store";
+    organization "OpenDayLight";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    contact "saichler@gmail.com";
+
+    revision 2015-11-28 {
+        description
+            "Initial revision.";
+    }
+
+    identity aaa-h2-store {
+        base config:module-type;
+        config:java-name-prefix AAAH2Store;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case aaa-h2-store {
+            when "/config:modules/config:module/config:type = 'aaa-h2-store'";
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/DomainStoreTest.java b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/DomainStoreTest.java
new file mode 100644
index 00000000..f11a99eb
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/DomainStoreTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.h2.persistence.DomainStore;
+
+public class DomainStoreTest {
+
+    Connection connectionMock = mock(Connection.class);
+    private final DomainStore domainStoreUnderTest = new DomainStore();
+
+    @Before
+    public void setup() {
+        domainStoreUnderTest.dbConnection = connectionMock;
+    }
+
+    @After
+    public void teardown() {
+        // dts.destroy();
+    }
+
+    @Test
+    public void getDomainsTest() throws SQLException, Exception {
+        // Setup Mock Behavior
+        String[] tableTypes = { "TABLE" };
+        Mockito.when(connectionMock.isClosed()).thenReturn(false);
+        DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
+        Mockito.when(connectionMock.getMetaData()).thenReturn(dbmMock);
+        ResultSet rsUserMock = mock(ResultSet.class);
+        Mockito.when(dbmMock.getTables(null, null, "DOMAINS", tableTypes)).thenReturn(rsUserMock);
+        Mockito.when(rsUserMock.next()).thenReturn(true);
+
+        Statement stmtMock = mock(Statement.class);
+        Mockito.when(connectionMock.createStatement()).thenReturn(stmtMock);
+
+        ResultSet rsMock = getMockedResultSet();
+        Mockito.when(stmtMock.executeQuery(anyString())).thenReturn(rsMock);
+
+        // Run Test
+        Domains domains = domainStoreUnderTest.getDomains();
+
+        // Verify
+        assertTrue(domains.getDomains().size() == 1);
+        verify(stmtMock).close();
+    }
+
+    public ResultSet getMockedResultSet() throws SQLException {
+        ResultSet rsMock = mock(ResultSet.class);
+        Mockito.when(rsMock.next()).thenReturn(true).thenReturn(false);
+        Mockito.when(rsMock.getInt(DomainStore.SQL_ID)).thenReturn(1);
+        Mockito.when(rsMock.getString(DomainStore.SQL_NAME)).thenReturn("DomainName_1");
+        Mockito.when(rsMock.getString(DomainStore.SQL_DESCR)).thenReturn("Desc_1");
+        Mockito.when(rsMock.getInt(DomainStore.SQL_ENABLED)).thenReturn(1);
+        return rsMock;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/GrantStoreTest.java b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/GrantStoreTest.java
new file mode 100644
index 00000000..168b67e2
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/GrantStoreTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2016 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.aaa.api.model.Grants;
+
+public class GrantStoreTest {
+
+    Connection connectionMock = mock(Connection.class);
+    private final GrantStore grantStoreUnderTest = new GrantStore();
+    private String did = "5";
+    private String uid = "5";
+
+    @Before
+    public void setup() {
+        grantStoreUnderTest.dbConnection = connectionMock;
+    }
+
+    @Test
+    public void getGrantsTest() throws Exception {
+        // Setup Mock Behavior
+        String[] tableTypes = { "TABLE" };
+        Mockito.when(connectionMock.isClosed()).thenReturn(false);
+        DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
+        Mockito.when(connectionMock.getMetaData()).thenReturn(dbmMock);
+        ResultSet rsUserMock = mock(ResultSet.class);
+        Mockito.when(dbmMock.getTables(null, null, "GRANTS", tableTypes)).thenReturn(rsUserMock);
+        Mockito.when(rsUserMock.next()).thenReturn(true);
+
+        PreparedStatement pstmtMock = mock(PreparedStatement.class);
+        Mockito.when(connectionMock.prepareStatement(anyString())).thenReturn(pstmtMock);
+
+        ResultSet rsMock = getMockedResultSet();
+        Mockito.when(pstmtMock.executeQuery()).thenReturn(rsMock);
+
+        // Run Test
+        Grants grants = grantStoreUnderTest.getGrants(did, uid);
+
+        // Verify
+        assertTrue(grants.getGrants().size() == 1);
+        verify(pstmtMock).close();
+    }
+
+    public ResultSet getMockedResultSet() throws SQLException {
+        ResultSet rsMock = mock(ResultSet.class);
+        Mockito.when(rsMock.next()).thenReturn(true).thenReturn(false);
+        Mockito.when(rsMock.getInt(GrantStore.SQL_ID)).thenReturn(1);
+        Mockito.when(rsMock.getString(GrantStore.SQL_TENANTID)).thenReturn(did);
+        Mockito.when(rsMock.getString(GrantStore.SQL_USERID)).thenReturn(uid);
+        Mockito.when(rsMock.getString(GrantStore.SQL_ROLEID)).thenReturn("Role_1");
+
+        return rsMock;
+
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/H2StoreTest.java b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/H2StoreTest.java
new file mode 100644
index 00000000..f583a302
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/H2StoreTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import java.io.File;
+import java.sql.SQLException;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.aaa.api.IDMStoreUtil;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+
+public class H2StoreTest {
+    @BeforeClass
+    public static void start() {
+        File f = new File("idmlight.db.mv.db");
+        if (f.exists()) {
+            f.delete();
+        }
+        f = new File("idmlight.db.trace.db");
+        if (f.exists()) {
+            f.delete();
+        }
+    }
+
+    @AfterClass
+    public static void end() {
+        File f = new File("idmlight.db.mv.db");
+        if (f.exists()) {
+            f.delete();
+        }
+        f = new File("idmlight.db.trace.db");
+        if (f.exists()) {
+            f.delete();
+        }
+    }
+
+    @Before
+    public void before() throws StoreException, SQLException {
+        UserStore us = new UserStore();
+        us.dbClean();
+        DomainStore ds = new DomainStore();
+        ds.dbClean();
+        RoleStore rs = new RoleStore();
+        rs.dbClean();
+        GrantStore gs = new GrantStore();
+        gs.dbClean();
+    }
+
+    @Test
+    public void testCreateDefaultDomain() throws StoreException {
+        Domain d = new Domain();
+        Assert.assertEquals(true, d != null);
+        DomainStore ds = new DomainStore();
+        d.setName(IIDMStore.DEFAULT_DOMAIN);
+        d.setEnabled(true);
+        d = ds.createDomain(d);
+        Assert.assertEquals(true, d != null);
+    }
+
+    @Test
+    public void testCreateTempRole() throws StoreException {
+        Role role = H2Store.createRole("temp", "temp domain", "Temp Testing role");
+        Assert.assertEquals(true, role != null);
+    }
+
+    @Test
+    public void testCreateUser() throws StoreException {
+        User user = H2Store.createUser("test", "pass", "domain", "desc", "email", true, "SALT");
+        Assert.assertEquals(true, user != null);
+    }
+
+    @Test
+    public void testCreateGrant() throws StoreException {
+        Domain d = H2Store.createDomain("sdn", true);
+        Role role = H2Store.createRole("temp", "temp domain", "Temp Testing role");
+        User user = H2Store.createUser("test", "pass", "domain", "desc", "email", true, "SALT");
+        Grant g = H2Store.createGrant(d.getDomainid(), user.getUserid(), role.getRoleid());
+        Assert.assertEquals(true, g != null);
+    }
+
+    @Test
+    public void testUpdatingUserEmail() throws StoreException {
+        UserStore us = new UserStore();
+        Domain d = H2Store.createDomain("sdn", true);
+        User user = H2Store.createUser("test", "pass", d.getDomainid(), "desc", "email", true,
+                "SALT");
+
+        user.setName("test");
+        user = us.putUser(user);
+        Assert.assertEquals(true, user != null);
+
+        user.setEmail("Test@Test.com");
+        user = us.putUser(user);
+
+        user = new User();
+        user.setName("test");
+        user.setDomainid(d.getDomainid());
+        user = us.getUser(IDMStoreUtil.createUserid(user.getName(), user.getDomainid()));
+
+        Assert.assertEquals("Test@Test.com", user.getEmail());
+    }
+    /*
+     * @Test public void testCreateUserViaAPI() throws StoreException { Domain d
+     * = StoreBuilder.createDomain("sdn",true);
+     *
+     * User user = new User(); user.setName("Hello"); user.setPassword("Hello");
+     * user.setDomainid(d.getDomainid()); UserHandler h = new UserHandler();
+     * h.createUser(null, user);
+     *
+     * User u = new User(); u.setName("Hello"); u.setDomainid(d.getDomainid());
+     * UserStore us = new UserStore(); u =
+     * us.getUser(IDMStoreUtil.createUserid(u.getName(),u.getDomainid()));
+     *
+     * Assert.assertEquals(true, u != null); }
+     *
+     * @Test public void testUpdateUserViaAPI() throws StoreException { Domain d
+     * = StoreBuilder.createDomain("sdn",true);
+     *
+     * User user = new User(); user.setName("Hello"); user.setPassword("Hello");
+     * user.setDomainid(d.getDomainid()); UserHandler h = new UserHandler();
+     * h.createUser(null, user);
+     *
+     * user.setEmail("Hello@Hello.com"); user.setPassword("Test123");
+     * h.putUser(null, user, "" + user.getUserid());
+     *
+     * UserStore us = new UserStore();
+     *
+     * User u = new User(); u.setName("Hello"); u.setDomainid(d.getDomainid());
+     * u = us.getUser(IDMStoreUtil.createUserid(u.getName(),u.getDomainid()));
+     *
+     * Assert.assertEquals("Hello@Hello.com", u.getEmail());
+     *
+     * String hash = SHA256Calculator.getSHA256("Test123", u.getSalt());
+     * Assert.assertEquals(u.getPassword(), hash); }
+     *
+     * @Test public void testUpdateUserRoleViaAPI() throws StoreException {
+     * Domain d = StoreBuilder.createDomain("sdn",true); Role role1 =
+     * StoreBuilder.createRole("temp1",d.getDomainid(),"Temp Testing role");
+     * Role role2 =
+     * StoreBuilder.createRole("temp2",d.getDomainid(),"Temp Testing role");
+     *
+     * User user = new User(); user.setName("Hello"); user.setPassword("Hello");
+     * user.setDomainid(d.getDomainid());
+     *
+     * UserHandler h = new UserHandler(); h.createUser(null, user);
+     *
+     * user.setEmail("Hello@Hello.com"); user.setPassword("Test123");
+     * h.putUser(null, user, user.getUserid());
+     *
+     * Grant g = new Grant(); g.setUserid(user.getUserid());
+     * g.setDomainid(d.getDomainid()); g.setRoleid(role1.getRoleid());
+     * GrantStore gs = new GrantStore(); g = gs.createGrant(g);
+     *
+     * Assert.assertEquals(true, g != null); Assert.assertEquals(g.getRoleid(),
+     * role1.getRoleid());
+     *
+     * g = gs.deleteGrant(IDMStoreUtil.createGrantid(user.getUserid(),
+     * d.getDomainid(), role1.getRoleid())); g.setRoleid(role2.getRoleid()); g =
+     * gs.createGrant(g);
+     *
+     * Assert.assertEquals(true, g != null); Assert.assertEquals(g.getRoleid(),
+     * role2.getRoleid());
+     *
+     * User u = new User(); u.setName("Hello"); u.setDomainid(d.getDomainid());
+     * UserStore us = new UserStore(); u =
+     * us.getUser(IDMStoreUtil.createUserid(u.getName(),u.getDomainid()));
+     *
+     * Assert.assertEquals("Hello@Hello.com", u.getEmail());
+     *
+     * String hash = SHA256Calculator.getSHA256("Test123", u.getSalt());
+     * Assert.assertEquals(true, hash.equals(u.getPassword())); }
+     */
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/RoleStoreTest.java b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/RoleStoreTest.java
new file mode 100644
index 00000000..37cb17a6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/RoleStoreTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.h2.persistence.RoleStore;
+
+public class RoleStoreTest {
+
+    Connection connectionMock = mock(Connection.class);
+    private final RoleStore RoleStoreUnderTest = new RoleStore();
+
+    @Before
+    public void setup() {
+        RoleStoreUnderTest.dbConnection = connectionMock;
+    }
+
+    @After
+    public void teardown() {
+        // dts.destroy();
+    }
+
+    @Test
+    public void getRolesTest() throws SQLException, Exception {
+        // Setup Mock Behavior
+        String[] tableTypes = { "TABLE" };
+        Mockito.when(connectionMock.isClosed()).thenReturn(false);
+        DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
+        Mockito.when(connectionMock.getMetaData()).thenReturn(dbmMock);
+        ResultSet rsUserMock = mock(ResultSet.class);
+        Mockito.when(dbmMock.getTables(null, null, "ROLES", tableTypes)).thenReturn(rsUserMock);
+        Mockito.when(rsUserMock.next()).thenReturn(true);
+
+        Statement stmtMock = mock(Statement.class);
+        Mockito.when(connectionMock.createStatement()).thenReturn(stmtMock);
+
+        ResultSet rsMock = getMockedResultSet();
+        Mockito.when(stmtMock.executeQuery(anyString())).thenReturn(rsMock);
+
+        // Run Test
+        Roles roles = RoleStoreUnderTest.getRoles();
+
+        // Verify
+        assertTrue(roles.getRoles().size() == 1);
+        verify(stmtMock).close();
+
+    }
+
+    public ResultSet getMockedResultSet() throws SQLException {
+        ResultSet rsMock = mock(ResultSet.class);
+        Mockito.when(rsMock.next()).thenReturn(true).thenReturn(false);
+        Mockito.when(rsMock.getInt(RoleStore.SQL_ID)).thenReturn(1);
+        Mockito.when(rsMock.getString(RoleStore.SQL_NAME)).thenReturn("RoleName_1");
+        Mockito.when(rsMock.getString(RoleStore.SQL_DESCR)).thenReturn("Desc_1");
+        return rsMock;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/UserStoreTest.java b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/UserStoreTest.java
new file mode 100644
index 00000000..e214c261
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-h2-store/src/test/java/org/opendaylight/aaa/h2/persistence/UserStoreTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.h2.persistence;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.aaa.h2.persistence.UserStore;
+
+public class UserStoreTest {
+
+    Connection connectionMock = mock(Connection.class);
+    private final UserStore userStoreUnderTest = new UserStore();
+
+    @Before
+    public void setup() {
+        userStoreUnderTest.dbConnection = connectionMock;
+    }
+
+    @After
+    public void teardown() {
+        // dts.destroy();
+    }
+
+    @Test
+    public void getUsersTest() throws SQLException, Exception {
+        // Setup Mock Behavior
+        String[] tableTypes = { "TABLE" };
+        Mockito.when(connectionMock.isClosed()).thenReturn(false);
+        DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
+        Mockito.when(connectionMock.getMetaData()).thenReturn(dbmMock);
+        ResultSet rsUserMock = mock(ResultSet.class);
+        Mockito.when(dbmMock.getTables(null, null, "USERS", tableTypes)).thenReturn(rsUserMock);
+        Mockito.when(rsUserMock.next()).thenReturn(true);
+
+        Statement stmtMock = mock(Statement.class);
+        Mockito.when(connectionMock.createStatement()).thenReturn(stmtMock);
+
+        ResultSet rsMock = getMockedResultSet();
+        Mockito.when(stmtMock.executeQuery(anyString())).thenReturn(rsMock);
+
+        // Run Test
+        Users users = userStoreUnderTest.getUsers();
+
+        // Verify
+        assertTrue(users.getUsers().size() == 1);
+        verify(stmtMock).close();
+
+    }
+
+    public ResultSet getMockedResultSet() throws SQLException {
+        ResultSet rsMock = mock(ResultSet.class);
+        Mockito.when(rsMock.next()).thenReturn(true).thenReturn(false);
+        Mockito.when(rsMock.getInt(UserStore.SQL_ID)).thenReturn(1);
+        Mockito.when(rsMock.getString(UserStore.SQL_NAME)).thenReturn("Name_1");
+        Mockito.when(rsMock.getString(UserStore.SQL_EMAIL)).thenReturn("Name_1@company.com");
+        Mockito.when(rsMock.getString(UserStore.SQL_PASSWORD)).thenReturn("Pswd_1");
+        Mockito.when(rsMock.getString(UserStore.SQL_DESCR)).thenReturn("Desc_1");
+        Mockito.when(rsMock.getInt(UserStore.SQL_ENABLED)).thenReturn(1);
+        return rsMock;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/pom.xml b/odl-aaa-moon/aaa/aaa-idmlight/pom.xml
new file mode 100644
index 00000000..2ca5ff69
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/pom.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>aaa-idmlight</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!--Yang Binding -->
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+
+        <!-- JSON JAXB Stuff -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-json-org</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-json-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-jaxb-annotations</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlets</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.mdsal</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                        <type>jar</type>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/initial/08-aaa-idmlight-config.xml</file>
+                                    <type>xml</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>attach-artifacts-idmtool</id>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/idmtool.py</file>
+                                    <type>py</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <!-- override default version so we don't use bnd 2.3.0 when embedding sqlite -->
+
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>org.opendaylight.aaa.shiro.realm,org.apache.shiro.web.env,org.apache.shiro.authc,org.opendaylight.aaa.shiro.web.env,org.opendaylight.aaa.shiro.filters,javax.servlet.http,javax.ws.rs,javax.ws.rs.core,javax.xml.bind.annotation,org.apache.felix.dm,org.opendaylight.aaa,org.opendaylight.aaa.api.*,org.osgi.framework,org.slf4j,org.eclipse.jetty.servlets,com.sun.jersey.spi.container.servlet,com.google.*,org.opendaylight.*,org.osgi.util.tracker</Import-Package>
+                        <Web-ContextPath>/auth</Web-ContextPath>
+                        <!--<Web-Connectors>adminConn</Web-Connectors> -->
+                        <!--Bundle-Activator>org.opendaylight.aaa.idm.Activator</Bundle-Activator-->
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightApplication.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightApplication.java
new file mode 100644
index 00000000..6fcba5d6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightApplication.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+import org.opendaylight.aaa.idm.rest.DomainHandler;
+import org.opendaylight.aaa.idm.rest.RoleHandler;
+import org.opendaylight.aaa.idm.rest.UserHandler;
+import org.opendaylight.aaa.idm.rest.VersionHandler;
+
+/**
+ * A JAX-RS application for IdmLight.  The REST endpoints delivered by this
+ * application are in the form:
+ * <code>http://{HOST}:{PORT}/auth/v1/</code>
+ *
+ * For example, the users REST endpoint is:
+ * <code>http://{HOST}:{PORT}/auth/v1/users</code>
+ *
+ * This application is responsible for interaction with the backing h2
+ * database store.
+ *
+ * @author liemmn
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>org.opendaylight.aaa.idm.rest.DomainHandler</code>
+ * @see <code>org.opendaylight.aaa.idm.rest.UserHandler</code>
+ * @see <code>org.opendaylight.aaa.idm.rest.RoleHandler</code>
+ */
+public class IdmLightApplication extends Application {
+
+    //TODO create a bug to address the fact that the implementation assumes 128
+    // as the max length, even though this claims 256.
+    /**
+     * The maximum field length for identity fields.
+     */
+    public static final int MAX_FIELD_LEN = 256;
+    public IdmLightApplication() {
+    }
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        return new HashSet<Class<?>>(Arrays.asList(VersionHandler.class,
+                                                   DomainHandler.class,
+                                                   RoleHandler.class,
+                                                   UserHandler.class));
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightProxy.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightProxy.java
new file mode 100644
index 00000000..d17d2b13
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/IdmLightProxy.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm;
+
+import com.google.common.base.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.api.SHA256Calculator;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An OSGi proxy for the IdmLight server.
+ *
+ */
+public class IdmLightProxy implements CredentialAuth<PasswordCredentials>, IdMService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(IdmLightProxy.class);
+
+    /**
+     * claimCache is responsible for storing the active claims per domain.  The
+     * outer map is keyed by domain, and the inner map is keyed by
+     * <code>PasswordCredentials</code>.
+     */
+    private static Map<String, Map<PasswordCredentials, Claim>> claimCache = new ConcurrentHashMap<>();
+
+    // adds a store for the default "sdn" domain
+    static {
+        claimCache.put(IIDMStore.DEFAULT_DOMAIN,
+                new ConcurrentHashMap<PasswordCredentials, Claim>());
+    }
+
+    @Override
+    public Claim authenticate(PasswordCredentials creds) {
+        Preconditions.checkNotNull(creds);
+        Preconditions.checkNotNull(creds.username());
+        Preconditions.checkNotNull(creds.password());
+        String domain = creds.domain() == null ? IIDMStore.DEFAULT_DOMAIN : creds.domain();
+        // FIXME: Add cache invalidation
+        Map<PasswordCredentials, Claim> cache = claimCache.get(domain);
+        if (cache == null) {
+            cache = new ConcurrentHashMap<PasswordCredentials, Claim>();
+            claimCache.put(domain, cache);
+        }
+        Claim claim = cache.get(creds);
+        if (claim == null) {
+            synchronized (claimCache) {
+                claim = cache.get(creds);
+                if (claim == null) {
+                    claim = dbAuthenticate(creds);
+                    if (claim != null) {
+                        cache.put(creds, claim);
+                    }
+                }
+            }
+        }
+        return claim;
+    }
+
+    /**
+     * Clears the cache of any active claims.
+     */
+    public static synchronized void clearClaimCache() {
+        LOG.info("Clearing the claim cache");
+        for (Map<PasswordCredentials, Claim> cache : claimCache.values()) {
+            cache.clear();
+        }
+    }
+
+    private static Claim dbAuthenticate(PasswordCredentials creds) {
+        Domain domain = null;
+        User user = null;
+        String credsDomain = creds.domain() == null ? IIDMStore.DEFAULT_DOMAIN : creds.domain();
+        // check to see domain exists
+        // TODO: ensure domain names are unique change to 'getDomain'
+        LOG.debug("get domain");
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(credsDomain);
+            if (domain == null) {
+                throw new AuthenticationException("Domain :" + credsDomain + " does not exist");
+            }
+        } catch (IDMStoreException e) {
+            throw new AuthenticationException("Error while fetching domain", e);
+        }
+
+        // check to see user exists and passes cred check
+        try {
+            LOG.debug("check user / pwd");
+            Users users = AAAIDMLightModule.getStore().getUsers(creds.username(), credsDomain);
+            List<User> userList = users.getUsers();
+            if (userList.size() == 0) {
+                throw new AuthenticationException("User :" + creds.username()
+                        + " does not exist in domain " + credsDomain);
+            }
+            user = userList.get(0);
+            if (!SHA256Calculator.getSHA256(creds.password(), user.getSalt()).equals(
+                    user.getPassword())) {
+                throw new AuthenticationException("UserName / Password not found");
+            }
+
+            // get all grants & roles for this domain and user
+            LOG.debug("get grants");
+            List<String> roles = new ArrayList<String>();
+            Grants grants = AAAIDMLightModule.getStore().getGrants(domain.getDomainid(),
+                    user.getUserid());
+            List<Grant> grantList = grants.getGrants();
+            for (int z = 0; z < grantList.size(); z++) {
+                Grant grant = grantList.get(z);
+                Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
+                if (role != null) {
+                    roles.add(role.getName());
+                }
+            }
+
+            // build up the claim
+            LOG.debug("build a claim");
+            ClaimBuilder claim = new ClaimBuilder();
+            claim.setUserId(user.getUserid().toString());
+            claim.setUser(creds.username());
+            claim.setDomain(credsDomain);
+            for (int z = 0; z < roles.size(); z++) {
+                claim.addRole(roles.get(z));
+            }
+            return claim.build();
+        } catch (IDMStoreException se) {
+            throw new AuthenticationException("idm data store exception :" + se.toString() + se);
+        }
+    }
+
+    @Override
+    public List<String> listDomains(String userId) {
+        LOG.debug("list Domains for userId: {}", userId);
+        List<String> domains = new ArrayList<String>();
+        try {
+            Grants grants = AAAIDMLightModule.getStore().getGrants(userId);
+            List<Grant> grantList = grants.getGrants();
+            for (int z = 0; z < grantList.size(); z++) {
+                Grant grant = grantList.get(z);
+                Domain domain = AAAIDMLightModule.getStore().readDomain(grant.getDomainid());
+                domains.add(domain.getName());
+            }
+            return domains;
+        } catch (IDMStoreException se) {
+            LOG.warn("error getting domains ", se.toString(), se);
+            return domains;
+        }
+
+    }
+
+    @Override
+    public List<String> listRoles(String userId, String domainName) {
+        LOG.debug("listRoles");
+        List<String> roles = new ArrayList<String>();
+
+        try {
+            // find domain name for specied domain name
+            String did = null;
+            try {
+                Domain domain = AAAIDMLightModule.getStore().readDomain(domainName);
+                if (domain == null) {
+                    LOG.debug("DomainName: {}", domainName + " Not found!");
+                    return roles;
+                }
+                did = domain.getDomainid();
+            } catch (IDMStoreException e) {
+                return roles;
+            }
+
+            // find all grants for uid and did
+            Grants grants = AAAIDMLightModule.getStore().getGrants(did, userId);
+            List<Grant> grantList = grants.getGrants();
+            for (int z = 0; z < grantList.size(); z++) {
+                Grant grant = grantList.get(z);
+                Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
+                roles.add(role.getName());
+            }
+
+            return roles;
+        } catch (IDMStoreException se) {
+            LOG.warn("error getting roles ", se.toString(), se);
+            return roles;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/StoreBuilder.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/StoreBuilder.java
new file mode 100644
index 00000000..111665c6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/StoreBuilder.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm;
+
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * StoreBuilder is triggered during feature installation by
+ * <code>AAAIDMLightModule.createInstance()</code>. StoreBuilder is responsible
+ * for initializing the H2 database with initial default user account
+ * information. By default, the following users are created:
+ * <ol>
+ * <li>admin</li>
+ * <li>user</li>
+ * </ol>
+ *
+ * By default, the following domain is created:
+ * <ol>
+ * <li>sdn</li>
+ * </ol>
+ *
+ * By default, the following grants are created:
+ * <ol>
+ * <li>admin with admin role on sdn</li>
+ * <li>admin with user role on sdn</li>
+ * <li>user with user role on sdn</li>
+ * </ol>
+ *
+ * @author peter.mellquist@hp.com
+ * @author saichler@cisco.com
+ */
+public class StoreBuilder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StoreBuilder.class);
+
+    public static void init(IIDMStore store) throws IDMStoreException {
+        LOG.info("creating idmlight schema in store");
+
+        // Check whether the default domain exists. If it exists, then do not
+        // create default data in the store.
+        // TODO Address the fact that someone may delete the sdn domain, or make
+        // sdn mandatory.
+        Domain defaultDomain = store.readDomain(IIDMStore.DEFAULT_DOMAIN);
+        if (defaultDomain != null) {
+            LOG.info("Found default domain in Store, skipping insertion of default data");
+            return;
+        }
+
+        // make domain
+        Domain domain = new Domain();
+        User adminUser = new User();
+        User userUser = new User();
+        Role adminRole = new Role();
+        Role userRole = new Role();
+        domain.setEnabled(true);
+        domain.setName(IIDMStore.DEFAULT_DOMAIN);
+        domain.setDescription("default odl sdn domain");
+        domain = store.writeDomain(domain);
+
+        // Create default users
+        // "admin" user
+        adminUser.setEnabled(true);
+        adminUser.setName("admin");
+        adminUser.setDomainid(domain.getDomainid());
+        adminUser.setDescription("admin user");
+        adminUser.setEmail("");
+        adminUser.setPassword("admin");
+        adminUser = store.writeUser(adminUser);
+        // "user" user
+        userUser.setEnabled(true);
+        userUser.setName("user");
+        userUser.setDomainid(domain.getDomainid());
+        userUser.setDescription("user user");
+        userUser.setEmail("");
+        userUser.setPassword("user");
+        userUser = store.writeUser(userUser);
+
+        // Create default Roles ("admin" and "user")
+        adminRole.setName("admin");
+        adminRole.setDomainid(domain.getDomainid());
+        adminRole.setDescription("a role for admins");
+        adminRole = store.writeRole(adminRole);
+        userRole.setName("user");
+        userRole.setDomainid(domain.getDomainid());
+        userRole.setDescription("a role for users");
+        userRole = store.writeRole(userRole);
+
+        // Create default grants
+        Grant grant = new Grant();
+        grant.setDomainid(domain.getDomainid());
+        grant.setUserid(userUser.getUserid());
+        grant.setRoleid(userRole.getRoleid());
+        grant = store.writeGrant(grant);
+
+        grant.setDomainid(domain.getDomainid());
+        grant.setUserid(adminUser.getUserid());
+        grant.setRoleid(userRole.getRoleid());
+        grant = store.writeGrant(grant);
+
+        grant.setDomainid(domain.getDomainid());
+        grant.setUserid(adminUser.getUserid());
+        grant.setRoleid(adminRole.getRoleid());
+        grant = store.writeGrant(grant);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/DomainHandler.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/DomainHandler.java
new file mode 100644
index 00000000..7ddc0748
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/DomainHandler.java
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.model.Claim;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.UserPwd;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.aaa.idm.IdmLightProxy;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * REST application used to manipulate the H2 database domains table. The REST
+ * endpoint is <code>/auth/v1/domains</code>.
+ *
+ * The following provides examples of curl commands and payloads to utilize the
+ * domains REST endpoint:
+ *
+ * <b>Get All Domains</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/domains</code>
+ *
+ * <b>Get A Specific Domain</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/domains/{id}</code>
+ *
+ * <b>Create A Domain</b>
+ * <code>curl -u admin:admin -X POST -H "Content-Type: application/json" --data-binary {@literal @}domain.json http://{HOST}:{PORT}/auth/v1/domains</code>
+ * Example domain.json <code>{
+ *   "description": "new domain",
+ *   "enabled", "true",
+ *   "name", "not sdn"
+ * }</code>
+ *
+ * <b>Update A Domain</b>
+ * <code>curl -u admin:admin -X PUT -H "Content-Type: application/json" --data-binary {@literal @}domain.json http://{HOST}:{PORT}/auth/v1/domains</code>
+ * Example domain.json <code>{
+ *   "description": "new domain description",
+ *   "enabled", "true",
+ *   "name", "not sdn"
+ * }</code>
+ *
+ * @author peter.mellquist@hp.com
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+@Path("/v1/domains")
+public class DomainHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DomainHandler.class);
+
+    /**
+     * Extracts all domains.
+     *
+     * @return a response with all domains stored in the H2 database
+     */
+    @GET
+    @Produces("application/json")
+    public Response getDomains() {
+        LOG.info("Get /domains");
+        Domains domains = null;
+        try {
+            domains = AAAIDMLightModule.getStore().getDomains();
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domains");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        return Response.ok(domains).build();
+    }
+
+    /**
+     * Extracts the domain represented by <code>domainId</code>.
+     *
+     * @param domainId the string domain (i.e., "sdn")
+     * @return a response with the specified domain
+     */
+    @GET
+    @Path("/{id}")
+    @Produces("application/json")
+    public Response getDomain(@PathParam("id") String domainId) {
+        LOG.info("Get /domains/{}", domainId);
+        Domain domain = null;
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(domainId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+
+        if (domain == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! domain id :" + domainId);
+            return Response.status(404).entity(idmerror).build();
+        }
+        return Response.ok(domain).build();
+    }
+
+    /**
+     * Creates a domain.  The name attribute is required for domain creation.
+     * Enabled and description fields are optional.  Optional fields default
+     * in the following manner:
+     * <code>enabled</code>: <code>false</code>
+     * <code>description</code>: An empty string (<code>""</code>).
+     *
+     * @param info passed from Jersey
+     * @param domain designated by the REST payload
+     * @return A response stating success or failure of domain creation.
+     */
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response createDomain(@Context UriInfo info, Domain domain) {
+        LOG.info("Post /domains");
+        try {
+            if (domain.isEnabled() == null) {
+                domain.setEnabled(false);
+            }
+            if (domain.getName() == null) {
+                domain.setName("");
+            }
+            if (domain.getDescription() == null) {
+                domain.setDescription("");
+            }
+            domain = AAAIDMLightModule.getStore().writeDomain(domain);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error creating domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        return Response.status(201).entity(domain).build();
+    }
+
+    /**
+     * Updates a domain.
+     *
+     * @param info passed from Jersey
+     * @param domain the REST payload
+     * @param domainId the last part of the path, containing the specified domain id
+     * @return A response stating success or failure of domain update.
+     */
+    @PUT
+    @Path("/{id}")
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response putDomain(@Context UriInfo info, Domain domain, @PathParam("id") String domainId) {
+        LOG.info("Put /domains/{}", domainId);
+        try {
+            domain.setDomainid(domainId);
+            domain = AAAIDMLightModule.getStore().updateDomain(domain);
+            if (domain == null) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("Not found! Domain id :" + domainId);
+                return Response.status(404).entity(idmerror).build();
+            }
+            IdmLightProxy.clearClaimCache();
+            return Response.status(200).entity(domain).build();
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error putting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+    }
+
+    /**
+     * Deletes a domain.
+     *
+     * @param info passed from Jersey
+     * @param domainId the last part of the path, containing the specified domain id
+     * @return A response stating success or failure of domain deletion.
+     */
+    @DELETE
+    @Path("/{id}")
+    public Response deleteDomain(@Context UriInfo info, @PathParam("id") String domainId) {
+        LOG.info("Delete /domains/{}", domainId);
+
+        try {
+            Domain domain = AAAIDMLightModule.getStore().deleteDomain(domainId);
+            if (domain == null) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("Not found! Domain id :" + domainId);
+                return Response.status(404).entity(idmerror).build();
+            }
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error deleting Domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        IdmLightProxy.clearClaimCache();
+        return Response.status(204).build();
+    }
+
+    /**
+     * Creates a grant.  A grant defines the role a particular user is given on
+     * a particular domain.  For example, by default, AAA installs a grant for
+     * the "admin" user, granting permission to act with "admin" role on the
+     * "sdn" domain.
+     *
+     * @param info passed from Jersey
+     * @param domainId the domain the user is allowed to access
+     * @param userId the user that is allowed to access the domain
+     * @param grant the payload containing role access controls
+     * @return A response stating success or failure of grant creation.
+     */
+    @POST
+    @Path("/{did}/users/{uid}/roles")
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response createGrant(@Context UriInfo info, @PathParam("did") String domainId,
+            @PathParam("uid") String userId, Grant grant) {
+        LOG.info("Post /domains/{}/users/{}/roles", domainId, userId);
+        Domain domain = null;
+        User user = null;
+        Role role = null;
+        String roleId = null;
+
+        // validate domain id
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(domainId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (domain == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! domain id :" + domainId);
+            return Response.status(404).entity(idmerror).build();
+        }
+        grant.setDomainid(domainId);
+
+        try {
+            user = AAAIDMLightModule.getStore().readUser(userId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting user");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (user == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! User id :" + userId);
+            return Response.status(404).entity(idmerror).build();
+        }
+        grant.setUserid(userId);
+
+        // validate role id
+        try {
+            roleId = grant.getRoleid();
+            LOG.info("roleid = {}", roleId);
+        } catch (NumberFormatException nfe) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Invalid Role id :" + grant.getRoleid());
+            return Response.status(404).entity(idmerror).build();
+        }
+        try {
+            role = AAAIDMLightModule.getStore().readRole(roleId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting role");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (role == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! role :" + grant.getRoleid());
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        // see if grant already exists for this
+        try {
+            Grant existingGrant = AAAIDMLightModule.getStore().readGrant(domainId, userId, roleId);
+            if (existingGrant != null) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("Grant already exists for did:" + domainId + " uid:" + userId
+                        + " rid:" + roleId);
+                return Response.status(403).entity(idmerror).build();
+            }
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error creating grant");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+
+        // create grant
+        try {
+            grant = AAAIDMLightModule.getStore().writeGrant(grant);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error creating grant");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+
+        IdmLightProxy.clearClaimCache();
+        return Response.status(201).entity(grant).build();
+    }
+
+    /**
+     * Used to validate user access.
+     *
+     * @param info passed from Jersey
+     * @param domainId the domain in question
+     * @param userpwd the password attempt
+     * @return A response stating success or failure of user validation.
+     */
+    @POST
+    @Path("/{did}/users/roles")
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response validateUser(@Context UriInfo info, @PathParam("did") String domainId,
+            UserPwd userpwd) {
+
+        LOG.info("GET /domains/{}/users", domainId);
+        Domain domain = null;
+        Claim claim = new Claim();
+        List<Role> roleList = new ArrayList<Role>();
+
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(domainId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (domain == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! Domain id :" + domainId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        // check request body for username and pwd
+        String username = userpwd.getUsername();
+        if (username == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("username not specfied in request body");
+            return Response.status(400).entity(idmerror).build();
+        }
+        String pwd = userpwd.getUserpwd();
+        if (pwd == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("userpwd not specfied in request body");
+            return Response.status(400).entity(idmerror).build();
+        }
+
+        // find userid for user
+        try {
+            Users users = AAAIDMLightModule.getStore().getUsers(username, domainId);
+            List<User> userList = users.getUsers();
+            if (userList.size() == 0) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("did not find username: " + username);
+                return Response.status(404).entity(idmerror).build();
+            }
+            User user = userList.get(0);
+            String userPwd = user.getPassword();
+            String reqPwd = userpwd.getUserpwd();
+            if (!userPwd.equals(reqPwd)) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("password does not match for username: " + username);
+                return Response.status(401).entity(idmerror).build();
+            }
+            claim.setDomainid(domainId);
+            claim.setUsername(username);
+            claim.setUserid(user.getUserid());
+            try {
+                Grants grants = AAAIDMLightModule.getStore().getGrants(domainId, user.getUserid());
+                List<Grant> grantsList = grants.getGrants();
+                for (int i = 0; i < grantsList.size(); i++) {
+                    Grant grant = grantsList.get(i);
+                    Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
+                    roleList.add(role);
+                }
+            } catch (IDMStoreException se) {
+                LOG.error("StoreException: ", se);
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("Internal error getting Roles");
+                idmerror.setDetails(se.getMessage());
+                return Response.status(500).entity(idmerror).build();
+            }
+            claim.setRoles(roleList);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting user");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+
+        return Response.ok(claim).build();
+    }
+
+    /**
+     * Get the grants for a user on a domain.
+     *
+     * @param info passed from Jersey
+     * @param domainId the domain in question
+     * @param userId the user in question
+     * @return A response containing the grants for a user on a domain.
+     */
+    @GET
+    @Path("/{did}/users/{uid}/roles")
+    @Produces("application/json")
+    public Response getRoles(@Context UriInfo info, @PathParam("did") String domainId,
+            @PathParam("uid") String userId) {
+        LOG.info("GET /domains/{}/users/{}/roles", domainId, userId);
+        Domain domain = null;
+        User user = null;
+        Roles roles = new Roles();
+        List<Role> roleList = new ArrayList<Role>();
+
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(domainId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (domain == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! Domain id :" + domainId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        try {
+            user = AAAIDMLightModule.getStore().readUser(userId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting user");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (user == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! User id :" + userId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        try {
+            Grants grants = AAAIDMLightModule.getStore().getGrants(domainId, userId);
+            List<Grant> grantsList = grants.getGrants();
+            for (int i = 0; i < grantsList.size(); i++) {
+                Grant grant = grantsList.get(i);
+                Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
+                roleList.add(role);
+            }
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting Roles");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+
+        roles.setRoles(roleList);
+        return Response.ok(roles).build();
+    }
+
+    /**
+     * Delete a grant.
+     *
+     * @param info passed from Jersey
+     * @param domainId the domain for the grant
+     * @param userId the user for the grant
+     * @param roleId the role for the grant
+     * @return A response stating success or failure of the grant deletion.
+     */
+    @DELETE
+    @Path("/{did}/users/{uid}/roles/{rid}")
+    public Response deleteGrant(@Context UriInfo info, @PathParam("did") String domainId,
+            @PathParam("uid") String userId, @PathParam("rid") String roleId) {
+        Domain domain = null;
+        User user = null;
+        Role role = null;
+
+        try {
+            domain = AAAIDMLightModule.getStore().readDomain(domainId);
+        } catch (IDMStoreException se) {
+            LOG.error("Error deleting Grant  : ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting domain");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (domain == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! Domain id :" + domainId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        try {
+            user = AAAIDMLightModule.getStore().readUser(userId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException : ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting user");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (user == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! User id :" + userId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        try {
+            role = AAAIDMLightModule.getStore().readRole(roleId);
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error getting Role");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        if (role == null) {
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Not found! Role id :" + roleId);
+            return Response.status(404).entity(idmerror).build();
+        }
+
+        // see if grant already exists
+        try {
+            Grant existingGrant = AAAIDMLightModule.getStore().readGrant(domainId, userId, roleId);
+            if (existingGrant == null) {
+                IDMError idmerror = new IDMError();
+                idmerror.setMessage("Grant does not exist for did:" + domainId + " uid:" + userId
+                        + " rid:" + roleId);
+                return Response.status(404).entity(idmerror).build();
+            }
+            existingGrant = AAAIDMLightModule.getStore().deleteGrant(existingGrant.getGrantid());
+        } catch (IDMStoreException se) {
+            LOG.error("StoreException: ", se);
+            IDMError idmerror = new IDMError();
+            idmerror.setMessage("Internal error creating grant");
+            idmerror.setDetails(se.getMessage());
+            return Response.status(500).entity(idmerror).build();
+        }
+        IdmLightProxy.clearClaimCache();
+        return Response.status(204).build();
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/RoleHandler.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/RoleHandler.java
new file mode 100644
index 00000000..34a60c0c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/RoleHandler.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.idm.IdmLightApplication;
+import org.opendaylight.aaa.idm.IdmLightProxy;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * REST application used to manipulate the H2 database roles table. The REST
+ * endpoint is <code>/auth/v1/roles</code>.
+ *
+ * The following provides examples of curl commands and payloads to utilize the
+ * roles REST endpoint:
+ *
+ * <b>Get All Roles</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/roles</code>
+ *
+ * <b>Get A Specific Role</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/roles/{id}</code>
+ *
+ * <b>Create A Role</b>
+ * <code>curl -u admin:admin -X POST -H "Content-Type: application/json" --data-binary {@literal @}role.json http://{HOST}:{PORT}/auth/v1/roles</code>
+ * An example of role.json:
+ * <code>{
+ *  "name":"IT Administrator",
+ *  "description":"A user role for IT admins"
+ * }</code>
+ *
+ * <b>Update A Role</b>
+ * <code>curl -u admin:admin -X PUT -H "Content-Type: application/json" --data-binary {@literal @}role.json http://{HOST}:{PORT}/auth/v1/roles/{id}</code>
+ * An example of role.json:
+ * <code>{
+ *  "name":"IT Administrator Limited",
+ *  "description":"A user role for IT admins who can only do one thing"
+ * }</code>
+ *
+ * @author peter.mellquist@hp.com
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+@Path("/v1/roles")
+public class RoleHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(RoleHandler.class);
+
+    /**
+     * Extracts all roles.
+     *
+     * @return A response with all roles in the H2 database, or internal error if one is encountered
+     */
+    @GET
+    @Produces("application/json")
+    public Response getRoles() {
+        LOG.info("get /roles");
+        Roles roles = null;
+        try {
+            roles = AAAIDMLightModule.getStore().getRoles();
+        } catch (IDMStoreException se) {
+            return new IDMError(500, "internal error getting roles", se.getMessage()).response();
+        }
+        return Response.ok(roles).build();
+    }
+
+    /**
+     * Extract a specific role identified by <code>id</code>
+     *
+     * @param id the String id for the role
+     * @return A response with the role identified by <code>id</code>, or internal error if one is encountered
+     */
+    @GET
+    @Path("/{id}")
+    @Produces("application/json")
+    public Response getRole(@PathParam("id") String id) {
+        LOG.info("get /roles/{}", id);
+        Role role = null;
+
+        try {
+            role = AAAIDMLightModule.getStore().readRole(id);
+        } catch (IDMStoreException se) {
+            return new IDMError(500, "internal error getting roles", se.getMessage()).response();
+        }
+
+        if (role == null) {
+            return new IDMError(404, "role not found id :" + id, "").response();
+        }
+        return Response.ok(role).build();
+    }
+
+    /**
+     * Creates a role.
+     *
+     * @param info passed from Jersey
+     * @param role the role JSON payload
+     * @return A response stating success or failure of role creation, or internal error if one is encountered
+     */
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response createRole(@Context UriInfo info, Role role) {
+        LOG.info("Post /roles");
+        try {
+            // TODO: role names should be unique!
+            // name
+            if (role.getName() == null) {
+                return new IDMError(404, "name must be defined on role create", "").response();
+            } else if (role.getName().length() > IdmLightApplication.MAX_FIELD_LEN) {
+                return new IDMError(400, "role name max length is :"
+                        + IdmLightApplication.MAX_FIELD_LEN, "").response();
+            }
+
+            // domain
+            if (role.getDomainid() == null) {
+                return new IDMError(404,
+                        "The role's domain must be defined on role when creating a role.", "")
+                        .response();
+            } else if (role.getDomainid().length() > IdmLightApplication.MAX_FIELD_LEN) {
+                return new IDMError(400, "role domain max length is :"
+                        + IdmLightApplication.MAX_FIELD_LEN, "").response();
+            }
+
+            // description
+            if (role.getDescription() == null) {
+                role.setDescription("");
+            } else if (role.getDescription().length() > IdmLightApplication.MAX_FIELD_LEN) {
+                return new IDMError(400, "role description max length is :"
+                        + IdmLightApplication.MAX_FIELD_LEN, "").response();
+            }
+
+            role = AAAIDMLightModule.getStore().writeRole(role);
+        } catch (IDMStoreException se) {
+            return new IDMError(500, "internal error creating role", se.getMessage()).response();
+        }
+
+        return Response.status(201).entity(role).build();
+    }
+
+    /**
+     * Updates a specific role identified by <code>id</code>.
+     *
+     * @param info passed from Jersey
+     * @param role the role JSON payload
+     * @param id the String id for the role
+     * @return A response stating success or failure of role update, or internal error if one occurs
+     */
+    @PUT
+    @Path("/{id}")
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response putRole(@Context UriInfo info, Role role, @PathParam("id") String id) {
+        LOG.info("put /roles/{}", id);
+
+        try {
+            role.setRoleid(id);
+
+            // name
+            // TODO: names should be unique
+            if ((role.getName() != null)
+                    && (role.getName().length() > IdmLightApplication.MAX_FIELD_LEN)) {
+                return new IDMError(400, "role name max length is :"
+                        + IdmLightApplication.MAX_FIELD_LEN, "").response();
+            }
+
+            // description
+            if ((role.getDescription() != null)
+                    && (role.getDescription().length() > IdmLightApplication.MAX_FIELD_LEN)) {
+                return new IDMError(400, "role description max length is :"
+                        + IdmLightApplication.MAX_FIELD_LEN, "").response();
+            }
+
+            role = AAAIDMLightModule.getStore().updateRole(role);
+            if (role == null) {
+                return new IDMError(404, "role id not found :" + id, "").response();
+            }
+            IdmLightProxy.clearClaimCache();
+            return Response.status(200).entity(role).build();
+        } catch (IDMStoreException se) {
+            return new IDMError(500, "internal error putting role", se.getMessage()).response();
+        }
+    }
+
+    /**
+     * Delete a role.
+     *
+     * @param info passed from Jersey
+     * @param id the String id for the role
+     * @return A response stating success or failure of user deletion, or internal error if one occurs
+     */
+    @DELETE
+    @Path("/{id}")
+    public Response deleteRole(@Context UriInfo info, @PathParam("id") String id) {
+        LOG.info("Delete /roles/{}", id);
+
+        try {
+            Role role = AAAIDMLightModule.getStore().deleteRole(id);
+            if (role == null) {
+                return new IDMError(404, "role id not found :" + id, "").response();
+            }
+        } catch (IDMStoreException se) {
+            return new IDMError(500, "internal error deleting role", se.getMessage()).response();
+        }
+        IdmLightProxy.clearClaimCache();
+        return Response.status(204).build();
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/UserHandler.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/UserHandler.java
new file mode 100644
index 00000000..1649faa2
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/UserHandler.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest;
+
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.aaa.idm.IdmLightApplication;
+import org.opendaylight.aaa.idm.IdmLightProxy;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * REST application used to manipulate the H2 database users table. The REST
+ * endpoint is <code>/auth/v1/users</code>.
+ *
+ * The following provides examples of how curl commands and payloads to utilize
+ * the users REST endpoint:
+ *
+ * <b>Get All Users</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/users</code>
+ *
+ * <b>Get A Specific User</b>
+ * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/users/{id}</code>
+ *
+ * <b>Create A User</b>
+ * <code>curl -u admin:admin -X POST -H "Content-type: application/json" --data-binary {@literal @}user.json http://{HOST}:{PORT}/auth/v1/users</code>
+ * An example of user.json file is:
+ * <code>{
+ *   "name": "admin2",
+ *   "password", "admin2",
+ *   "domain": "sdn"
+ * }</code>
+ *
+ * <b>Update A User</b>
+ * <code>curl -u admin:admin -X PUT -H "Content-type: application/json" --data-binary {@literal @}user.json http://{HOST}:{PORT}/auth/v1/users/{id}</code>
+ * An example of user.json file is:
+ * <code>{
+ *   "name": "admin2",
+ *   "password", "admin2",
+ *   "domain": "sdn",
+ *   "description", "Simple description."
+ * }</code>
+ *
+ * <b>Delete A User</b>
+ * <code>curl -u admin:admin -X DELETE http://{HOST}:{PORT}/auth/v1/users/{id}</code>
+ *
+ * @author peter.mellquist@hp.com
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+@Path("/v1/users")
+public class UserHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserHandler.class);
+
+    /**
+     * If a user is created through the <code>/auth/v1/users</code> rest
+     * endpoint without a password, the default password is assigned to the
+     * user.
+     */
+    private final static String DEFAULT_PWD = "changeme";
+
+    /**
+     * When an HTTP GET is performed on <code>/auth/v1/users</code>, the
+     * password field is replaced with <code>REDACTED_PASSWORD</code> for
+     * security reasons.
+     */
+    private static final String REDACTED_PASSWORD = "**********";
+
+    /**
+     * When an HTTP GET is performed on <code>/auth/v1/users</code>, the salt
+     * field is replaced with <code>REDACTED_SALT</code> for security reasons.
+     */
+    private static final String REDACTED_SALT = "**********";
+
+    /**
+     * When creating a user, the description is optional and defaults to an
+     * empty string.
+     */
+    private static final String DEFAULT_DESCRIPTION = "";
+
+    /**
+     * When creating a user, the email is optional and defaults to an empty
+     * string.
+     */
+    private static final String DEFAULT_EMAIL = "";
+
+    /**
+     * Extracts all users. The password and salt fields are redacted for
+     * security reasons.
+     *
+     * @return A response containing the users, or internal error if one occurs
+     */
+    @GET
+    @Produces("application/json")
+    public Response getUsers() {
+        LOG.info("GET /auth/v1/users  (extracts all users)");
+
+        try {
+            final Users users = AAAIDMLightModule.getStore().getUsers();
+
+            // Redact the password and salt for security purposes.
+            final Collection<User> usersList = users.getUsers();
+            for (User user : usersList) {
+                redactUserPasswordInfo(user);
+            }
+
+            return Response.ok(users).build();
+        } catch (IDMStoreException se) {
+            return internalError("getting", se);
+        }
+    }
+
+    /**
+     * Extracts the user represented by <code>id</code>. The password and salt
+     * fields are redacted for security reasons.
+     *
+     * @param id the unique id of representing the user account
+     * @return A response with the user information, or internal error if one occurs
+     */
+    @GET
+    @Path("/{id}")
+    @Produces("application/json")
+    public Response getUser(@PathParam("id") String id) {
+        LOG.info("GET auth/v1/users/ {}  (extract user with specified id)", id);
+
+        try {
+            final User user = AAAIDMLightModule.getStore().readUser(id);
+
+            if (user == null) {
+                final String error = "user not found! id: " + id;
+                return new IDMError(404, error, "").response();
+            }
+
+            // Redact the password and salt for security purposes.
+            redactUserPasswordInfo(user);
+
+            return Response.ok(user).build();
+        } catch (IDMStoreException se) {
+            return internalError("getting", se);
+        }
+    }
+
+    /**
+     * REST endpoint to create a user. Name and domain are required attributes,
+     * and all other fields (description, email, password, enabled) are
+     * optional. Optional fields default in the following manner:
+     * <code>description</code>: An empty string (<code>""</code>).
+     * <code>email</code>: An empty string (<code>""</code>).
+     * <code>password</code>: <code>changeme</code> <code>enabled</code>:
+     * <code>true</code>
+     *
+     * If a password is not provided, please ensure you change the default
+     * password ASAP for security reasons!
+     *
+     * @param info passed from Jersey
+     * @param user the user defined in the JSON payload
+     * @return A response stating success or failure of user creation
+     */
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response createUser(@Context UriInfo info, User user) {
+        LOG.info("POST /auth/v1/users  (create a user with the specified payload");
+
+        // The "enabled" field is optional, and defaults to true.
+        if (user.isEnabled() == null) {
+            user.setEnabled(true);
+        }
+
+        // The "name" field is required.
+        final String userName = user.getName();
+        if (userName == null) {
+            return missingRequiredField("name");
+        }
+        // The "name" field has a maximum length.
+        if (userName.length() > IdmLightApplication.MAX_FIELD_LEN) {
+            return providedFieldTooLong("name", IdmLightApplication.MAX_FIELD_LEN);
+        }
+
+        // The "domain field is required.
+        final String domainId = user.getDomainid();
+        if (domainId == null) {
+            return missingRequiredField("domain");
+        }
+        // The "domain" field has a maximum length.
+        if (domainId.length() > IdmLightApplication.MAX_FIELD_LEN) {
+            return providedFieldTooLong("domain", IdmLightApplication.MAX_FIELD_LEN);
+        }
+
+        // The "description" field is optional and defaults to "".
+        final String userDescription = user.getDescription();
+        if (userDescription == null) {
+            user.setDescription(DEFAULT_DESCRIPTION);
+        }
+        // The "description" field has a maximum length.
+        if (userDescription.length() > IdmLightApplication.MAX_FIELD_LEN) {
+            return providedFieldTooLong("description", IdmLightApplication.MAX_FIELD_LEN);
+        }
+
+        // The "email" field is optional and defaults to "".
+        final String userEmail = user.getEmail();
+        if (userEmail == null) {
+            user.setEmail(DEFAULT_EMAIL);
+        }
+        if (userEmail.length() > IdmLightApplication.MAX_FIELD_LEN) {
+            return providedFieldTooLong("email", IdmLightApplication.MAX_FIELD_LEN);
+        }
+        // TODO add a check on email format here.
+
+        // The "password" field is optional and defautls to "changeme".
+        final String userPassword = user.getPassword();
+        if (userPassword == null) {
+            user.setPassword(DEFAULT_PWD);
+        } else if (userPassword.length() > IdmLightApplication.MAX_FIELD_LEN) {
+            return providedFieldTooLong("password", IdmLightApplication.MAX_FIELD_LEN);
+        }
+
+        try {
+            // At this point, fields have been properly verified. Create the
+            // user account
+            final User createdUser = AAAIDMLightModule.getStore().writeUser(user);
+            user.setUserid(createdUser.getUserid());
+        } catch (IDMStoreException se) {
+            return internalError("creating", se);
+        }
+
+        // Redact the password and salt for security reasons.
+        redactUserPasswordInfo(user);
+        // TODO report back to the client a warning message to change the
+        // default password if none was specified.
+        return Response.status(201).entity(user).build();
+    }
+
+    /**
+     * REST endpoint to update a user account.
+     *
+     * @param info passed from Jersey
+     * @param user the user defined in the JSON payload
+     * @param id the unique id for the user that will be updated
+     * @return A response stating success or failure of the user update
+     */
+    @PUT
+    @Path("/{id}")
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response putUser(@Context UriInfo info, User user, @PathParam("id") String id) {
+
+        LOG.info("PUT /auth/v1/users/{}  (Updates a user account)", id);
+
+        try {
+            user.setUserid(id);
+
+            if (checkInputFieldLength(user.getPassword())) {
+                return providedFieldTooLong("password", IdmLightApplication.MAX_FIELD_LEN);
+            }
+
+            if (checkInputFieldLength(user.getName())) {
+                return providedFieldTooLong("name", IdmLightApplication.MAX_FIELD_LEN);
+            }
+
+            if (checkInputFieldLength(user.getDescription())) {
+                return providedFieldTooLong("description", IdmLightApplication.MAX_FIELD_LEN);
+            }
+
+            if (checkInputFieldLength(user.getEmail())) {
+                return providedFieldTooLong("email", IdmLightApplication.MAX_FIELD_LEN);
+            }
+
+            if (checkInputFieldLength(user.getDomainid())) {
+                return providedFieldTooLong("domain", IdmLightApplication.MAX_FIELD_LEN);
+            }
+
+            user = AAAIDMLightModule.getStore().updateUser(user);
+            if (user == null) {
+                return new IDMError(404, String.format("User not found for id %s", id), "").response();
+            }
+
+            IdmLightProxy.clearClaimCache();
+
+            // Redact the password and salt for security reasons.
+            redactUserPasswordInfo(user);
+            return Response.status(200).entity(user).build();
+        } catch (IDMStoreException se) {
+            return internalError("updating", se);
+        }
+    }
+
+    /**
+     * REST endpoint to delete a user account.
+     *
+     * @param info passed from Jersey
+     * @param id the unique id of the user which is being deleted
+     * @return A response stating success or failure of user deletion
+     */
+    @DELETE
+    @Path("/{id}")
+    public Response deleteUser(@Context UriInfo info, @PathParam("id") String id) {
+        LOG.info("DELETE /auth/v1/users/{}  (Delete a user account)", id);
+
+        try {
+            final User user = AAAIDMLightModule.getStore().deleteUser(id);
+
+            if (user == null) {
+                return new IDMError(404,
+                        String.format("Error deleting user.  " +
+                                      "Couldn't find user with id %s", id),
+                                      "").response();
+            }
+        } catch (IDMStoreException se) {
+            return internalError("deleting", se);
+        }
+
+        // Successfully deleted the user; report success to the client.
+        IdmLightProxy.clearClaimCache();
+        return Response.status(204).build();
+    }
+
+    /**
+     * Creates a <code>Response</code> related to an internal server error.
+     *
+     * @param verbal such as "creating", "deleting", "updating"
+     * @param e The exception, which is propagated in the response
+     * @return A response containing internal error with specific reasoning
+     */
+    private Response internalError(final String verbal, final Exception e) {
+        LOG.error("There was an internal error {} the user", verbal, e);
+        return new IDMError(500,
+                String.format("There was an internal error %s the user", verbal),
+                e.getMessage()).response();
+    }
+
+    /**
+     * Creates a <code>Response</code> related to the user not providing a
+     * required field.
+     *
+     * @param fieldName the name of the field which is missing
+     * @return A response explaining that the request is missing a field
+     */
+    private Response missingRequiredField(final String fieldName) {
+
+        return new IDMError(400,
+                String.format("%s is required to create the user account.  " +
+                              "Please provide a %s in your payload.", fieldName, fieldName),
+                              "").response();
+    }
+
+    /**
+     * Creates a <code>Response</code> related to the user providing a field
+     * that is too long.
+     *
+     * @param fieldName the name of the field that is too long
+     * @param maxFieldLength the maximum length of <code>fieldName</code>
+     * @return A response containing the bad field and the maximum field length
+     */
+    private Response providedFieldTooLong(final String fieldName, final int maxFieldLength) {
+
+        return new IDMError(400,
+                getProvidedFieldTooLongMessage(fieldName, maxFieldLength),
+                "").response();
+    }
+
+    /**
+     * Creates the client-facing message related to the user providing a field
+     * that is too long.
+     *
+     * @param fieldName the name of the field that is too long
+     * @param maxFieldLength the maximum length of <code>fieldName</code>
+     * @return
+     */
+    private static String getProvidedFieldTooLongMessage(final String fieldName,
+            final int maxFieldLength) {
+
+        return String.format("The provided {} field is too long.  " +
+                             "The max length is {}.", fieldName, maxFieldLength);
+    }
+
+    /**
+     * Prepares a user account for output by redacting the appropriate fields.
+     * This method side-effects the <code>user</code> parameter.
+     *
+     * @param user the user account which will have fields redacted
+     */
+    private static void redactUserPasswordInfo(final User user) {
+        user.setPassword(REDACTED_PASSWORD);
+        user.setSalt(REDACTED_SALT);
+    }
+
+    /**
+     * Validate the input field length
+     *
+     * @param inputField
+     * @return true if input field bigger than the MAX_FIELD_LEN
+     */
+    private boolean checkInputFieldLength(final String inputField) {
+        return inputField != null && (inputField.length() > IdmLightApplication.MAX_FIELD_LEN);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/VersionHandler.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/VersionHandler.java
new file mode 100644
index 00000000..f865162a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/aaa/idm/rest/VersionHandler.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+
+import org.opendaylight.aaa.api.model.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author peter.mellquist@hp.com
+ *
+ */
+@Deprecated
+@Path("/")
+public class VersionHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(VersionHandler.class);;
+
+    protected static String CURRENT_VERSION = "v1";
+    protected static String LAST_UPDATED = "2014-04-18T18:30:02.25Z";
+    protected static String CURRENT_STATUS = "CURRENT";
+
+    @GET
+    @Produces("application/json")
+    public Version getVersion(@Context HttpServletRequest request) {
+        LOG.info("Get /");
+        Version version = new Version();
+        version.setId(CURRENT_VERSION);
+        version.setUpdated(LAST_UPDATED);
+        version.setStatus(CURRENT_STATUS);
+        return version;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModule.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModule.java
new file mode 100644
index 00000000..d6872635
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModule.java
@@ -0,0 +1,90 @@
+package org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204;
+
+import org.opendaylight.aaa.api.CredentialAuth;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.idm.IdmLightProxy;
+import org.opendaylight.aaa.idm.StoreBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AAAIDMLightModule extends org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AbstractAAAIDMLightModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AAAIDMLightModule.class);
+    private BundleContext bundleContext = null;
+    private static volatile IIDMStore store = null;
+
+    public AAAIDMLightModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public AAAIDMLightModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final IdmLightProxy proxy = new IdmLightProxy();
+        final ServiceRegistration<?> idmService = bundleContext.registerService(IdMService.class.getName(), proxy, null);
+        final ServiceRegistration<?> clientAuthService = bundleContext.registerService(CredentialAuth.class.getName(), proxy, null);
+
+        final ServiceTracker<IIDMStore, IIDMStore> storeServiceTracker = new ServiceTracker<>(bundleContext, IIDMStore.class,
+                new ServiceTrackerCustomizer<IIDMStore, IIDMStore>() {
+                    @Override
+                    public IIDMStore addingService(ServiceReference<IIDMStore> reference) {
+                        store = reference.getBundle().getBundleContext().getService(reference);
+                        LOG.info("IIDMStore service {} was found", store.getClass());
+                        try {
+                            StoreBuilder.init(store);
+                        } catch (IDMStoreException e) {
+                            LOG.error("Failed to initialize data in store", e);
+                        }
+
+                        return store;
+                    }
+
+                    @Override
+                    public void modifiedService(ServiceReference<IIDMStore> reference, IIDMStore service) {
+                    }
+
+                    @Override
+                    public void removedService(ServiceReference<IIDMStore> reference, IIDMStore service) {
+                    }
+                });
+
+        storeServiceTracker.open();
+
+        LOG.info("AAA IDM Light Module Initialized");
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                idmService.unregister();
+                clientAuthService.unregister();
+                storeServiceTracker.close();
+            }
+        };
+    }
+
+    public void setBundleContext(BundleContext b){
+        this.bundleContext = b;
+    }
+
+    public static final IIDMStore getStore(){
+        return store;
+    }
+
+    public static final void setStore(IIDMStore s){
+        store = s;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModuleFactory.java b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModuleFactory.java
new file mode 100644
index 00000000..de277da8
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/java/org/opendaylight/yang/gen/v1/config/aaa/authn/idmlight/rev151204/AAAIDMLightModuleFactory.java
@@ -0,0 +1,29 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: aaa-idmlight yang module local name: aaa-idmlight
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Dec 04 11:37:37 PST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class AAAIDMLightModuleFactory extends org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AbstractAAAIDMLightModuleFactory {
+    @Override
+    public AAAIDMLightModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, AAAIDMLightModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+        AAAIDMLightModule module = super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public AAAIDMLightModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        AAAIDMLightModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/WEB-INF/web.xml b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/WEB-INF/web.xml
new file mode 100644
index 00000000..facba131
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/WEB-INF/web.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+    version="3.0">
+
+    <servlet>
+        <servlet-name>IdmLight</servlet-name>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.opendaylight.aaa.idm.IdmLightApplication</param-value>
+        </init-param>
+        <init-param>
+           <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name><param-value>true</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>IdmLight</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <context-param>
+      <param-name>shiroEnvironmentClass</param-name>
+      <param-value>org.opendaylight.aaa.shiro.web.env.KarafIniWebEnvironment</param-value>
+    </context-param>
+
+    <listener>
+        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
+    </listener>
+
+    <filter>
+        <filter-name>ShiroFilter</filter-name>
+        <filter-class>org.opendaylight.aaa.shiro.filters.AAAFilter</filter-class>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>ShiroFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <filter>
+        <filter-name>cross-origin-restconf</filter-name>
+        <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
+        <init-param>
+            <param-name>allowedOrigins</param-name>
+            <param-value>*</param-value>
+        </init-param>
+        <init-param>
+            <param-name>allowedMethods</param-name>
+            <param-value>GET,POST,OPTIONS,DELETE,PUT,HEAD</param-value>
+        </init-param>
+        <init-param>
+            <param-name>allowedHeaders</param-name>
+            <param-value>origin, content-type, accept, authorization, Authorization</param-value>
+        </init-param>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>cross-origin-restconf</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>NB api</web-resource-name>
+            <url-pattern>/*</url-pattern>
+            <http-method>POST</http-method>
+            <http-method>GET</http-method>
+            <http-method>PUT</http-method>
+            <http-method>PATCH</http-method>
+            <http-method>DELETE</http-method>
+            <http-method>HEAD</http-method>
+        </web-resource-collection>
+    </security-constraint>
+
+</web-app>
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/idmtool.py b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/idmtool.py
new file mode 100755
index 00000000..b14a8758
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/idmtool.py
@@ -0,0 +1,255 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2016 Brocade Communications Systems and others.  All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+#
+
+'''
+idmtool
+
+Used to manipulate ODL AAA idm on a node-per-node basis.  Assumes only one domain (sdn)
+since current support in ODL is limited.
+'''
+
+__author__ = "Ryan Goulding"
+__copyright__ = "Copyright (c) 2016 Brocade Communications Systems and others"
+__credits__ = "Ryan Goulding"
+__license__ = "EPL"
+__version__ = "1.0"
+__maintainer__ = "Ryan Goulding"
+__email__ = "ryandgoulding@gmail.com"
+__status__ = "Production"
+
+import argparse, getpass, json, requests, sys
+
+parser = argparse.ArgumentParser('idmtool')
+
+user=''
+hostname='localhost'
+protocol='http'
+port='8181'
+target_host='{}://{}:{}/'.format(protocol, hostname, port)
+
+# main program arguments
+parser.add_argument('user',help='username for BSC node', nargs=1)
+parser.add_argument('--target-host', help="target host node", nargs=1)
+
+subparsers = parser.add_subparsers(help='sub-command help')
+
+# users table related
+list_users = subparsers.add_parser('list-users', help='list all users')
+list_users.set_defaults(func=list_users)
+add_user = subparsers.add_parser('add-user', help='add a user')
+add_user.set_defaults(func=add_user)
+add_user.add_argument('newUser', help='new user name', nargs=1)
+change_password = subparsers.add_parser('change-password', help='change a password')
+change_password.set_defaults(func=change_password)
+change_password.add_argument('userid', help='change the password for a particular userid', nargs=1)
+delete_user = subparsers.add_parser('delete-user', help='delete a user')
+delete_user.add_argument('userid', help='name@sdn', nargs=1)
+delete_user.set_defaults(func=delete_user)
+
+# domains table related
+# only read is defined;  this was done on purpose since the "domain" concept
+# is mostly unsupported in ODL.
+list_domains = subparsers.add_parser('list-domains', help='list all domains')
+list_domains.set_defaults(func=list_domains)
+
+# roles table related
+list_roles = subparsers.add_parser('list-roles', help='list all roles')
+list_roles.set_defaults(func=list_roles)
+add_role = subparsers.add_parser('add-role', help='add a role')
+add_role.add_argument('role', help='role name', nargs=1)
+add_role.set_defaults(func=add_role)
+delete_role = subparsers.add_parser('delete-role', help='delete a role')
+delete_role.add_argument('roleid', help='rolename@sdn', nargs=1)
+delete_role.set_defaults(func=delete_role)
+add_grant = subparsers.add_parser('add-grant', help='add a grant')
+add_grant.set_defaults(func=add_grant)
+add_grant.add_argument('userid', help="username@sdn", nargs=1)
+add_grant.add_argument('roleid', help="role@sdn", nargs=1)
+get_grants = subparsers.add_parser('get-grants', help='get grants for userid on sdn')
+get_grants.set_defaults(func=get_grants)
+get_grants.add_argument('userid', help="username@sdn", nargs=1)
+delete_grant = subparsers.add_parser('delete-grant', help='delete a grant')
+delete_grant.add_argument('userid', help='username@sdn', nargs=1)
+delete_grant.add_argument('roleid', help='role@sdn', nargs=1)
+delete_grant.set_defaults(func=delete_grant)
+
+def process_result(r):
+    ''' Generic method to print result of a REST call '''
+    print ''
+    sc = r.status_code
+    if sc >= 200 and sc < 300:
+        print "command succeeded!"
+        try:
+            res = r.json()
+            if res is not None:
+                print '\njson:\n', json.dumps(res, indent=4, sort_keys=True)
+        except(ValueError):
+            pass
+    elif sc == 401:
+        print "Incorrect Credentials Provided"
+    elif sc == 404:
+        print "RESTconf is either not installed or not initialized yet"
+    elif sc >= 500 and sc < 600:
+        print "Internal Server Error Ocurred"
+    else:
+        print "Unknown error; HTTP status code: {}".format(sc)
+
+def get_request(user, password, url, description, outputResult=True):
+    if outputResult:
+        print description
+    try:
+        r = requests.get(url, auth=(user,password))
+        if outputResult:
+            process_result(r)
+        return r
+    except(requests.exceptions.ConnectionError):
+        if outputResult:
+            print "Unable to connect;  are you sure the controller is up?"
+            sys.exit(1)
+
+def post_request(user, password, url, description, payload, params):
+    print description
+    try:
+        r = requests.post(url, auth=(user,password), data=payload, headers=params)
+        process_result(r)
+    except(requests.exceptions.ConnectionError):
+        print "Unable to connect; are you sure the controller is up?"
+        sys.exit(1)
+
+def put_request(user, password, url, description, payload, params):
+    print description
+    try:
+        r = requests.put(url, auth=(user,password), data=payload, headers=params)
+        process_result(r)
+    except(requests.exceptions.ConnectionError):
+        print "Unable to connect; are you sure the controller is up?"
+        sys.exit(1)
+
+def delete_request(user, password, url, description, payload='', params={'Content-Type':'application/json'}):
+    print description
+    try:
+        r = requests.delete(url, auth=(user,password), data=payload, headers=params)
+        process_result(r)
+    except(requests.exceptions.ConnectionError):
+        print "Unable to connect; are you sure the controller is up?"
+        sys.exit(1)
+
+def poll_new_password():
+    new_password = getpass.getpass(prompt="Enter new password: ")
+    new_password_repeated = getpass.getpass(prompt="Re-enter password: ")
+    if new_password != new_password_repeated:
+        print "Passwords did not match;  cancelling the add_user request"
+        sys.exit(1)
+    return new_password
+
+def list_users(user, password):
+    get_request(user, password, target_host + 'auth/v1/users', 'list_users')
+
+def add_user(user, password, newUser):
+    new_password = poll_new_password()
+    description = 'add_user({})'.format(user)
+    url = target_host + 'auth/v1/users'
+    payload =  {'name':newUser, 'password':new_password, 'description':'', "domainid":"sdn", 'userid':'{}@sdn'.format(newUser), 'email':''}
+    jsonpayload = json.dumps(payload)
+    headers={'Content-Type':'application/json'}
+    post_request(user, password, url, description, jsonpayload, headers)
+
+def delete_user(user, password, userid):
+    url = target_host + 'auth/v1/users/{}'.format(userid)
+    description = 'delete_user({})'.format(userid)
+    delete_request(user, password, url, description)
+
+def change_password(user, password, existingUserId):
+    url = target_host + 'auth/v1/users/{}'.format(existingUserId)
+    r = get_request(user, password, target_host + 'auth/v1/users/{}'.format(existingUserId), 'list_users', outputResult=False)
+    try:
+        existing = r.json()
+        del existing['salt']
+        del existing['password']
+        new_password = poll_new_password()
+        existing['password'] = new_password
+        description='change_password({})'.format(existingUserId)
+        headers={'Content-Type':'application/json'}
+        url = target_host + 'auth/v1/users/{}'.format(existingUserId)
+        put_request(user, password, url, 'change_password({})'.format(user), json.dumps(existing), headers)
+    except(AttributeError):
+        print "Unable to connect;  are you sure the controller is up?"
+        sys.exit(1)
+
+def list_domains(user, password):
+    get_request(user, password, target_host + 'auth/v1/domains', 'list_domains')
+
+def list_roles(user, password):
+    get_request(user, password, target_host + 'auth/v1/roles', 'list_roles')
+
+def add_role(user, password, role):
+    url = target_host + 'auth/v1/roles'
+    description = 'add_role({})'.format(role)
+    payload = {"roleid":'{}@sdn'.format(role), 'name':role, 'description':'', 'domainid':'sdn'}
+    data = json.dumps(payload)
+    headers={'Content-Type':'application/json'}
+    post_request(user, password, url, description, data, headers)
+
+def delete_role(user, password, roleid):
+    url = target_host + 'auth/v1/roles/{}'.format(roleid)
+    description = 'delete_role({})'.format(roleid)
+    delete_request(user, password, url, description)
+
+def add_grant(user, password, userid, roleid):
+    description = 'add_grant(userid={},roleid={})'.format(userid, roleid)
+    payload = {"roleid":roleid, "userid":userid, "grantid":'{}@{}@{}'.format(userid, roleid, "sdn"), "domainid":"sdn"}
+    url = target_host + 'auth/v1/domains/sdn/users/{}/roles'.format(userid)
+    data=json.dumps(payload)
+    headers={'Content-Type':'application/json'}
+    post_request(user, password, url, description, data, headers)
+
+def get_grants(user, password, userid):
+    get_request(user, password, target_host + 'auth/v1/domains/sdn/users/{}/roles'.format(userid), 'get_grants({})'.format(userid))
+
+def delete_grant(user, password, userid, roleid):
+    url = target_host + 'auth/v1/domains/sdn/users/{}/roles/{}'.format(userid, roleid)
+    print url
+    description = 'delete_grant(userid={},roleid={})'.format(userid, roleid)
+    delete_request(user, password, url, description)
+
+args = parser.parse_args()
+command = args.func.prog.split()[1:]
+user = args.user[0]
+password = getpass.getpass()
+temp_host_arr = args.target_host
+if temp_host_arr is not None:
+    temp_host_val = temp_host_arr[0]
+    if temp_host_val is not None:
+        target_host = temp_host_val
+        if not target_host.endswith("/"):
+            target_host += "/"
+if "list-users" in command:
+    list_users(user,password)
+if "list-domains" in command:
+    list_domains(user,password)
+if "list-roles" in command:
+    list_roles(user,password)
+if "add-user" in command:
+    add_user(user,password, args.newUser[0])
+if "add-grant" in command:
+    add_grant(user,password, args.userid[0], args.roleid[0])
+if "get-grants" in command:
+    get_grants(user,password, args.userid[0])
+if "change-password" in command:
+    change_password(user, password, args.userid[0])
+if "delete-user" in command:
+    delete_user(user, password, args.userid[0])
+if "delete-role" in command:
+    delete_role(user, password, args.roleid[0])
+if "add-role" in command:
+    add_role(user, password, args.role[0])
+if "delete-grant" in command:
+    delete_grant(user, password, args.userid[0], args.roleid[0])
+
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/initial/08-aaa-idmlight-config.xml b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/initial/08-aaa-idmlight-config.xml
new file mode 100644
index 00000000..695ce762
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/resources/initial/08-aaa-idmlight-config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:authn="config:aaa:authn:idmlight">authn:aaa-idmlight</type>
+                    <name>aaa-idmlight</name>
+                </module>
+            </modules>
+        </data>
+    </configuration>
+    <required-capabilities>
+        <capability>config:aaa:authn:idmlight?module=aaa-idmlight&amp;revision=2015-12-04</capability>
+    </required-capabilities>
+
+</snapshot>
+
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/main/yang/aaa-idmlight.yang b/odl-aaa-moon/aaa/aaa-idmlight/src/main/yang/aaa-idmlight.yang
new file mode 100644
index 00000000..4f28d755
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/main/yang/aaa-idmlight.yang
@@ -0,0 +1,28 @@
+module aaa-idmlight {
+  yang-version 1;
+  namespace "config:aaa:authn:idmlight";
+  prefix "aaa-idmlight";
+    organization "OpenDayLight";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    contact "saichler@gmail.com";
+
+    revision 2015-12-04 {
+        description
+            "Initial revision.";
+    }
+
+    identity aaa-idmlight {
+        base config:module-type;
+        config:java-name-prefix AAAIDMLight;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case aaa-idmlight {
+            when "/config:modules/config:module/config:type = 'aaa-idmlight'";
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/persistence/PasswordHashTest.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/persistence/PasswordHashTest.java
new file mode 100644
index 00000000..44fadf7a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/persistence/PasswordHashTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.persistence;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.api.SHA256Calculator;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+import org.opendaylight.aaa.idm.IdmLightProxy;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+
+/*
+ * @Author - Sharon Aicler (saichler@cisco.com)
+*/
+public class PasswordHashTest {
+
+    @Before
+    public void before() throws IDMStoreException{
+        IIDMStore store = Mockito.mock(IIDMStore.class);
+        AAAIDMLightModule.setStore(store);
+        Domain domain = new Domain();
+        domain.setName("sdn");
+        domain.setDomainid("sdn");
+
+        Mockito.when(store.readDomain("sdn")).thenReturn(domain);
+        Creds c = new Creds();
+        Users users = new Users();
+        User user = new User();
+        user.setName("admin");
+        user.setUserid(c.username());
+        user.setDomainid("sdn");
+        user.setSalt("ABCD");
+        user.setPassword(SHA256Calculator.getSHA256(c.password(),user.getSalt()));
+        List<User> lu = new LinkedList<>();
+        lu.add(user);
+        users.setUsers(lu);
+
+        Grants grants = new Grants();
+        Grant grant = new Grant();
+        List<Grant> g = new ArrayList<>();
+        g.add(grant);
+        grant.setDomainid("sdn");
+        grant.setRoleid("admin");
+        grant.setUserid("admin");
+        grants.setGrants(g);
+        Role role = new Role();
+        role.setRoleid("admin");
+        role.setName("admin");
+        Mockito.when(store.readRole("admin")).thenReturn(role);
+        Mockito.when(store.getUsers(c.username(), c.domain())).thenReturn(users);
+        Mockito.when(store.getGrants(c.domain(), c.username())).thenReturn(grants);
+    }
+
+    @Test
+    public void testPasswordHash(){
+        IdmLightProxy proxy = new IdmLightProxy();
+        proxy.authenticate(new Creds());
+    }
+
+    private static class Creds implements PasswordCredentials {
+        @Override
+        public String username() {
+            return "admin";
+        }
+        @Override
+        public String password() {
+            return "admin";
+        }
+        @Override
+        public String domain() {
+            return "sdn";
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/DomainHandlerTest.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/DomainHandlerTest.java
new file mode 100644
index 00000000..a8b964ae
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/DomainHandlerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import org.junit.Test;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.Roles;
+
+public class DomainHandlerTest extends HandlerTest{
+
+    @Test
+    public void testDomainHandler() {
+        //check default domains
+        Domains domains = resource().path("/v1/domains").get(Domains.class);
+        assertNotNull(domains);
+        assertEquals(1, domains.getDomains().size());
+        assertTrue(domains.getDomains().get(0).getName().equals("sdn"));
+
+        //check existing domain
+        Domain domain = resource().path("/v1/domains/0").get(Domain.class);
+        assertNotNull(domain);
+        assertTrue(domain.getName().equals("sdn"));
+
+        //check not exist domain
+        try {
+            resource().path("/v1/domains/5").get(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("Not found! domain id"));
+        }
+
+        // check create domain
+        Map<String, String> domainData = new HashMap<String, String>();
+        domainData.put("name","dom1");
+        domainData.put("description","test dom");
+        domainData.put("domainid","1");
+        domainData.put("enabled","true");
+        ClientResponse clientResponse = resource().path("/v1/domains").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, domainData);
+        assertEquals(201, clientResponse.getStatus());
+
+        // check update domain data
+        domainData.put("name","dom1Update");
+        clientResponse = resource().path("/v1/domains/1").type(MediaType.APPLICATION_JSON).put(ClientResponse.class, domainData);
+        assertEquals(200, clientResponse.getStatus());
+        domain = resource().path("/v1/domains/1").get(Domain.class);
+        assertNotNull(domain);
+        assertTrue(domain.getName().equals("dom1Update"));
+
+        // check create grant
+        Map<String, String> grantData = new HashMap<String, String>();
+        grantData.put("roleid","1");
+        clientResponse = resource().path("/v1/domains/1/users/0/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, grantData);
+        assertEquals(201, clientResponse.getStatus());
+
+        // check create existing grant
+        clientResponse = resource().path("/v1/domains/1/users/0/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, grantData);
+        assertEquals(403, clientResponse.getStatus());
+
+        // check create grant with invalid domain id
+        clientResponse = resource().path("/v1/domains/5/users/0/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, grantData);
+        assertEquals(404, clientResponse.getStatus());
+
+        // check validate user (admin)
+        Map<String, String> usrPwdData = new HashMap<String, String>();
+        usrPwdData.put("username","admin");
+        usrPwdData.put("userpwd","admin");
+        clientResponse = resource().path("/v1/domains/0/users/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, usrPwdData);
+        assertEquals(200, clientResponse.getStatus());
+
+        // check validate user (admin) with wrong password
+        usrPwdData.put("userpwd","1234");
+        clientResponse = resource().path("/v1/domains/0/users/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, usrPwdData);
+        assertEquals(401, clientResponse.getStatus());
+
+        // check get user (admin) roles
+        Roles usrRoles = resource().path("/v1/domains/0/users/0/roles").get(Roles.class);
+        assertNotNull(usrRoles);
+        assertTrue(usrRoles.getRoles().size() > 1);
+
+        // check get invalid user roles
+        try {
+            resource().path("/v1/domains/0/users/5/roles").get(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+        }
+
+        // check delete grant
+        clientResponse = resource().path("/v1/domains/0/users/0/roles/0").delete(ClientResponse.class);
+        assertEquals(204, clientResponse.getStatus());
+
+        // check delete grant for invalid domain
+        clientResponse = resource().path("/v1/domains/3/users/0/roles/0").delete(ClientResponse.class);
+        assertEquals(404, clientResponse.getStatus());
+
+        // check delete domain
+        clientResponse = resource().path("/v1/domains/1").delete(ClientResponse.class);
+        assertEquals(204, clientResponse.getStatus());
+
+        // check delete not existing domain
+        try {
+            resource().path("/v1/domains/1").delete(IDMError.class);
+            fail("Shoulda failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("Not found! Domain id"));
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/HandlerTest.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/HandlerTest.java
new file mode 100644
index 00000000..7b8eebb4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/HandlerTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest.test;
+
+import com.sun.jersey.spi.container.servlet.WebComponent;
+import com.sun.jersey.test.framework.AppDescriptor;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import org.junit.Before;
+import org.opendaylight.aaa.idm.IdmLightApplication;
+import org.opendaylight.aaa.idm.StoreBuilder;
+import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
+
+
+public abstract class HandlerTest extends JerseyTest {
+
+    protected IDMTestStore testStore = new IDMTestStore();
+
+    @Override
+    protected AppDescriptor configure() {
+        return new WebAppDescriptor.Builder()
+                                   .initParam(WebComponent.RESOURCE_CONFIG_CLASS, IdmLightApplication.class.getName())
+                                   .build();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        StoreBuilder.init(testStore);
+        AAAIDMLightModule.setStore(testStore);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/IDMTestStore.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/IDMTestStore.java
new file mode 100644
index 00000000..0fed2789
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/IDMTestStore.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IIDMStore;
+import org.opendaylight.aaa.api.model.Domain;
+import org.opendaylight.aaa.api.model.Domains;
+import org.opendaylight.aaa.api.model.Grant;
+import org.opendaylight.aaa.api.model.Grants;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+
+public class IDMTestStore implements IIDMStore {
+
+    private List<Domain> domains = new ArrayList<Domain>();
+    private List<Grant> grants = new ArrayList<Grant>();
+    private List<Role> roles = new ArrayList<Role>();
+    private List<User> users = new ArrayList<User>();
+
+    public IDMTestStore() {
+        // TODO Auto-generated constructor stub
+    }
+
+    @Override
+    public Domain writeDomain(Domain domain) throws IDMStoreException {
+        domain.setDomainid(String.valueOf(domains.size()));
+        domains.add(domain);
+        return domain;
+    }
+
+    @Override
+    public Domain readDomain(String domainid) throws IDMStoreException {
+        for(Domain dom : domains)  {
+            if (dom.getDomainid().equals(domainid)) {
+                return dom;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Domain deleteDomain(String domainid) throws IDMStoreException {
+        for(Domain dom : domains)  {
+            if (dom.getDomainid().equals(domainid)) {
+                domains.remove(dom);
+                return dom;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Domain updateDomain(Domain domain) throws IDMStoreException {
+        for(Domain dom : domains)  {
+            if (dom.getDomainid().equals(domain.getDomainid())) {
+                domains.remove(dom);
+                domains.add(domain);
+                return domain;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Domains getDomains() throws IDMStoreException {
+        Domains doms =  new Domains();
+        doms.setDomains(domains);
+        return doms;
+    }
+
+    @Override
+    public Role writeRole(Role role) throws IDMStoreException {
+        role.setRoleid(String.valueOf(roles.size()));
+        roles.add(role);
+        return role;
+    }
+
+    @Override
+    public Role readRole(String roleid) throws IDMStoreException {
+        for (Role role : roles) {
+            if (role.getRoleid().equals(roleid)) {
+                return role;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Role deleteRole(String roleid) throws IDMStoreException {
+        for (Role role : roles) {
+            if (role.getRoleid().equals(roleid)) {
+                roles.remove(role);
+                return role;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Role updateRole(Role role) throws IDMStoreException {
+        for (Role inRole : roles) {
+            if (inRole.getRoleid().equals(role.getRoleid())) {
+                roles.remove(inRole);
+                roles.add(role);
+                return role;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Roles getRoles() throws IDMStoreException {
+        Roles rols = new Roles();
+        rols.setRoles(roles);
+        return rols;
+    }
+
+    @Override
+    public User writeUser(User user) throws IDMStoreException {
+        user.setUserid(String.valueOf(users.size()));
+        users.add(user);
+        return user;
+    }
+
+    @Override
+    public User readUser(String userid) throws IDMStoreException {
+        for(User usr : users) {
+            if (usr.getUserid().equals(userid)) {
+                return usr;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public User deleteUser(String userid) throws IDMStoreException {
+        for(User usr : users) {
+            if (usr.getUserid().equals(userid)) {
+                users.remove(usr);
+                return usr;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public User updateUser(User user) throws IDMStoreException {
+        for(User usr : users) {
+            if (usr.getUserid().equals(user.getUserid())) {
+                users.remove(usr);
+                users.add(user);
+                return usr;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Users getUsers() throws IDMStoreException {
+        Users usrs = new Users();
+        usrs.setUsers(users);
+        return usrs;
+    }
+
+    @Override
+    public Users getUsers(String username, String domainId) throws IDMStoreException {
+        Users usrs = new Users();
+        User user = null;
+        Domain domain = null;
+        for(User usr : users) {
+            if (usr.getName().equals(username)) {
+                user = usr;
+                break;
+            }
+        }
+        for(Domain dom : domains) {
+            if (dom.getDomainid().equals(domainId)) {
+                domain = dom;
+                break;
+            }
+        }
+        if (user == null || domain == null)
+            return usrs;
+        for (Grant grant : grants) {
+            if (grant.getUserid().equals(user.getUserid()) && grant.getDomainid().equals(domain.getDomainid())) {
+                List<User> usrList = new ArrayList<User>();
+                usrList.add(user);
+                usrs.setUsers(usrList);
+                break;
+            }
+        }
+        return usrs;
+    }
+
+    @Override
+    public Grant writeGrant(Grant grant) throws IDMStoreException {
+        grant.setGrantid(String.valueOf(grants.size()));
+        grants.add(grant);
+        return grant;
+    }
+
+    @Override
+    public Grant readGrant(String grantid) throws IDMStoreException {
+        for (Grant grant : grants) {
+            if (grant.getGrantid().equals(grantid)) {
+                return grant;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Grant deleteGrant(String grantid) throws IDMStoreException {
+        for (Grant grant : grants) {
+            if (grant.getGrantid().equals(grantid)) {
+                grants.remove(grant);
+                return grant;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Grants getGrants(String domainid, String userid) throws IDMStoreException {
+        Grants usrGrants = new Grants();
+        List<Grant> usrGrant = new ArrayList<Grant>();
+        for (Grant grant : grants) {
+            if (grant.getUserid().equals(userid) && grant.getDomainid().equals(domainid)) {
+                usrGrant.add(grant);
+            }
+        }
+        usrGrants.setGrants(usrGrant);
+        return usrGrants;
+    }
+
+    @Override
+    public Grants getGrants(String userid) throws IDMStoreException {
+        Grants usrGrants = new Grants();
+        List<Grant> usrGrant = new ArrayList<Grant>();
+        for (Grant grant : grants) {
+            if (grant.getUserid().equals(userid)) {
+                usrGrant.add(grant);
+            }
+        }
+        usrGrants.setGrants(usrGrant);
+        return usrGrants;
+    }
+
+    @Override
+    public Grant readGrant(String domainid, String userid, String roleid) throws IDMStoreException {
+        for (Grant grant : grants) {
+            if (grant.getDomainid().equals(domainid) && grant.getUserid().equals(userid) && grant.getRoleid().equals(roleid)) {
+                return grant;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/RoleHandlerTest.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/RoleHandlerTest.java
new file mode 100644
index 00000000..baf59558
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/RoleHandlerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import org.junit.Test;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.Role;
+import org.opendaylight.aaa.api.model.Roles;
+
+
+public class RoleHandlerTest extends HandlerTest{
+
+    @Test
+    public void testRoleHandler() {
+        //check default roles
+        Roles roles = resource().path("/v1/roles").get(Roles.class);
+        assertNotNull(roles);
+        List<Role> roleList = roles.getRoles();
+        assertEquals(2, roleList.size());
+        for (Role role : roleList) {
+            assertTrue(role.getName().equals("admin") || role.getName().equals("user"));
+        }
+
+        //check existing role
+        Role role = resource().path("/v1/roles/0").get(Role.class);
+        assertNotNull(role);
+        assertTrue(role.getName().equals("admin"));
+
+        //check not exist Role
+        try {
+            resource().path("/v1/roles/5").get(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("role not found"));
+        }
+
+        // check create Role
+        Map<String, String> roleData = new HashMap<String, String>();
+        roleData.put("name","role1");
+        roleData.put("description","test Role");
+        roleData.put("domainid","0");
+        ClientResponse clientResponse = resource().path("/v1/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, roleData);
+        assertEquals(201, clientResponse.getStatus());
+
+        // check create Role missing name data
+        roleData.remove("name");
+        try {
+            clientResponse = resource().path("/v1/roles").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, roleData);
+            assertEquals(404, clientResponse.getStatus());
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(500, resp.getStatus());
+        }
+
+        // check update Role data
+        roleData.put("name","role1Update");
+        clientResponse = resource().path("/v1/roles/2").type(MediaType.APPLICATION_JSON).put(ClientResponse.class, roleData);
+        assertEquals(200, clientResponse.getStatus());
+        role = resource().path("/v1/roles/2").get(Role.class);
+        assertNotNull(role);
+        assertTrue(role.getName().equals("role1Update"));
+
+        // check delete Role
+        clientResponse = resource().path("/v1/roles/2").delete(ClientResponse.class);
+        assertEquals(204, clientResponse.getStatus());
+
+        // check delete not existing Role
+        try {
+            resource().path("/v1/roles/2").delete(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("role id not found"));
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/UserHandlerTest.java b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/UserHandlerTest.java
new file mode 100644
index 00000000..115546b6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/src/test/java/org/opendaylight/aaa/idm/rest/test/UserHandlerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idm.rest.test;
+
+import static org.junit.Assert.*;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import org.junit.Test;
+import org.opendaylight.aaa.api.model.IDMError;
+import org.opendaylight.aaa.api.model.User;
+import org.opendaylight.aaa.api.model.Users;
+
+public class UserHandlerTest extends HandlerTest {
+
+    @Test
+    public void testUserHandler() {
+        //check default users
+        Users users = resource().path("/v1/users").get(Users.class);
+        assertNotNull(users);
+        List<User> usrList = users.getUsers();
+        assertEquals(2, usrList.size());
+        for (User usr : usrList) {
+            assertTrue(usr.getName().equals("admin") || usr.getName().equals("user"));
+        }
+
+        //check existing user
+        User usr = resource().path("/v1/users/0").get(User.class);
+        assertNotNull(usr);
+        assertTrue(usr.getName().equals("admin"));
+
+        //check not exist user
+        try {
+            resource().path("/v1/users/5").get(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("user not found"));
+        }
+
+        // check create user
+        Map<String, String> usrData = new HashMap<String, String>();
+        usrData.put("name","usr1");
+        usrData.put("description","test user");
+        usrData.put("enabled","true");
+        usrData.put("email","user1@usr.org");
+        usrData.put("password","ChangeZbadPa$$w0rd");
+        usrData.put("domainid","0");
+        ClientResponse clientResponse = resource().path("/v1/users").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, usrData);
+        assertEquals(201, clientResponse.getStatus());
+
+        // check create user missing name data
+        usrData.remove("name");
+        try {
+            clientResponse = resource().path("/v1/users").type(MediaType.APPLICATION_JSON).post(ClientResponse.class, usrData);
+            assertEquals(400, clientResponse.getStatus());
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(500, resp.getStatus());
+        }
+
+        // check update user data
+        usrData.put("name","usr1Update");
+        clientResponse = resource().path("/v1/users/2").type(MediaType.APPLICATION_JSON).put(ClientResponse.class, usrData);
+        assertEquals(200, clientResponse.getStatus());
+        usr = resource().path("/v1/users/2").get(User.class);
+        assertNotNull(usr);
+        assertTrue(usr.getName().equals("usr1Update"));
+
+        // check delete user
+        clientResponse = resource().path("/v1/users/2").delete(ClientResponse.class);
+        assertEquals(204, clientResponse.getStatus());
+
+        // check delete not existing user
+        try {
+            resource().path("/v1/users/2").delete(IDMError.class);
+            fail("Should failed with 404!");
+        } catch (UniformInterfaceException e) {
+            ClientResponse resp = e.getResponse();
+            assertEquals(404, resp.getStatus());
+            assertTrue(resp.getEntity(IDMError.class).getMessage().contains("Couldn't find user"));
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/cleardb.sh b/odl-aaa-moon/aaa/aaa-idmlight/tests/cleardb.sh
new file mode 100755
index 00000000..6385b48d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/cleardb.sh
@@ -0,0 +1,5 @@
+sudo service idmlight stop
+echo "dropping all tables..."
+sleep 3
+sudo sqlite3 /opt/idmlight/dmlight.db < ../sql/idmlight.sql
+sudo service idmlight start
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/domain.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/domain.json
new file mode 100644
index 00000000..4dfd25e9
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/domain.json
@@ -0,0 +1,5 @@
+{
+    "domainid": "1",
+    "name":"R&D",
+    "enabled":"true"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/domain2.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/domain2.json
new file mode 100644
index 00000000..69244b30
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/domain2.json
@@ -0,0 +1,5 @@
+{
+    "domainid": "1",
+    "name":"ATG",
+    "enabled":"true"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/grant.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/grant.json
new file mode 100644
index 00000000..0c4a9e90
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/grant.json
@@ -0,0 +1,4 @@
+{
+    "roleid":"2",
+    "description":"role grant"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/grant2.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/grant2.json
new file mode 100644
index 00000000..ad685b7a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/grant2.json
@@ -0,0 +1,4 @@
+{
+    "roleid":"3",
+    "description":"role grant"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/result.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/result.json
new file mode 100644
index 00000000..a3dd995d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/result.json
@@ -0,0 +1 @@
+{"domainid":2,"userid":2,"username":"peter","roles":[{"roleid":2,"name":"user","description":"A user role with limited access"},{"roleid":3,"name":"user","description":"A user role with limited access"}]}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/role-admin.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/role-admin.json
new file mode 100644
index 00000000..cf93caae
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/role-admin.json
@@ -0,0 +1,4 @@
+{
+    "name":"admin",
+    "description":"An admin role with full access"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/role-user.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/role-user.json
new file mode 100644
index 00000000..78588c9a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/role-user.json
@@ -0,0 +1,4 @@
+{
+    "name":"user",
+    "description":"A user role with limited access"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/test.sh b/odl-aaa-moon/aaa/aaa-idmlight/tests/test.sh
new file mode 100755
index 00000000..3589be58
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/test.sh
@@ -0,0 +1,308 @@
+# GLOBAL VARS
+TARGET="localhost:8282/auth"
+TESTCOUNT=0
+PASSCOUNT=0
+FAILCOUNT=0
+
+getit() {
+((TESTCOUNT++))
+echo '['$TESTCOUNT']' $NAME
+echo GET $URL
+echo "Desired Result=" $PASSCODE
+STATUS=$(curl -X GET -k -s -H Accept:application/json -o result.json -w '%{http_code}' $URL)
+if [ $STATUS -eq $PASSCODE ]; then
+   ((PASSCOUNT++))
+   cat result.json | python -mjson.tool
+   echo "[PASS] Status=" $STATUS
+else
+   cat result.json | python -mjson.tool
+   echo "[FAIL] Status=" $STATUS
+   ((FAILCOUNT++))
+fi
+echo
+}
+
+
+deleteit() {
+((TESTCOUNT++))
+echo '['$TESTCOUNT']' $NAME
+echo DELETE $URL
+echo "Desired Result=" $PASSCODE
+STATUS=$(curl -X DELETE -k -s -H Accept:application/json -o result.json -w '%{http_code}' $URL)
+if [ $STATUS -eq $PASSCODE ]; then
+   ((PASSCOUNT++))
+   echo "[PASS] Status=" $STATUS
+else
+   cat result.json | python -mjson.tool
+   echo "[FAIL] Status=" $STATUS
+   ((FAILCOUNT++))
+fi
+echo
+}
+
+postit() {
+((TESTCOUNT++))
+echo '['$TESTCOUNT']' $NAME
+echo POST $URL
+echo "Desired Result=" $PASSCODE
+echo "POST File=" $POSTFILE
+STATUS=$(curl -X POST -k -s -H "Content-type:application/json" --data-binary "@"$POSTFILE -o result.json -w '%{http_code}' $URL)
+if [ $STATUS -eq $PASSCODE ]; then
+   ((PASSCOUNT++))
+   cat result.json | python -mjson.tool
+   echo "[PASS] Status=" $STATUS
+else
+   cat result.json | python -mjson.tool
+   echo "[FAIL] Status=" $STATUS
+   ((FAILCOUNT++))
+fi
+echo
+}
+
+putit() {
+((TESTCOUNT++))
+echo '['$TESTCOUNT']' $NAME
+echo PUT $URL
+echo "Desired Result=" $PASSCODE
+echo "PUT file=" $PUTFILE
+STATUS=$(curl -X PUT -k -s -H "Content-type:application/json" --data-binary "@"$PUTFILE -o result.json -w '%{http_code}' $URL)
+if [ $STATUS -eq $PASSCODE ]; then
+   ((PASSCOUNT++))
+   cat result.json | python -mjson.tool
+   echo "[PASS] Status=" $STATUS
+else
+   cat result.json | python -mjson.tool
+   echo "[FAIL] Status=" $STATUS
+   ((FAILCOUNT++))
+fi
+echo
+}
+
+
+#
+# DOMAIN TESTS
+#
+
+NAME="get all domains"
+URL="http://$TARGET/v1/domains"
+PASSCODE=200
+getit
+
+NAME="create a new domain"
+URL="http://$TARGET/v1/domains"
+POSTFILE=domain.json
+PASSCODE=201
+postit
+
+NAME="get domain 1"
+URL="http://$TARGET/v1/domains/1"
+PASSCODE=200
+getit
+
+NAME="delete domain 1"
+URL="http://$TARGET/v1/domains/1"
+PASSCODE=204
+deleteit
+
+NAME="create a new domain"
+URL="http://$TARGET/v1/domains"
+POSTFILE=domain.json
+PASSCODE=201
+postit
+
+NAME="get all domains"
+URL="http://$TARGET/v1/domains"
+PASSCODE=200
+getit
+
+NAME="update domain 2"
+URL="http://$TARGET/v1/domains/2"
+PUTFILE=domain.json
+PASSCODE=200
+putit
+
+NAME="create a new domain"
+URL="http://$TARGET/v1/domains"
+POSTFILE=domain2.json
+PASSCODE=201
+postit
+
+NAME="get all domains"
+URL="http://$TARGET/v1/domains"
+PASSCODE=200
+getit
+
+#
+# USER TESTS
+#
+
+NAME="get all users"
+URL="http://$TARGET/v1/users"
+PASSCODE=200
+getit
+
+NAME="create a new user"
+URL="http://$TARGET/v1/users"
+POSTFILE=user.json
+PASSCODE=201
+postit
+
+NAME="get all users"
+URL="http://$TARGET/v1/users"
+PASSCODE=200
+getit
+
+NAME="get user 1"
+URL="http://$TARGET/v1/users/1"
+PASSCODE=200
+getit
+
+NAME="delete user 1"
+URL="http://$TARGET/v1/users/1"
+PASSCODE=204
+deleteit
+
+NAME="get all users"
+URL="http://$TARGET/v1/users"
+PASSCODE=200
+getit
+
+NAME="create a new user"
+URL="http://$TARGET/v1/users"
+POSTFILE=user.json
+PASSCODE=201
+postit
+
+NAME="update a user"
+URL="http://$TARGET/v1/users/2"
+PUTFILE=user.json
+PASSCODE=200
+putit
+
+NAME="create a new user"
+URL="http://$TARGET/v1/users"
+POSTFILE=user2.json
+PASSCODE=201
+postit
+
+NAME="get all users"
+URL="http://$TARGET/v1/users"
+PASSCODE=200
+getit
+
+# ROLE TESTS
+
+NAME="get all roles"
+URL="http://$TARGET/v1/roles"
+PASSCODE=200
+getit
+
+NAME="create a new role"
+URL="http://$TARGET/v1/roles"
+POSTFILE=role-user.json
+PASSCODE=201
+postit
+
+NAME="get all roles"
+URL="http://$TARGET/v1/roles"
+PASSCODE=200
+getit
+
+NAME="get role 1"
+URL="http://$TARGET/v1/roles/1"
+PASSCODE=200
+getit
+
+NAME="delete role 1"
+URL="http://$TARGET/v1/roles/1"
+PASSCODE=204
+deleteit
+
+NAME="create a new role"
+URL="http://$TARGET/v1/roles"
+POSTFILE=role-user.json
+PASSCODE=201
+postit
+
+NAME="update role 2"
+URL="http://$TARGET/v1/roles/2"
+PUTFILE=role-user.json
+PASSCODE=200
+putit
+
+NAME="create a new role"
+URL="http://$TARGET/v1/roles"
+POSTFILE=role-admin.json
+PASSCODE=201
+postit
+
+NAME="get all roles"
+URL="http://$TARGET/v1/roles"
+PASSCODE=200
+getit
+
+# Grant tests
+
+NAME="grant a role"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+POSTFILE=grant.json
+PASSCODE=201
+postit
+
+NAME="try to create a double grant"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+POSTFILE=grant.json
+PASSCODE=403
+postit
+
+NAME="get all roles for domain and user"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+PASSCODE=200
+getit
+
+NAME="delete a grant"
+URL="http://$TARGET/v1/domains/2/users/2/roles/2"
+PASSCODE=204
+deleteit
+
+NAME="delete a grant"
+URL="http://$TARGET/v1/domains/2/users/2/roles/2"
+PASSCODE=404
+deleteit
+
+NAME="get all roles for domain and user"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+PASSCODE=200
+getit
+
+NAME="grant a role"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+POSTFILE=grant.json
+PASSCODE=201
+postit
+
+NAME="grant a role"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+POSTFILE=grant2.json
+PASSCODE=201
+postit
+
+NAME="get all roles for domain and user"
+URL="http://$TARGET/v1/domains/2/users/2/roles"
+PASSCODE=200
+getit
+
+NAME="get all roles for domain, user and pwd"
+URL="http://$TARGET/v1/domains/2/users/roles"
+POSTFILE=userpwd.json
+PASSCODE=200
+postit
+
+
+#
+# RESULTS
+#
+echo "SUMMARY"
+echo "======================================"
+echo 'TESTS:'$TESTCOUNT 'PASS:'$PASSCOUNT 'FAIL:'$FAILCOUNT
+
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/user.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/user.json
new file mode 100644
index 00000000..6f30d705
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/user.json
@@ -0,0 +1,7 @@
+{
+    "name":"peter",
+    "description":"peter test user",
+    "enabled":"true",
+    "email":"user1@gmail.com",
+    "password":"foobar"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/user2.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/user2.json
new file mode 100644
index 00000000..9864cdb2
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/user2.json
@@ -0,0 +1,7 @@
+{
+    "name":"liem",
+    "description":"liem test user",
+    "enabled":"true",
+    "email":"user1@gmail.com",
+    "password":"foobar"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idmlight/tests/userpwd.json b/odl-aaa-moon/aaa/aaa-idmlight/tests/userpwd.json
new file mode 100644
index 00000000..e5258b98
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idmlight/tests/userpwd.json
@@ -0,0 +1,4 @@
+{
+    "username":"peter",
+    "userpwd":"foobar"
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/pom.xml b/odl-aaa-moon/aaa/aaa-idp-mapping/pom.xml
new file mode 100644
index 00000000..d3d37c40
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-authn-idpmapping</artifactId>
+  <version>0.3.2-Beryllium-SR2</version>
+  <packaging>bundle</packaging>
+
+    <properties>
+        <powermock.version>1.5.2</powermock.version>
+    </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.glassfish</groupId>
+      <artifactId>javax.json</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- Test dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Activator>org.opendaylight.aaa.idpmapping.Activator</Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Activator.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Activator.java
new file mode 100644
index 00000000..7342485e
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Activator.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+
+public class Activator extends DependencyActivatorBase {
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/IdpJson.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/IdpJson.java
new file mode 100644
index 00000000..00328b60
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/IdpJson.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import javax.json.stream.JsonLocation;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParser.Event;
+
+/**
+ * Converts between JSON and the internal data structures used in the
+ * RuleProcessor.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class IdpJson {
+
+    public IdpJson() {
+    }
+
+    public Object loadJson(java.io.Reader in) {
+        JsonParser parser = Json.createParser(in);
+        Event event = null;
+
+        // Prime the pump. Get the first item from the parser.
+        event = parser.next();
+
+        // Act on first item.
+        return loadJsonItem(parser, event);
+    }
+
+    public Object loadJson(Path filename) throws IOException {
+        BufferedReader reader = Files.newBufferedReader(filename, StandardCharsets.UTF_8);
+        return loadJson(reader);
+    }
+
+    public Object loadJson(String string) {
+        StringReader reader = new StringReader(string);
+        return loadJson(reader);
+    }
+
+    /*
+     * Process current parser item indicated by event. Consumes exactly the
+     * number of parser events necessary to load the item. Caller must advance
+     * the parser via parser.next() after this method returns.
+     */
+    private Object loadJsonItem(JsonParser parser, Event event) {
+        switch (event) {
+        case START_OBJECT: {
+            return loadJsonObject(parser, event);
+        }
+        case START_ARRAY: {
+            return loadJsonArray(parser, event);
+        }
+        case VALUE_NULL: {
+            return null;
+        }
+        case VALUE_NUMBER: {
+            if (parser.isIntegralNumber()) {
+                return parser.getLong();
+            } else {
+                return parser.getBigDecimal().doubleValue();
+            }
+        }
+        case VALUE_STRING: {
+            return parser.getString();
+        }
+        case VALUE_TRUE: {
+            return Boolean.TRUE;
+        }
+        case VALUE_FALSE: {
+            return Boolean.FALSE;
+        }
+        default: {
+            JsonLocation location = parser.getLocation();
+            throw new IllegalStateException(String.format(
+                    "unknown JSON parsing event %s, location(line=%d column=%d offset=%d)", event,
+                    location.getLineNumber(), location.getColumnNumber(),
+                    location.getStreamOffset()));
+        }
+        }
+    }
+
+    private List<Object> loadJsonArray(JsonParser parser, Event event) {
+        List<Object> list = new ArrayList<Object>();
+
+        if (event != Event.START_ARRAY) {
+            JsonLocation location = parser.getLocation();
+            throw new IllegalStateException(
+                    String.format(
+                            "expected JSON parsing event to be START_ARRAY, not %s location(line=%d column=%d offset=%d)",
+                            event, location.getLineNumber(), location.getColumnNumber(),
+                            location.getStreamOffset()));
+        }
+        event = parser.next(); // consume START_ARRAY
+        while (event != Event.END_ARRAY) {
+            Object obj;
+
+            obj = loadJsonItem(parser, event);
+            list.add(obj);
+            event = parser.next(); // next array item or END_ARRAY
+        }
+        return list;
+    }
+
+    private Map<String, Object> loadJsonObject(JsonParser parser, Event event) {
+        Map<String, Object> map = new LinkedHashMap<String, Object>();
+
+        if (event != Event.START_OBJECT) {
+            JsonLocation location = parser.getLocation();
+            throw new IllegalStateException(String.format(
+                    "expected JSON parsing event to be START_OBJECT, not %s, ",
+                    "location(line=%d column=%d offset=%d)", event, location.getLineNumber(),
+                    location.getColumnNumber(), location.getStreamOffset()));
+        }
+        event = parser.next(); // consume START_OBJECT
+        while (event != Event.END_OBJECT) {
+            if (event == Event.KEY_NAME) {
+                String key;
+                Object value;
+
+                key = parser.getString();
+                event = parser.next(); // consume key
+                value = loadJsonItem(parser, event);
+                map.put(key, value);
+            } else {
+                JsonLocation location = parser.getLocation();
+                throw new IllegalStateException(
+                        String.format(
+                                "expected JSON parsing event to be KEY_NAME, not %s, location(line=%d column=%d offset=%d)",
+                                event, location.getLineNumber(), location.getColumnNumber(),
+                                location.getStreamOffset()));
+
+            }
+            event = parser.next(); // next key or END_OBJECT
+        }
+        return map;
+    }
+
+    public String dumpJson(Object obj) {
+        Map<String, Object> properties = new HashMap<String, Object>(1);
+        properties.put(JsonGenerator.PRETTY_PRINTING, true);
+        JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(properties);
+        StringWriter stringWriter = new StringWriter();
+        JsonGenerator generator = generatorFactory.createGenerator(stringWriter);
+
+        dumpJsonItem(generator, obj);
+        generator.close();
+        return stringWriter.toString();
+    }
+
+    private void dumpJsonItem(JsonGenerator generator, Object obj) {
+        // ordered by expected occurrence
+        if (obj instanceof String) {
+            generator.write((String) obj);
+        } else if (obj instanceof List) {
+            generator.writeStartArray();
+            @SuppressWarnings("unchecked")
+            List<Object> list = (List<Object>) obj;
+            dumpJsonArray(generator, list);
+        } else if (obj instanceof Map) {
+            generator.writeStartObject();
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) obj;
+            dumpJsonObject(generator, map);
+        } else if (obj instanceof Long) {
+            generator.write(((Long) obj).longValue());
+        } else if (obj instanceof Boolean) {
+            generator.write(((Boolean) obj).booleanValue());
+        } else if (obj == null) {
+            generator.writeNull();
+        } else if (obj instanceof Double) {
+            generator.write(((Double) obj).doubleValue());
+        } else {
+            throw new IllegalStateException(
+                    String.format(
+                            "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
+                            obj.getClass().getSimpleName()));
+        }
+    }
+
+    private void dumpJsonArray(JsonGenerator generator, List<Object> list) {
+        for (Object obj : list) {
+            dumpJsonItem(generator, obj);
+        }
+        generator.writeEnd();
+    }
+
+    private void dumpJsonObject(JsonGenerator generator, Map<String, Object> map) {
+
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            String key = entry.getKey();
+            Object obj = entry.getValue();
+
+            // ordered by expected occurrence
+            if (obj instanceof String) {
+                generator.write(key, (String) obj);
+            } else if (obj instanceof List) {
+                generator.writeStartArray(key);
+                @SuppressWarnings("unchecked")
+                List<Object> list = (List<Object>) obj;
+                dumpJsonArray(generator, list);
+            } else if (obj instanceof Map) {
+                generator.writeStartObject(key);
+                @SuppressWarnings("unchecked")
+                Map<String, Object> map1 = (Map<String, Object>) obj;
+                dumpJsonObject(generator, map1);
+            } else if (obj instanceof Long) {
+                generator.write(key, ((Long) obj).longValue());
+            } else if (obj instanceof Boolean) {
+                generator.write(key, ((Boolean) obj).booleanValue());
+            } else if (obj == null) {
+                generator.write(key, JsonValue.NULL);
+            } else if (obj instanceof Double) {
+                generator.write(key, ((Double) obj).doubleValue());
+            } else {
+                throw new IllegalStateException(
+                        String.format(
+                                "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
+                                obj.getClass().getSimpleName()));
+            }
+        }
+        generator.writeEnd();
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidRuleException.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidRuleException.java
new file mode 100644
index 00000000..1e42f4f2
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidRuleException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+/**
+ * Exception thrown when a mapping rule is improperly defined.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class InvalidRuleException extends RuntimeException {
+
+    private static final long serialVersionUID = 1948891573270429630L;
+
+    public InvalidRuleException() {
+    }
+
+    public InvalidRuleException(String message) {
+        super(message);
+    }
+
+    public InvalidRuleException(Throwable cause) {
+        super(cause);
+    }
+
+    public InvalidRuleException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidTypeException.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidTypeException.java
new file mode 100644
index 00000000..fb8b132f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidTypeException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+/**
+ * Exception thrown when the type of a value is incorrect for a given context.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class InvalidTypeException extends RuntimeException {
+
+    private static final long serialVersionUID = 4437011247503994368L;
+
+    public InvalidTypeException() {
+    }
+
+    public InvalidTypeException(String message) {
+        super(message);
+    }
+
+    public InvalidTypeException(Throwable cause) {
+        super(cause);
+    }
+
+    public InvalidTypeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidValueException.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidValueException.java
new file mode 100644
index 00000000..2f83c13f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/InvalidValueException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+/**
+ * Exception thrown when a value cannot be used in a given context.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class InvalidValueException extends RuntimeException {
+
+    private static final long serialVersionUID = -2351651535772692180L;
+
+    public InvalidValueException() {
+    }
+
+    public InvalidValueException(String message) {
+        super(message);
+    }
+
+    public InvalidValueException(Throwable cause) {
+        super(cause);
+    }
+
+    public InvalidValueException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/RuleProcessor.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/RuleProcessor.java
new file mode 100644
index 00000000..0f86fde6
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/RuleProcessor.java
@@ -0,0 +1,1368 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+enum ProcessResult {
+    RULE_FAIL, RULE_SUCCESS, BLOCK_CONTINUE, STATEMENT_CONTINUE
+}
+
+/**
+ * Evaluate a set of rules against an assertion from an external Identity
+ * Provider (IdP) mapping those assertion values to local values.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class RuleProcessor {
+    private static final Logger LOG = LoggerFactory.getLogger(RuleProcessor.class);
+
+    public String ruleIdFormat = "<rule [${rule_number}:\"${rule_name}\"]>";
+    public String statementIdFormat = "<rule [${rule_number}:\"${rule_name}\"] block [${block_number}:\"${block_name}\"] statement ${statement_number}>";
+
+    /*
+     * Reserved variables
+     */
+    public static final String ASSERTION = "assertion";
+    public static final String RULE_NUMBER = "rule_number";
+    public static final String RULE_NAME = "rule_name";
+    public static final String BLOCK_NUMBER = "block_number";
+    public static final String BLOCK_NAME = "block_name";
+    public static final String STATEMENT_NUMBER = "statement_number";
+    public static final String REGEXP_ARRAY_VARIABLE = "regexp_array";
+    public static final String REGEXP_MAP_VARIABLE = "regexp_map";
+
+    private static final String REGEXP_NAMED_GROUP_PAT = "\\(\\?<([a-zA-Z][a-zA-Z0-9]*)>";
+    private static final Pattern REGEXP_NAMED_GROUP_RE = Pattern.compile(REGEXP_NAMED_GROUP_PAT);
+
+    List<Map<String, Object>> rules = null;
+    boolean success = true;
+    Map<String, Map<String, Object>> mappings = null;
+
+    public RuleProcessor(java.io.Reader rulesIn, Map<String, Map<String, Object>> mappings) {
+        this.mappings = mappings;
+        IdpJson json = new IdpJson();
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> loadJson = (List<Map<String, Object>>) json.loadJson(rulesIn);
+        rules = loadJson;
+    }
+
+    public RuleProcessor(Path rulesIn, Map<String, Map<String, Object>> mappings)
+            throws IOException {
+        this.mappings = mappings;
+        IdpJson json = new IdpJson();
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> loadJson = (List<Map<String, Object>>) json.loadJson(rulesIn);
+        rules = loadJson;
+    }
+
+    public RuleProcessor(String rulesIn, Map<String, Map<String, Object>> mappings) {
+        this.mappings = mappings;
+        IdpJson json = new IdpJson();
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> loadJson = (List<Map<String, Object>>) json.loadJson(rulesIn);
+        rules = loadJson;
+    }
+
+    /*
+     * For some odd reason the Java Regular Expression API does not include a
+     * way to retrieve a map of the named groups and their values. The API only
+     * permits us to retrieve a named group if we already know the group names.
+     * So instead we parse the pattern string looking for named groups, extract
+     * the name, look up the value of the named group and build a map from that.
+     */
+
+    private Map<String, String> regexpGroupMap(String pattern, Matcher matcher) {
+        Map<String, String> groupMap = new HashMap<String, String>();
+        Matcher groupMatcher = REGEXP_NAMED_GROUP_RE.matcher(pattern);
+
+        while (groupMatcher.find()) {
+            String groupName = groupMatcher.group(1);
+
+            groupMap.put(groupName, matcher.group(groupName));
+        }
+        return groupMap;
+    }
+
+    static public String join(List<Object> list, String conjunction) {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (Object item : list) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(conjunction);
+            }
+            sb.append(item.toString());
+        }
+        return sb.toString();
+    }
+
+    private List<String> regexpGroupList(Matcher matcher) {
+        List<String> groupList = new ArrayList<String>(matcher.groupCount() + 1);
+        groupList.add(0, matcher.group(0));
+        for (int i = 1; i < matcher.groupCount() + 1; i++) {
+            groupList.add(i, matcher.group(i));
+        }
+        return groupList;
+    }
+
+    private String objToString(Object obj) {
+        StringWriter sw = new StringWriter();
+        objToStringItem(sw, obj);
+        return sw.toString();
+    }
+
+    private void objToStringItem(StringWriter sw, Object obj) {
+        // ordered by expected occurrence
+        if (obj instanceof String) {
+            sw.write('"');
+            sw.write(((String) obj).replaceAll("\"", "\\\""));
+            sw.write('"');
+        } else if (obj instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<Object> list = (List<Object>) obj;
+            boolean first = true;
+
+            sw.write('[');
+            for (Object item : list) {
+                if (first) {
+                    first = false;
+                } else {
+                    sw.write(", ");
+                }
+                objToStringItem(sw, item);
+            }
+            sw.write(']');
+        } else if (obj instanceof Map) {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) obj;
+            boolean first = true;
+
+            sw.write('{');
+            for (Map.Entry<String, Object> entry : map.entrySet()) {
+                String key = entry.getKey();
+                Object value = entry.getValue();
+
+                if (first) {
+                    first = false;
+                } else {
+                    sw.write(", ");
+                }
+
+                objToStringItem(sw, key);
+                sw.write(": ");
+                objToStringItem(sw, value);
+
+            }
+            sw.write('}');
+        } else if (obj instanceof Long) {
+            sw.write(((Long) obj).toString());
+        } else if (obj instanceof Boolean) {
+            sw.write(((Boolean) obj).toString());
+        } else if (obj == null) {
+            sw.write("null");
+        } else if (obj instanceof Double) {
+            sw.write(((Double) obj).toString());
+        } else {
+            throw new IllegalStateException(
+                    String.format(
+                            "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
+                            obj.getClass().getSimpleName()));
+        }
+    }
+
+    private Object deepCopy(Object obj) {
+        // ordered by expected occurrence
+        if (obj instanceof String) {
+            return obj; // immutable
+        } else if (obj instanceof List) {
+            List<Object> new_list = new ArrayList<Object>();
+            @SuppressWarnings("unchecked")
+            List<Object> list = (List<Object>) obj;
+            for (Object item : list) {
+                new_list.add(deepCopy(item));
+            }
+            return new_list;
+        } else if (obj instanceof Map) {
+            Map<String, Object> new_map = new LinkedHashMap<String, Object>();
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) obj;
+            for (Map.Entry<String, Object> entry : map.entrySet()) {
+                String key = entry.getKey(); // immutable
+                Object value = entry.getValue();
+                new_map.put(key, deepCopy(value));
+            }
+            return new_map;
+        } else if (obj instanceof Long) {
+            return obj; // immutable
+        } else if (obj instanceof Boolean) {
+            return obj; // immutable
+        } else if (obj == null) {
+            return null;
+        } else if (obj instanceof Double) {
+            return obj; // immutable
+        } else {
+            throw new IllegalStateException(
+                    String.format(
+                            "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
+                            obj.getClass().getSimpleName()));
+        }
+    }
+
+    public String ruleId(Map<String, Object> namespace) {
+        return substituteVariables(ruleIdFormat, namespace);
+    }
+
+    public String statementId(Map<String, Object> namespace) {
+        return substituteVariables(statementIdFormat, namespace);
+    }
+
+    public String substituteVariables(String string, Map<String, Object> namespace) {
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = Token.VARIABLE_RE.matcher(string);
+
+        while (matcher.find()) {
+            Token token = new Token(matcher.group(0), namespace);
+            token.load();
+            String replacement;
+            if (token.type == TokenType.STRING) {
+                replacement = token.getStringValue();
+            } else {
+                replacement = objToString(token.getObjectValue());
+            }
+
+            matcher.appendReplacement(sb, replacement);
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    Map<String, Object> getMapping(Map<String, Object> namespace, Map<String, Object> rule) {
+        Map<String, Object> mapping = null;
+        String mappingName = null;
+
+        try {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) rule.get("mapping");
+            mapping = map;
+        } catch (java.lang.ClassCastException e) {
+            throw new InvalidRuleException(String.format(
+                    "%s rule defines 'mapping' but it is not a Map", this.ruleId(namespace), e));
+        }
+        if (mapping != null) {
+            return mapping;
+        }
+        try {
+            mappingName = (String) rule.get("mapping_name");
+        } catch (java.lang.ClassCastException e) {
+            throw new InvalidRuleException(String.format(
+                    "%s rule defines 'mapping_name' but it is not a string",
+                    this.ruleId(namespace), e));
+        }
+        if (mappingName == null) {
+            throw new InvalidRuleException(String.format(
+                    "%s rule does not define mapping nor mapping_name unable to load mapping",
+                    this.ruleId(namespace)));
+        }
+        mapping = this.mappings.get(mappingName);
+        if (mapping == null) {
+            throw new InvalidRuleException(
+                    String.format(
+                            "%s rule specifies mapping_name '%s' but a mapping by that name does not exist, unable to load mapping",
+                            this.ruleId(namespace)));
+        }
+        LOG.debug(String.format("using named mapping '%s' from rule %s mapping=%s", mappingName,
+                this.ruleId(namespace), mapping));
+        return mapping;
+    }
+
+    private String getVerb(List<Object> statement) {
+        Token verb;
+
+        if (statement.size() < 1) {
+            throw new InvalidRuleException("statement has no verb");
+        }
+
+        try {
+            verb = new Token(statement.get(0), null);
+        } catch (Exception e) {
+            throw new InvalidRuleException(String.format(
+                    "statement first member (i.e. verb) error %s", e));
+        }
+
+        if (verb.type != TokenType.STRING) {
+            throw new InvalidRuleException(String.format(
+                    "statement first member (i.e. verb) must be a string, not %s", verb.type));
+        }
+
+        return (verb.getStringValue()).toLowerCase();
+    }
+
+    private Token getToken(String verb, List<Object> statement, int index,
+            Map<String, Object> namespace, Set<TokenStorageType> storageTypes,
+            Set<TokenType> tokenTypes) {
+        Object item;
+        Token token;
+
+        try {
+            item = statement.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidRuleException(String.format(
+                    "verb '%s' requires at least %d items but only %d are available.", verb,
+                    index + 1, statement.size(), e));
+        }
+
+        try {
+            token = new Token(item, namespace);
+        } catch (Exception e) {
+            throw new StatementErrorException(String.format("parameter %d, %s", index, e));
+        }
+
+        if (storageTypes != null) {
+            if (!storageTypes.contains(token.storageType)) {
+                throw new InvalidTypeException(
+                        String.format(
+                                "verb '%s' requires parameter #%d to have storage types %s not %s. statement=%s",
+                                verb, index, storageTypes, statement));
+            }
+        }
+
+        if (tokenTypes != null) {
+            token.load(); // Note, Token.load() sets the Token.type
+
+            if (!tokenTypes.contains(token.type)) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #%d to have types %s, not %s. statement=%s",
+                        verb, index, tokenTypes, statement));
+            }
+        }
+
+        return token;
+    }
+
+    private Token getParameter(String verb, List<Object> statement, int index,
+            Map<String, Object> namespace, Set<TokenType> tokenTypes) {
+        Object item;
+        Token token;
+
+        try {
+            item = statement.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidRuleException(String.format(
+                    "verb '%s' requires at least %d items but only %d are available.", verb,
+                    index + 1, statement.size(), e));
+        }
+
+        try {
+            token = new Token(item, namespace);
+        } catch (Exception e) {
+            throw new StatementErrorException(String.format("parameter %d, %s", index, e));
+        }
+
+        token.load();
+
+        if (tokenTypes != null) {
+            try {
+                token.get(); // Note, Token.get() sets the Token.type
+            } catch (UndefinedValueException e) {
+                // OK if not yet defined
+            }
+            if (!tokenTypes.contains(token.type)) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #%d to have types %s, not %s. statement=%s",
+                        verb, index, tokenTypes, item.getClass().getSimpleName(), statement));
+            }
+        }
+
+        return token;
+    }
+
+    private Object getRawParameter(String verb, List<Object> statement, int index,
+            Set<TokenType> tokenTypes) {
+        Object item;
+
+        try {
+            item = statement.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidRuleException(String.format(
+                    "verb '%s' requires at least %d items but only %d are available.", verb,
+                    index + 1, statement.size(), e));
+        }
+
+        if (tokenTypes != null) {
+            TokenType itemType = Token.classify(item);
+
+            if (!tokenTypes.contains(itemType)) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #%d to have types %s, not %s. statement=%s",
+                        verb, index, tokenTypes, statement));
+            }
+        }
+
+        return item;
+    }
+
+    private Token getVariable(String verb, List<Object> statement, int index,
+            Map<String, Object> namespace) {
+        Object item;
+        Token token;
+
+        try {
+            item = statement.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidRuleException(String.format(
+                    "verb '%s' requires at least %d items but only %d are available.", verb,
+                    index + 1, statement.size(), e));
+        }
+
+        try {
+            token = new Token(item, namespace);
+        } catch (Exception e) {
+            throw new StatementErrorException(String.format("parameter %d, %s", index, e));
+        }
+
+        if (token.storageType != TokenStorageType.VARIABLE) {
+            throw new InvalidTypeException(String.format(
+                    "verb '%s' requires parameter #%d to be a variable not %s. statement=%s", verb,
+                    index, token.storageType, statement));
+        }
+
+        return token;
+    }
+
+    public Map<String, Object> process(String assertionJson) {
+        ProcessResult result;
+        IdpJson json = new IdpJson();
+        @SuppressWarnings("unchecked")
+        Map<String, Object> assertion = (Map<String, Object>) json.loadJson(assertionJson);
+        LOG.info("Assertion JSON: {}", json.dumpJson(assertion));
+        this.success = true;
+
+        for (int ruleNumber = 0; ruleNumber < this.rules.size(); ruleNumber++) {
+            Map<String, Object> namespace = new HashMap<String, Object>();
+            Map<String, Object> rule = (Map<String, Object>) this.rules.get(ruleNumber);
+            namespace.put(RULE_NUMBER, Long.valueOf(ruleNumber));
+            namespace.put(RULE_NAME, "");
+            namespace.put(ASSERTION, deepCopy(assertion));
+
+            result = processRule(namespace, rule);
+
+            if (result == ProcessResult.RULE_SUCCESS) {
+                Map<String, Object> mapped = new LinkedHashMap<String, Object>();
+                Map<String, Object> mapping = getMapping(namespace, rule);
+                for (Map.Entry<String, Object> entry : ((Map<String, Object>) mapping).entrySet()) {
+                    String key = entry.getKey();
+                    Object value = entry.getValue();
+                    Object newValue = null;
+                    try {
+                        Token token = new Token(value, namespace);
+                        newValue = token.get();
+                    } catch (Exception e) {
+                        throw new InvalidRuleException(String.format(
+                                "%s unable to get value for mapping %s=%s, %s", ruleId(namespace),
+                                key, value, e), e);
+                    }
+                    mapped.put(key, newValue);
+                }
+                return mapped;
+            }
+        }
+        return null;
+    }
+
+    private ProcessResult processRule(Map<String, Object> namespace, Map<String, Object> rule) {
+        ProcessResult result = ProcessResult.BLOCK_CONTINUE;
+        @SuppressWarnings("unchecked")
+        List<List<List<Object>>> statementBlocks = (List<List<List<Object>>>) rule.get("statement_blocks");
+        if (statementBlocks == null) {
+            throw new InvalidRuleException("rule missing 'statement_blocks'");
+
+        }
+        for (int blockNumber = 0; blockNumber < statementBlocks.size(); blockNumber++) {
+            List<List<Object>> block = (List<List<Object>>) statementBlocks.get(blockNumber);
+            namespace.put(BLOCK_NUMBER, Long.valueOf(blockNumber));
+            namespace.put(BLOCK_NAME, "");
+
+            result = processBlock(namespace, block);
+            if (EnumSet.of(ProcessResult.RULE_SUCCESS, ProcessResult.RULE_FAIL).contains(result)) {
+                break;
+            } else if (result == ProcessResult.BLOCK_CONTINUE) {
+                continue;
+            } else {
+                throw new IllegalStateException(String.format("%s unexpected statement result: %s",
+                        result));
+            }
+        }
+        if (EnumSet.of(ProcessResult.RULE_SUCCESS, ProcessResult.BLOCK_CONTINUE).contains(result)) {
+            return ProcessResult.RULE_SUCCESS;
+        } else {
+            return ProcessResult.RULE_FAIL;
+        }
+    }
+
+    private ProcessResult processBlock(Map<String, Object> namespace, List<List<Object>> block) {
+        ProcessResult result = ProcessResult.STATEMENT_CONTINUE;
+
+        for (int statementNumber = 0; statementNumber < block.size(); statementNumber++) {
+            List<Object> statement = (List<Object>) block.get(statementNumber);
+            namespace.put(STATEMENT_NUMBER, Long.valueOf(statementNumber));
+
+            try {
+                result = processStatement(namespace, statement);
+            } catch (Exception e) {
+                throw new IllegalStateException(String.format("%s statement=%s %s",
+                        statementId(namespace), statement, e), e);
+            }
+            if (EnumSet.of(ProcessResult.BLOCK_CONTINUE, ProcessResult.RULE_SUCCESS,
+                    ProcessResult.RULE_FAIL).contains(result)) {
+                break;
+            } else if (result == ProcessResult.STATEMENT_CONTINUE) {
+                continue;
+            } else {
+                throw new IllegalStateException(String.format("%s unexpected statement result: %s",
+                        result));
+            }
+        }
+        if (result == ProcessResult.STATEMENT_CONTINUE) {
+            result = ProcessResult.BLOCK_CONTINUE;
+        }
+        return result;
+    }
+
+    private ProcessResult processStatement(Map<String, Object> namespace, List<Object> statement) {
+        ProcessResult result = ProcessResult.STATEMENT_CONTINUE;
+        String verb = getVerb(statement);
+
+        switch (verb) {
+        case "set":
+            result = verbSet(verb, namespace, statement);
+            break;
+        case "length":
+            result = verbLength(verb, namespace, statement);
+            break;
+        case "interpolate":
+            result = verbInterpolate(verb, namespace, statement);
+            break;
+        case "append":
+            result = verbAppend(verb, namespace, statement);
+            break;
+        case "unique":
+            result = verbUnique(verb, namespace, statement);
+            break;
+        case "split":
+            result = verbSplit(verb, namespace, statement);
+            break;
+        case "join":
+            result = verbJoin(verb, namespace, statement);
+            break;
+        case "lower":
+            result = verbLower(verb, namespace, statement);
+            break;
+        case "upper":
+            result = verbUpper(verb, namespace, statement);
+            break;
+        case "in":
+            result = verbIn(verb, namespace, statement);
+            break;
+        case "not_in":
+            result = verbNotIn(verb, namespace, statement);
+            break;
+        case "compare":
+            result = verbCompare(verb, namespace, statement);
+            break;
+        case "regexp":
+            result = verbRegexp(verb, namespace, statement);
+            break;
+        case "regexp_replace":
+            result = verbRegexpReplace(verb, namespace, statement);
+            break;
+        case "exit":
+            result = verbExit(verb, namespace, statement);
+            break;
+        case "continue":
+            result = verbContinue(verb, namespace, statement);
+            break;
+        default:
+            throw new InvalidRuleException(String.format("unknown verb '%s'", verb));
+        }
+
+        return result;
+    }
+
+    private ProcessResult verbSet(String verb, Map<String, Object> namespace, List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token parameter = getParameter(verb, statement, 2, namespace, null);
+
+        variable.set(parameter.getObjectValue());
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbLength(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token parameter = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.ARRAY, TokenType.MAP, TokenType.STRING));
+        long length;
+
+        switch (parameter.type) {
+        case ARRAY: {
+            length = parameter.getListValue().size();
+        }
+            break;
+        case MAP: {
+            length = parameter.getMapValue().size();
+        }
+            break;
+        case STRING: {
+            length = parameter.getStringValue().length();
+        }
+            break;
+        default:
+            throw new IllegalStateException(String.format("unexpected token type: %s",
+                    parameter.type));
+        }
+
+        variable.set(length);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s parameter=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    parameter.getObjectValue()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbInterpolate(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        String string = (String) getRawParameter(verb, statement, 2, EnumSet.of(TokenType.STRING));
+        String newValue = null;
+
+        try {
+            newValue = substituteVariables(string, namespace);
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, variable='%s' string='%s': %s", verb, variable, string, e));
+        }
+        variable.set(newValue);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s string='%s'",
+                    statementId(namespace), verb, this.success, variable, variable.get(), string));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbAppend(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getToken(verb, statement, 1, namespace,
+                EnumSet.of(TokenStorageType.VARIABLE), EnumSet.of(TokenType.ARRAY));
+        Token item = getParameter(verb, statement, 2, namespace, null);
+
+        try {
+            List<Object> list = variable.getListValue();
+            list.add(item.getObjectValue());
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, variable='%s' item='%s': %s", verb,
+                    variable.getObjectValue(), item.getObjectValue(), e));
+        }
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s item=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    item.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbUnique(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token array = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.ARRAY));
+
+        List<Object> newValue = new ArrayList<Object>();
+        Set<Object> seen = new HashSet<Object>();
+
+        for (Object member : array.getListValue()) {
+            if (seen.contains(member)) {
+                continue;
+            } else {
+                newValue.add(member);
+                seen.add(member);
+            }
+        }
+
+        variable.set(newValue);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s array=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    array.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbSplit(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token string = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.STRING));
+        Token pattern = getParameter(verb, statement, 3, namespace, EnumSet.of(TokenType.STRING));
+
+        Pattern regexp;
+        List<String> newValue;
+
+        try {
+            regexp = Pattern.compile(pattern.getStringValue());
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, bad regular expression pattern '%s', %s", verb,
+                    pattern.getObjectValue(), e));
+        }
+        try {
+            newValue = new ArrayList<String>(
+                    Arrays.asList(regexp.split((String) string.getStringValue())));
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, string='%s' pattern='%s', %s", verb,
+                    string.getObjectValue(), pattern.getObjectValue(), e));
+        }
+
+        variable.set(newValue);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s variable: %s=%s string='%s' pattern='%s'",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    string.getObjectValue(), pattern.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbJoin(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token array = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.ARRAY));
+        Token conjunction = getParameter(verb, statement, 3, namespace,
+                EnumSet.of(TokenType.STRING));
+        String newValue;
+
+        try {
+            newValue = join(array.getListValue(), conjunction.getStringValue());
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, array=%s conjunction='%s', %s", verb,
+                    array.getObjectValue(), conjunction.getObjectValue(), e));
+        }
+
+        variable.set(newValue);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s variable: %s=%s array='%s' conjunction='%s'",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    array.getObjectValue(), conjunction.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbLower(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token parameter = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.STRING, TokenType.ARRAY, TokenType.MAP));
+
+        try {
+            switch (parameter.type) {
+            case STRING: {
+                String oldValue = parameter.getStringValue();
+                String newValue;
+                newValue = oldValue.toLowerCase();
+                variable.set(newValue);
+            }
+                break;
+            case ARRAY: {
+                List<Object> oldValue = parameter.getListValue();
+                List<Object> newValue = new ArrayList<Object>(oldValue.size());
+                String oldItem;
+                String newItem;
+
+                for (Object item : oldValue) {
+                    try {
+                        oldItem = (String) item;
+                    } catch (ClassCastException e) {
+                        throw new InvalidValueException(String.format(
+                                "verb '%s' failed, array item (%s) is not a string, array=%s",
+                                verb, item, parameter.getObjectValue(), e));
+                    }
+                    newItem = oldItem.toLowerCase();
+                    newValue.add(newItem);
+                }
+                variable.set(newValue);
+            }
+                break;
+            case MAP: {
+                Map<String, Object> oldValue = parameter.getMapValue();
+                Map<String, Object> newValue = new LinkedHashMap<String, Object>(oldValue.size());
+
+                for (Map.Entry<String, Object> entry : oldValue.entrySet()) {
+                    String oldKey;
+                    String newKey;
+                    Object value = entry.getValue();
+
+                    oldKey = entry.getKey();
+                    newKey = oldKey.toLowerCase();
+                    newValue.put(newKey, value);
+                }
+                variable.set(newValue);
+            }
+                break;
+            default:
+                throw new IllegalStateException(String.format("unexpected token type: %s",
+                        parameter.type));
+            }
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, variable='%s' parameter='%s': %s", verb, variable,
+                    parameter.getObjectValue(), e), e);
+        }
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s parameter=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    parameter.getObjectValue()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbUpper(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token parameter = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.STRING, TokenType.ARRAY, TokenType.MAP));
+
+        try {
+            switch (parameter.type) {
+            case STRING: {
+                String oldValue = parameter.getStringValue();
+                String newValue;
+                newValue = oldValue.toUpperCase();
+                variable.set(newValue);
+            }
+                break;
+            case ARRAY: {
+                List<Object> oldValue = parameter.getListValue();
+                List<Object> newValue = new ArrayList<Object>(oldValue.size());
+                String oldItem;
+                String newItem;
+
+                for (Object item : oldValue) {
+                    try {
+                        oldItem = (String) item;
+                    } catch (ClassCastException e) {
+                        throw new InvalidValueException(String.format(
+                                "verb '%s' failed, array item (%s) is not a string, array=%s",
+                                verb, item, parameter.getObjectValue(), e));
+                    }
+                    newItem = oldItem.toUpperCase();
+                    newValue.add(newItem);
+                }
+                variable.set(newValue);
+            }
+                break;
+            case MAP: {
+                Map<String, Object> oldValue = parameter.getMapValue();
+                Map<String, Object> newValue = new LinkedHashMap<String, Object>(oldValue.size());
+
+                for (Map.Entry<String, Object> entry : oldValue.entrySet()) {
+                    String oldKey;
+                    String newKey;
+                    Object value = entry.getValue();
+
+                    oldKey = entry.getKey();
+                    newKey = oldKey.toUpperCase();
+                    newValue.put(newKey, value);
+                }
+                variable.set(newValue);
+            }
+                break;
+            default:
+                throw new IllegalStateException(String.format("unexpected token type: %s",
+                        parameter.type));
+            }
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, variable='%s' parameter='%s': %s", verb, variable,
+                    parameter.getObjectValue(), e), e);
+        }
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s variable: %s=%s parameter=%s",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    parameter.getObjectValue()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbIn(String verb, Map<String, Object> namespace, List<Object> statement) {
+        Token member = getParameter(verb, statement, 1, namespace, null);
+        Token collection = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.ARRAY, TokenType.MAP, TokenType.STRING));
+
+        switch (collection.type) {
+        case ARRAY: {
+            this.success = collection.getListValue().contains(member.getObjectValue());
+        }
+            break;
+        case MAP: {
+            if (member.type != TokenType.STRING) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #1 to be a %swhen parameter #2 is a %s",
+                        TokenType.STRING, collection.type));
+            }
+            this.success = collection.getMapValue().containsKey(member.getObjectValue());
+        }
+            break;
+        case STRING: {
+            if (member.type != TokenType.STRING) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #1 to be a %swhen parameter #2 is a %s",
+                        TokenType.STRING, collection.type));
+            }
+            this.success = (collection.getStringValue()).contains(member.getStringValue());
+        }
+            break;
+        default:
+            throw new IllegalStateException(String.format("unexpected token type: %s",
+                    collection.type));
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s member=%s collection=%s",
+                    statementId(namespace), verb, this.success, member.getObjectValue(),
+                    collection.getObjectValue()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbNotIn(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token member = getParameter(verb, statement, 1, namespace, null);
+        Token collection = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.ARRAY, TokenType.MAP, TokenType.STRING));
+
+        switch (collection.type) {
+        case ARRAY: {
+            this.success = !collection.getListValue().contains(member.getObjectValue());
+        }
+            break;
+        case MAP: {
+            if (member.type != TokenType.STRING) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #1 to be a %swhen parameter #2 is a %s",
+                        TokenType.STRING, collection.type));
+            }
+            this.success = !collection.getMapValue().containsKey(member.getObjectValue());
+        }
+            break;
+        case STRING: {
+            if (member.type != TokenType.STRING) {
+                throw new InvalidTypeException(String.format(
+                        "verb '%s' requires parameter #1 to be a %swhen parameter #2 is a %s",
+                        TokenType.STRING, collection.type));
+            }
+            this.success = !(collection.getStringValue()).contains(member.getStringValue());
+        }
+            break;
+        default:
+            throw new IllegalStateException(String.format("unexpected token type: %s",
+                    collection.type));
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s member=%s collection=%s",
+                    statementId(namespace), verb, this.success, member.getObjectValue(),
+                    collection.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbCompare(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token left = getParameter(verb, statement, 1, namespace, null);
+        Token op = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.STRING));
+        Token right = getParameter(verb, statement, 3, namespace, null);
+        String invalidOp = "operator %s not supported for type %s";
+        TokenType tokenType;
+        String opValue = op.getStringValue();
+        boolean result;
+
+        if (left.type != right.type) {
+            throw new InvalidTypeException(String.format(
+                    "verb '%s' both items must have the same type left is %s and right is %s",
+                    verb, left.type, right.type));
+        } else {
+            tokenType = left.type;
+        }
+
+        switch (opValue) {
+        case "==":
+        case "!=": {
+            switch (tokenType) {
+            case STRING: {
+                String leftValue = left.getStringValue();
+                String rightValue = right.getStringValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case INTEGER: {
+                Long leftValue = left.getLongValue();
+                Long rightValue = right.getLongValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case REAL: {
+                Double leftValue = left.getDoubleValue();
+                Double rightValue = right.getDoubleValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case ARRAY: {
+                List<Object> leftValue = left.getListValue();
+                List<Object> rightValue = right.getListValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case MAP: {
+                Map<String, Object> leftValue = left.getMapValue();
+                Map<String, Object> rightValue = right.getMapValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case BOOLEAN: {
+                Boolean leftValue = left.getBooleanValue();
+                Boolean rightValue = right.getBooleanValue();
+                result = leftValue.equals(rightValue);
+            }
+                break;
+            case NULL: {
+                result = (left.getNullValue() == right.getNullValue());
+            }
+                break;
+            default: {
+                throw new IllegalStateException(String.format("unexpected token type: %s",
+                        tokenType));
+            }
+            }
+            if (opValue.equals("!=")) { // negate the sense of the test
+                result = !result;
+            }
+        }
+            break;
+        case "<":
+        case ">=": {
+            switch (tokenType) {
+            case STRING: {
+                String leftValue = left.getStringValue();
+                String rightValue = right.getStringValue();
+                result = leftValue.compareTo(rightValue) < 0;
+            }
+                break;
+            case INTEGER: {
+                Long leftValue = left.getLongValue();
+                Long rightValue = right.getLongValue();
+                result = leftValue < rightValue;
+            }
+                break;
+            case REAL: {
+                Double leftValue = left.getDoubleValue();
+                Double rightValue = right.getDoubleValue();
+                result = leftValue < rightValue;
+            }
+                break;
+            case ARRAY:
+            case MAP:
+            case BOOLEAN:
+            case NULL: {
+                throw new InvalidRuleException(String.format(invalidOp, opValue, tokenType));
+            }
+            default: {
+                throw new IllegalStateException(String.format("unexpected token type: %s",
+                        tokenType));
+            }
+            }
+            if (opValue.equals(">=")) { // negate the sense of the test
+                result = !result;
+            }
+        }
+            break;
+        case ">":
+        case "<=": {
+            switch (tokenType) {
+            case STRING: {
+                String leftValue = left.getStringValue();
+                String rightValue = right.getStringValue();
+                result = leftValue.compareTo(rightValue) > 0;
+            }
+                break;
+            case INTEGER: {
+                Long leftValue = left.getLongValue();
+                Long rightValue = right.getLongValue();
+                result = leftValue > rightValue;
+            }
+                break;
+            case REAL: {
+                Double leftValue = left.getDoubleValue();
+                Double rightValue = right.getDoubleValue();
+                result = leftValue > rightValue;
+            }
+                break;
+            case ARRAY:
+            case MAP:
+            case BOOLEAN:
+            case NULL: {
+                throw new InvalidRuleException(String.format(invalidOp, opValue, tokenType));
+            }
+            default: {
+                throw new IllegalStateException(String.format("unexpected token type: %s",
+                        tokenType));
+            }
+            }
+            if (opValue.equals("<=")) { // negate the sense of the test
+                result = !result;
+            }
+        }
+            break;
+        default: {
+            throw new InvalidRuleException(String.format(
+                    "verb '%s' has unknown comparison operator '%s'", verb, op.getObjectValue()));
+        }
+        }
+        this.success = result;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("%s verb='%s' success=%s left=%s op='%s' right=%s",
+                    statementId(namespace), verb, this.success, left.getObjectValue(),
+                    op.getObjectValue(), right.getObjectValue()));
+        }
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbRegexp(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token string = getParameter(verb, statement, 1, namespace, EnumSet.of(TokenType.STRING));
+        Token pattern = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.STRING));
+
+        Pattern regexp;
+        Matcher matcher;
+
+        try {
+            regexp = Pattern.compile(pattern.getStringValue());
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, bad regular expression pattern '%s', %s", verb,
+                    pattern.getObjectValue(), e));
+        }
+        matcher = regexp.matcher(string.getStringValue());
+
+        if (matcher.find()) {
+            this.success = true;
+            namespace.put(REGEXP_ARRAY_VARIABLE, regexpGroupList(matcher));
+            namespace.put(REGEXP_MAP_VARIABLE, regexpGroupMap(pattern.getStringValue(), matcher));
+        } else {
+            this.success = false;
+            namespace.put(REGEXP_ARRAY_VARIABLE, new ArrayList<Object>());
+            namespace.put(REGEXP_MAP_VARIABLE, new HashMap<String, Object>());
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s string='%s' pattern='%s' %s=%s %s=%s",
+                    statementId(namespace), verb, this.success, string.getObjectValue(),
+                    pattern.getObjectValue(), REGEXP_ARRAY_VARIABLE,
+                    namespace.get(REGEXP_ARRAY_VARIABLE), REGEXP_MAP_VARIABLE,
+                    namespace.get(REGEXP_MAP_VARIABLE)));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbRegexpReplace(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        Token variable = getVariable(verb, statement, 1, namespace);
+        Token string = getParameter(verb, statement, 2, namespace, EnumSet.of(TokenType.STRING));
+        Token pattern = getParameter(verb, statement, 3, namespace, EnumSet.of(TokenType.STRING));
+        Token replacement = getParameter(verb, statement, 4, namespace,
+                EnumSet.of(TokenType.STRING));
+
+        Pattern regexp;
+        Matcher matcher;
+        String newValue;
+
+        try {
+            regexp = Pattern.compile(pattern.getStringValue());
+        } catch (Exception e) {
+            throw new InvalidValueException(String.format(
+                    "verb '%s' failed, bad regular expression pattern '%s', %s", verb,
+                    pattern.getObjectValue(), e));
+        }
+        matcher = regexp.matcher(string.getStringValue());
+
+        newValue = matcher.replaceAll(replacement.getStringValue());
+        variable.set(newValue);
+        this.success = true;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s variable: %s=%s string='%s' pattern='%s' replacement='%s'",
+                    statementId(namespace), verb, this.success, variable, variable.get(),
+                    string.getObjectValue(), pattern.getObjectValue(), replacement.getObjectValue()));
+        }
+
+        return ProcessResult.STATEMENT_CONTINUE;
+    }
+
+    private ProcessResult verbExit(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        ProcessResult statementResult = ProcessResult.STATEMENT_CONTINUE;
+
+        Token exitStatusParam = getParameter(verb, statement, 1, namespace,
+                EnumSet.of(TokenType.STRING));
+        Token criteriaParam = getParameter(verb, statement, 2, namespace,
+                EnumSet.of(TokenType.STRING));
+        String exitStatus = (exitStatusParam.getStringValue()).toLowerCase();
+        String criteria = (criteriaParam.getStringValue()).toLowerCase();
+        ProcessResult result;
+        boolean doExit;
+
+        if (exitStatus.equals("rule_succeeds")) {
+            result = ProcessResult.RULE_SUCCESS;
+        } else if (exitStatus.equals("rule_fails")) {
+            result = ProcessResult.RULE_FAIL;
+        } else {
+            throw new InvalidRuleException(String.format("verb='%s' unknown exit status '%s'",
+                    verb, exitStatus));
+        }
+
+        if (criteria.equals("if_success")) {
+            if (this.success) {
+                doExit = true;
+            } else {
+                doExit = false;
+            }
+        } else if (criteria.equals("if_not_success")) {
+            if (!this.success) {
+                doExit = true;
+            } else {
+                doExit = false;
+            }
+        } else if (criteria.equals("always")) {
+            doExit = true;
+        } else if (criteria.equals("never")) {
+            doExit = false;
+        } else {
+            throw new InvalidRuleException(String.format("verb='%s' unknown exit criteria '%s'",
+                    verb, criteria));
+        }
+
+        if (doExit) {
+            statementResult = result;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s status=%s criteria=%s exiting=%s result=%s",
+                    statementId(namespace), verb, this.success, exitStatus, criteria, doExit,
+                    statementResult));
+        }
+
+        return statementResult;
+    }
+
+    private ProcessResult verbContinue(String verb, Map<String, Object> namespace,
+            List<Object> statement) {
+        ProcessResult statementResult = ProcessResult.STATEMENT_CONTINUE;
+        Token criteriaParam = getParameter(verb, statement, 1, namespace,
+                EnumSet.of(TokenType.STRING));
+        String criteria = (criteriaParam.getStringValue()).toLowerCase();
+        boolean doContinue;
+
+        if (criteria.equals("if_success")) {
+            if (this.success) {
+                doContinue = true;
+            } else {
+                doContinue = false;
+            }
+        } else if (criteria.equals("if_not_success")) {
+            if (!this.success) {
+                doContinue = true;
+            } else {
+                doContinue = false;
+            }
+        } else if (criteria.equals("always")) {
+            doContinue = true;
+        } else if (criteria.equals("never")) {
+            doContinue = false;
+        } else {
+            throw new InvalidRuleException(String.format(
+                    "verb='%s' unknown continue criteria '%s'", verb, criteria));
+        }
+
+        if (doContinue) {
+            statementResult = ProcessResult.BLOCK_CONTINUE;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format(
+                    "%s verb='%s' success=%s criteria=%s continuing=%s result=%s",
+                    statementId(namespace), verb, this.success, criteria, doContinue,
+                    statementResult));
+        }
+
+        return statementResult;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/StatementErrorException.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/StatementErrorException.java
new file mode 100644
index 00000000..6abab3ee
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/StatementErrorException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+/**
+ * Exception thrown when a mapping rule statement fails.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class StatementErrorException extends RuntimeException {
+
+    private static final long serialVersionUID = 8312665727576018327L;
+
+    public StatementErrorException() {
+    }
+
+    public StatementErrorException(String message) {
+        super(message);
+    }
+
+    public StatementErrorException(Throwable cause) {
+        super(cause);
+    }
+
+    public StatementErrorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Token.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Token.java
new file mode 100644
index 00000000..402fb064
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/Token.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+enum TokenStorageType {
+    UNKNOWN, CONSTANT, VARIABLE
+}
+
+enum TokenType {
+    STRING, // java String
+    ARRAY, // java List
+    MAP, // java Map
+    INTEGER, // java Long
+    BOOLEAN, // java Boolean
+    NULL, // java null
+    REAL, // java Double
+    UNKNOWN, // undefined
+}
+
+/**
+ * Rule statements can contain variables or constants, this class encapsulates
+ * those values, enforces type handling and supports reading and writing of
+ * those values.
+ *
+ * Technically at the syntactic level these are not tokens. A token would have
+ * finer granularity such as identifier, operator, etc. I just couldn't think of
+ * a better name for how they're used here and thought token was a reasonable
+ * compromise as a name.
+ *
+ * @author John Dennis <jdennis@redhat.com>
+ */
+
+class Token {
+
+    /*
+     * Regexp to identify a variable beginning with $ Supports array notation,
+     * e.g. $foo[bar] Optional delimiting braces may be used to separate
+     * variable from surrounding text.
+     *
+     * Examples: $foo ${foo} $foo[bar] ${foo[bar] where foo is the variable name
+     * and bar is the array index.
+     *
+     * Identifer is any alphabetic followed by alphanumeric or underscore
+     */
+    private static final String VARIABLE_PAT = "(?<!\\\\)\\$" + // non-escaped $
+                                                                // sign
+            "\\{?" + // optional delimiting brace
+            "([a-zA-Z][a-zA-Z0-9_]*)" + // group 1: variable name
+            "(\\[" + // group 2: optional index
+            "([a-zA-Z0-9_]+)" + // group 3: array index
+            "\\])?" + // end optional index
+            "\\}?"; // optional delimiting brace
+    public static final Pattern VARIABLE_RE = Pattern.compile(VARIABLE_PAT);
+    /*
+     * Requires only a variable to be present in the string but permits leading
+     * and trailing whitespace.
+     */
+    private static final String VARIABLE_ONLY_PAT = "^\\s*" + VARIABLE_PAT + "\\s*$";
+    public static final Pattern VARIABLE_ONLY_RE = Pattern.compile(VARIABLE_ONLY_PAT);
+
+    private Object value = null;
+
+    public Map<String, Object> namespace = null;
+    public TokenStorageType storageType = TokenStorageType.UNKNOWN;
+    public TokenType type = TokenType.UNKNOWN;
+    public String name = null;
+    public String index = null;
+
+    Token(Object input, Map<String, Object> namespace) {
+        this.namespace = namespace;
+        if (input instanceof String) {
+            parseVariable((String) input);
+            if (this.storageType == TokenStorageType.CONSTANT) {
+                this.value = input;
+                this.type = classify(input);
+            }
+        } else {
+            this.storageType = TokenStorageType.CONSTANT;
+            this.value = input;
+            this.type = classify(input);
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (this.storageType == TokenStorageType.CONSTANT) {
+            return String.format("%s", this.value);
+        } else if (this.storageType == TokenStorageType.VARIABLE) {
+            if (this.index == null) {
+                return String.format("$%s", this.name);
+            } else {
+                return String.format("$%s[%s]", this.name, this.index);
+            }
+        } else {
+            return "UNKNOWN";
+        }
+    }
+
+    void parseVariable(String string) {
+        Matcher matcher = VARIABLE_ONLY_RE.matcher(string);
+        if (matcher.find()) {
+            String name = matcher.group(1);
+            String index = matcher.group(3);
+
+            this.storageType = TokenStorageType.VARIABLE;
+            this.name = name;
+            this.index = index;
+        } else {
+            this.storageType = TokenStorageType.CONSTANT;
+        }
+    }
+
+    public static TokenType classify(Object value) {
+        TokenType tokenType = TokenType.UNKNOWN;
+        // ordered by expected occurrence
+        if (value instanceof String) {
+            tokenType = TokenType.STRING;
+        } else if (value instanceof List) {
+            tokenType = TokenType.ARRAY;
+        } else if (value instanceof Map) {
+            tokenType = TokenType.MAP;
+        } else if (value instanceof Long) {
+            tokenType = TokenType.INTEGER;
+        } else if (value instanceof Boolean) {
+            tokenType = TokenType.BOOLEAN;
+        } else if (value == null) {
+            tokenType = TokenType.NULL;
+        } else if (value instanceof Double) {
+            tokenType = TokenType.REAL;
+        } else {
+            throw new InvalidRuleException(String.format(
+                    "Type must be String, Long, Double, Boolean, List, Map, or null, not %s",
+                    value.getClass().getSimpleName(), value));
+        }
+        return tokenType;
+    }
+
+    Object get() {
+        return get(null);
+    }
+
+    Object get(Object index) {
+        Object base = null;
+
+        if (this.storageType == TokenStorageType.CONSTANT) {
+            return this.value;
+        }
+
+        if (this.namespace.containsKey(this.name)) {
+            base = this.namespace.get(this.name);
+        } else {
+            throw new UndefinedValueException(String.format("variable '%s' not defined", this.name));
+        }
+
+        if (index == null) {
+            index = this.index;
+        }
+
+        if (index == null) { // scalar types
+            value = base;
+        } else {
+            if (base instanceof List) {
+                @SuppressWarnings("unchecked")
+                List<Object> list = (List<Object>) base;
+                Integer idx = null;
+
+                if (index instanceof Long) {
+                    idx = new Integer(((Long) index).intValue());
+                } else if (index instanceof String) {
+                    try {
+                        idx = new Integer((String) index);
+                    } catch (NumberFormatException e) {
+                        throw new InvalidTypeException(
+                                String.format(
+                                        "variable '%s' is an array indexed by '%s', however the index cannot be converted to an integer",
+                                        this.name, index, e));
+                    }
+                } else {
+                    throw new InvalidTypeException(
+                            String.format(
+                                    "variable '%s' is an array indexed by '%s', however the index must be an integer or string not %s",
+                                    this.name, index, index.getClass().getSimpleName()));
+                }
+
+                try {
+                    value = list.get(idx);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new UndefinedValueException(
+                            String.format(
+                                    "variable '%s' is an array of size %d indexed by '%s', however the index is out of bounds",
+                                    this.name, list.size(), idx, e));
+                }
+            } else if (base instanceof Map) {
+                @SuppressWarnings("unchecked")
+                Map<String, Object> map = (Map<String, Object>) base;
+                String idx = null;
+                if (index instanceof String) {
+                    idx = (String) index;
+                } else {
+                    throw new InvalidTypeException(
+                            String.format(
+                                    "variable '%s' is a map indexed by '%s', however the index must be a string not %s",
+                                    this.name, index, index.getClass().getSimpleName()));
+                }
+                if (!map.containsKey(idx)) {
+                    throw new UndefinedValueException(
+                            String.format(
+                                    "variable '%s' is a map indexed by '%s', however the index does not exist",
+                                    this.name, index));
+                }
+                value = map.get(idx);
+            } else {
+                throw new InvalidTypeException(
+                        String.format(
+                                "variable '%s' is indexed by '%s', variable must be an array or map, not %s",
+                                this.name, index, base.getClass().getSimpleName()));
+
+            }
+        }
+        this.type = classify(value);
+        return value;
+    }
+
+    void set(Object value) {
+        set(value, null);
+    }
+
+    void set(Object value, Object index) {
+
+        if (this.storageType == TokenStorageType.CONSTANT) {
+            throw new InvalidTypeException("cannot assign to a constant");
+        }
+
+        if (index == null) {
+            index = this.index;
+        }
+
+        if (index == null) { // scalar types
+            this.namespace.put(this.name, value);
+        } else {
+            Object base = null;
+
+            if (this.namespace.containsKey(this.name)) {
+                base = this.namespace.get(this.name);
+            } else {
+                throw new UndefinedValueException(String.format("variable '%s' not defined",
+                        this.name));
+            }
+
+            if (base instanceof List) {
+                @SuppressWarnings("unchecked")
+                List<Object> list = (List<Object>) base;
+                Integer idx = null;
+
+                if (index instanceof Long) {
+                    idx = new Integer(((Long) index).intValue());
+                } else if (index instanceof String) {
+                    try {
+                        idx = new Integer((String) index);
+                    } catch (NumberFormatException e) {
+                        throw new InvalidTypeException(
+                                String.format(
+                                        "variable '%s' is an array indexed by '%s', however the index cannot be converted to an integer",
+                                        this.name, index, e));
+                    }
+                } else {
+                    throw new InvalidTypeException(
+                            String.format(
+                                    "variable '%s' is an array indexed by '%s', however the index must be an integer or string not %s",
+                                    this.name, index, index.getClass().getSimpleName()));
+                }
+
+                try {
+                    value = list.set(idx, value);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new UndefinedValueException(
+                            String.format(
+                                    "variable '%s' is an array of size %d indexed by '%s', however the index is out of bounds",
+                                    this.name, list.size(), idx, e));
+                }
+            } else if (base instanceof Map) {
+                @SuppressWarnings("unchecked")
+                Map<String, Object> map = (Map<String, Object>) base;
+                String idx = null;
+                if (index instanceof String) {
+                    idx = (String) index;
+                } else {
+                    throw new InvalidTypeException(
+                            String.format(
+                                    "variable '%s' is a map indexed by '%s', however the index must be a string not %s",
+                                    this.name, index, index.getClass().getSimpleName()));
+                }
+                if (!map.containsKey(idx)) {
+                    throw new UndefinedValueException(
+                            String.format(
+                                    "variable '%s' is a map indexed by '%s', however the index does not exist",
+                                    this.name, index));
+                }
+                value = map.put(idx, value);
+            } else {
+                throw new InvalidTypeException(
+                        String.format(
+                                "variable '%s' is indexed by '%s', variable must be an array or map, not %s",
+                                this.name, index, base.getClass().getSimpleName()));
+
+            }
+        }
+    }
+
+    public Object load() {
+        this.value = get();
+        return this.value;
+    }
+
+    public Object load(Object index) {
+        this.value = get(index);
+        return this.value;
+    }
+
+    public String getStringValue() {
+        if (this.type == TokenType.STRING) {
+            return (String) this.value;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.STRING, this.type));
+        }
+    }
+
+    public List<Object> getListValue() {
+        if (this.type == TokenType.ARRAY) {
+            @SuppressWarnings("unchecked")
+            List<Object> list = (List<Object>) this.value;
+            return list;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.ARRAY, this.type));
+        }
+    }
+
+    public Map<String, Object> getMapValue() {
+        if (this.type == TokenType.MAP) {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) this.value;
+            return map;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.MAP, this.type));
+        }
+    }
+
+    public Long getLongValue() {
+        if (this.type == TokenType.INTEGER) {
+            return (Long) this.value;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.INTEGER, this.type));
+        }
+    }
+
+    public Boolean getBooleanValue() {
+        if (this.type == TokenType.BOOLEAN) {
+            return (Boolean) this.value;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.BOOLEAN, this.type));
+        }
+    }
+
+    public Double getDoubleValue() {
+        if (this.type == TokenType.REAL) {
+            return (Double) this.value;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.REAL, this.type));
+        }
+    }
+
+    public Object getNullValue() {
+        if (this.type == TokenType.NULL) {
+            return this.value;
+        } else {
+            throw new InvalidTypeException(String.format("expected %s value but token type is %s",
+                    TokenType.NULL, this.type));
+        }
+    }
+
+    public Object getObjectValue() {
+        return this.value;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/UndefinedValueException.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/UndefinedValueException.java
new file mode 100644
index 00000000..7200da3d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/main/java/org/opendaylight/aaa/idpmapping/UndefinedValueException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.idpmapping;
+
+/**
+ * Exception thrown when a statement references an undefined value.
+ *
+ * @author John Dennis &lt;jdennis@redhat.com&gt;
+ */
+
+public class UndefinedValueException extends RuntimeException {
+
+    private static final long serialVersionUID = -1607453931670834435L;
+
+    public UndefinedValueException() {
+    }
+
+    public UndefinedValueException(String message) {
+        super(message);
+    }
+
+    public UndefinedValueException(Throwable cause) {
+        super(cause);
+    }
+
+    public UndefinedValueException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/RuleProcessorTest.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/RuleProcessorTest.java
new file mode 100644
index 00000000..84d403f9
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/RuleProcessorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PrepareForTest(RuleProcessor.class)
+@RunWith(PowerMockRunner.class)
+public class RuleProcessorTest {
+
+    @Mock
+    private RuleProcessor ruleProcess;
+
+    @Before
+    public void setUp() {
+        ruleProcess = PowerMockito.mock(RuleProcessor.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @Test
+    public void testJoin() {
+        List<Object> list = new ArrayList<Object>();
+        list.add("str1");
+        list.add("str2");
+        list.add("str3");
+        assertEquals("str1/str2/str3", RuleProcessor.join(list, "/"));
+    }
+
+    @Test
+    public void testSubstituteVariables() {
+        Map<String, Object> namespace = new HashMap<String, Object>() {
+            {
+                put("foo1", new HashMap<String, String>() {
+                    {
+                        put("0", "1");
+                    }
+                });
+            }
+        };
+        String str = "foo1[0]";
+        String subVariable = ruleProcess.substituteVariables(str, namespace);
+        assertNotNull(subVariable);
+        assertEquals(subVariable, str);
+    }
+
+    @Test
+    public void testGetMapping() {
+        Map<String, Object> namespace = new HashMap<String, Object>() {
+            {
+                put("foo1", new HashMap<String, String>() {
+                    {
+                        put("0", "1");
+                    }
+                });
+            }
+        };
+        final Map<String, Object> item = new HashMap<String, Object>() {
+            {
+                put("str", "val");
+            }
+        };
+        Map<String, Object> rules = new HashMap<String, Object>() {
+            {
+                put("mapping", item);
+                put("mapping_name", "mapping");
+            }
+        };
+        Map<String, Object> mapping = ruleProcess.getMapping(namespace, rules);
+        assertNotNull(mapping);
+        assertTrue(mapping.containsKey("str"));
+        assertEquals("val", mapping.get("str"));
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        String json = " {\"rules\":[" + "{\"Name\":\"user\", \"Id\":1},"
+                + "{\"Name\":\"Admin\", \"Id\":2}]} ";
+        Map<String, Object> mapping = new HashMap<String, Object>() {
+            {
+                put("Name", "Admin");
+            }
+        };
+        List<Map<String, Object>> internalRules = new ArrayList<Map<String, Object>>();
+        Map<String, Object> internalRule = new HashMap<String, Object>() {
+            {
+                put("Name", "Admin");
+                put("statement_blocks", "user");
+            }
+        };
+        internalRules.add(internalRule);
+        MemberModifier.field(RuleProcessor.class, "rules").set(ruleProcess, internalRules);
+        PowerMockito.suppress(MemberMatcher.method(RuleProcessor.class, "processRule", Map.class,
+                Map.class));
+        PowerMockito.when(ruleProcess, "processRule", any(Map.class), any(Map.class)).thenReturn(
+                ProcessResult.RULE_SUCCESS);
+        PowerMockito.suppress(MemberMatcher.method(RuleProcessor.class, "getMapping", Map.class,
+                Map.class));
+        when(ruleProcess.getMapping(any(Map.class), any(Map.class))).thenReturn(mapping);
+        Whitebox.invokeMethod(ruleProcess, "process", json);
+        verify(ruleProcess, times(3)).getMapping(any(Map.class), any(Map.class));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/TokenTest.java b/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/TokenTest.java
new file mode 100644
index 00000000..d6181051
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-idp-mapping/src/test/java/org/opendaylight/aaa/idpmapping/TokenTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.idpmapping;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+
+public class TokenTest {
+
+    private final Map<String, Object> namespace = new HashMap<String, Object>() {
+        {
+            put("foo1", new HashMap<String, String>() {
+                {
+                    put("0", "1");
+                }
+            });
+        }
+    };
+    private Object input = "$foo1[0]";
+    private Token token = new Token(input, namespace);
+    private Token mapToken = new Token(namespace, namespace);
+
+    @Test
+    public void testToken() {
+        assertEquals(token.toString(), input);
+        assertTrue(token.storageType == TokenStorageType.VARIABLE);
+        assertEquals(mapToken.toString(), "{foo1={0=1}}");
+        assertTrue(mapToken.storageType == TokenStorageType.CONSTANT);
+    }
+
+    @Test
+    public void testClassify() {
+        assertEquals(Token.classify(new ArrayList<>()), TokenType.ARRAY);
+        assertEquals(Token.classify(true), TokenType.BOOLEAN);
+        assertEquals(Token.classify(new Long(365)), TokenType.INTEGER);
+        assertEquals(Token.classify(new HashMap<String, Object>()), TokenType.MAP);
+        assertEquals(Token.classify(null), TokenType.NULL);
+        assertEquals(Token.classify(365.00), TokenType.REAL);
+        assertEquals(Token.classify("foo_str"), TokenType.STRING);
+    }
+
+    @Test
+    public void testGet() {
+        assertNotNull(token.get());
+        assertTrue(token.get("0") == "1");
+        assertNotNull(mapToken.get());
+        assertTrue(mapToken.get(0) == namespace);
+    }
+
+    @Test
+    public void testGetMapValue() {
+        assertTrue(mapToken.getMapValue() == namespace);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro-act/pom.xml b/odl-aaa-moon/aaa/aaa-shiro-act/pom.xml
new file mode 100644
index 00000000..fade2aea
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro-act/pom.xml
@@ -0,0 +1,84 @@
+<!-- Copyright (c) 2015 Brocade Communications Systems, Inc. and others.
+  All rights reserved. This program and the accompanying materials are made
+  available under the terms of the Eclipse Public License v1.0 which accompanies
+  this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-shiro-act</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-shiro</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>${bundle.plugin.version}</version>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+            </instructions>
+            <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Activator>org.opendaylight.aaa.shiroact.Activator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java b/odl-aaa-moon/aaa/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java
new file mode 100644
index 00000000..0012a0bd
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiroact;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for activating the aaa-shiro-act bundle. This bundle is primarily
+ * responsible for enabling AuthN and AuthZ. If this bundle is not installed,
+ * then AuthN and AuthZ will not take effect.
+ *
+ * To ensure that the AAA is enabled for your feature, make sure to include the
+ * <code>odl-aaa-shiro</code> feature in your feature definition.
+ *
+ * Offers contextual <code>DEBUG</code> level clues concerning the activation of
+ * the <code>aaa-shiro-act</code> bundle. To enable the enhanced debugging issue
+ * the following line in the karaf shell:
+ * <code>log:set debug org.opendaylight.aaa.shiroact.Activator</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    @Override
+    public void destroy(BundleContext bc, DependencyManager dm)
+            throws Exception {
+        final String DEBUG_MESSAGE = "Destroying the aaa-shiro-act bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+    @Override
+    public void init(BundleContext bc, DependencyManager dm) throws Exception {
+        final String DEBUG_MESSAGE = "Initializing the aaa-shiro-act bundle";
+        LOG.debug(DEBUG_MESSAGE);
+        ServiceProxy.getInstance().setEnabled(true);
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java b/odl-aaa-moon/aaa/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java
new file mode 100644
index 00000000..23eef9db
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiroact;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+
+public class ActivatorTest {
+
+    @Test
+    public void testActivatorEnablesServiceProxy() throws Exception {
+        // should toggle the ServiceProxy enable status to true
+        new Activator().init(null, null);;
+        assertTrue(ServiceProxy.getInstance().getEnabled(null));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/pom.xml b/odl-aaa-moon/aaa/aaa-shiro/pom.xml
new file mode 100644
index 00000000..ea551532
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/pom.xml
@@ -0,0 +1,169 @@
+<!-- Copyright (c) 2015 Brocade Communications Systems, Inc. and others.
+  All rights reserved. This program and the accompanying materials are made
+  available under the terms of the Eclipse Public License v1.0 which accompanies
+  this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-shiro</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+     <!-- jersey client for moon authN -->
+     <dependency>
+       <groupId>com.sun.jersey</groupId>
+       <artifactId>jersey-client</artifactId>
+       <scope>provided</scope>
+     </dependency>
+     <dependency>
+       <groupId>org.json</groupId>
+       <artifactId>json</artifactId>
+       <version>20140107</version>
+    </dependency>
+    <!-- OAuth2 dependencies for moon -->
+    <dependency>
+        <groupId>org.apache.oltu.oauth2</groupId>
+        <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+        <scope>provided</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.oltu.oauth2</groupId>
+        <artifactId>org.apache.oltu.oauth2.common</artifactId>
+        <scope>provided</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.oltu.oauth2</groupId>
+        <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+        <scope>provided</scope>
+    </dependency>
+    <!-- end -->
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-authn-sts</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-authn-basic</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.shiro</groupId>
+      <artifactId>shiro-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.shiro</groupId>
+      <artifactId>shiro-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <version>1.1.6</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>1.1.6</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>${bundle.plugin.version}</version>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+            </instructions>
+            <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              *
+            </Import-Package>
+            <Web-ContextPath>/moon</Web-ContextPath>
+            <Bundle-Activator>org.opendaylight.aaa.shiro.Activator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <phase>package</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/shiro.ini</file>
+                  <type>cfg</type>
+                  <classifier>configuration</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/Activator.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/Activator.java
new file mode 100644
index 00000000..2f1c98f7
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/Activator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This scaffolding allows the use of AAA Filters without AuthN or AuthZ
+ * enabled. This is done to support workflows such as those included in the
+ * <code>odl-restconf-noauth</code> feature.
+ *
+ * This class is also responsible for offering contextual <code>DEBUG</code>
+ * level clues concerning the activation of the <code>aaa-shiro</code> bundle.
+ * To enable these debug messages, issue the following command in the karaf
+ * shell: <code>log:set debug org.opendaylight.aaa.shiro.Activator</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    @Override
+    public void destroy(BundleContext bc, DependencyManager dm) throws Exception {
+        final String DEBUG_MESSAGE = "Destroying the aaa-shiro bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+    @Override
+    public void init(BundleContext bc, DependencyManager dm) throws Exception {
+        final String DEBUG_MESSAGE = "Initializing the aaa-shiro bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java
new file mode 100644
index 00000000..e4485d73
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro;
+
+import org.opendaylight.aaa.shiro.filters.AAAFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for enabling and disabling the AAA service. By default, the
+ * service is disabled; the AAAFilter will not require AuthN or AuthZ. The
+ * service is enabled through calling
+ * <code>ServiceProxy.getInstance().setEnabled(true)</code>. AuthN and AuthZ are
+ * disabled by default in order to support workflows such as the feature
+ * <code>odl-restconf-noauth</code>.
+ *
+ * The AAA service is enabled through installing the <code>odl-aaa-shiro</code>
+ * feature. The <code>org.opendaylight.aaa.shiroact.Activator()</code>
+ * constructor calls enables AAA through the ServiceProxy, which in turn enables
+ * the AAAFilter.
+ *
+ * ServiceProxy is a singleton; access to the ServiceProxy is granted through
+ * the <code>getInstance()</code> function.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <a
+ *      href="https://github.com/opendaylight/netconf/blob/master/opendaylight/restconf/sal-rest-connector/src/main/resources/WEB-INF/web.xml">resconf
+ *      web,xml</a>
+ * @see <code>org.opendaylight.aaa.shiro.Activator</code>
+ * @see <code>org.opendaylight.aaa.shiro.filters.AAAFilter</code>
+ */
+public class ServiceProxy {
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceProxy.class);
+
+    /**
+     * AuthN and AuthZ are disabled by default to support workflows included in
+     * features such as <code>odl-restconf-noauth</code>
+     */
+    public static final boolean DEFAULT_AA_ENABLE_STATUS = false;
+
+    private static ServiceProxy instance = new ServiceProxy();
+    private volatile boolean enabled = false;
+    private AAAFilter filter;
+
+    /**
+     * private for singleton pattern
+     */
+    private ServiceProxy() {
+        final String INFO_MESSAGE = "Creating the ServiceProxy";
+        LOG.info(INFO_MESSAGE);
+    }
+
+    /**
+     * @return ServiceProxy, a feature level singleton
+     */
+    public static ServiceProxy getInstance() {
+        return instance;
+    }
+
+    /**
+     * Enables/disables the feature, cascading the state information to the
+     * AAAFilter.
+     *
+     * @param enabled A flag indicating whether to enable the Service.
+     */
+    public synchronized void setEnabled(final boolean enabled) {
+        this.enabled = enabled;
+        final String SERVICE_ENABLED_INFO_MESSAGE = "Setting ServiceProxy enabled to " + enabled;
+        LOG.info(SERVICE_ENABLED_INFO_MESSAGE);
+        // check for null because of non-determinism in bundle load
+        if (filter != null) {
+            filter.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * Extract whether the service is enabled.
+     *
+     * @param filter
+     *            register an optional Filter for callback if enable state
+     *            changes
+     * @return Whether the service is enabled
+     */
+    public synchronized boolean getEnabled(final AAAFilter filter) {
+        this.filter = filter;
+        return enabled;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/accounting/Accounter.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/accounting/Accounter.java
new file mode 100644
index 00000000..e768ea59
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/accounting/Accounter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.accounting;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Accounter is a common place to output AAA messages. Use this class through
+ * invoking <code>Logger.output("message")</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class Accounter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Accounter.class);
+
+    /*
+     * Essentially makes Accounter a singleton, avoiding the verbosity of
+     * <code>Accounter.getInstance().output("message")</code>.
+     */
+    private Accounter() {
+    }
+
+    /**
+     * Account for a particular <code>message</code>
+     *
+     * @param message A message for the aggregated AAA log.
+     */
+    public static void output(final String message) {
+        LOG.debug(message);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRules.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRules.java
new file mode 100644
index 00000000..9e84c988
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRules.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.authorization;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A singleton container of default authorization rules that are installed as
+ * part of Shiro initialization. This class defines an immutable set of rules
+ * that are needed to provide system-wide security. These include protecting
+ * certain MD-SAL leaf nodes that contain AAA data from random access. This is
+ * not a place to define your custom rule set; additional RBAC rules are
+ * configured through the shiro initialization file:
+ * <code>$KARAF_HOME/shiro.ini</code>
+ *
+ * An important distinction to consider is that Shiro URL rules work to protect
+ * the system at the Web layer, and <code>AuthzDomDataBroker</code> works to
+ * protect the system down further at the DOM layer.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class DefaultRBACRules {
+
+    private static DefaultRBACRules instance;
+
+    /**
+     * a collection of the default security rules
+     */
+    private Collection<RBACRule> rbacRules = new HashSet<RBACRule>();
+
+    /**
+     * protects the AAA MD-SAL store by preventing access to the leaf nodes to
+     * non-admin users.
+     */
+    private static final RBACRule PROTECT_AAA_MDSAL = RBACRule.createAuthorizationRule(
+            "*/authorization/*", Sets.newHashSet("admin"));
+
+    /*
+     * private for singleton pattern
+     */
+    private DefaultRBACRules() {
+        // rbacRules.add(PROTECT_AAA_MDSAL);
+    }
+
+    /**
+     *
+     * @return the container instance for the default RBAC Rules
+     */
+    public static final DefaultRBACRules getInstance() {
+        if (null == instance) {
+            instance = new DefaultRBACRules();
+        }
+        return instance;
+    }
+
+    /**
+     *
+     * @return a copy of the default rules, so any modifications to the returned
+     *         reference do not affect the <code>DefaultRBACRules</code>.
+     */
+    public final Collection<RBACRule> getRBACRules() {
+        // Returns a copy of the rbacRules set such that the original set keeps
+        // its contract of remaining immutable. Calls to rbacRules.add() are
+        // encapsulated solely in <code>DefaultRBACRules</code>.
+        //
+        // Since this method is only called at shiro initialiation time,
+        // memory consumption of creating a new set is a non-issue.
+        return Sets.newHashSet(rbacRules);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/RBACRule.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/RBACRule.java
new file mode 100644
index 00000000..0da95eb4
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/authorization/RBACRule.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.authorization;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A container for RBAC Rules. An RBAC Rule is composed of a url pattern which
+ * may contain asterisk characters (*), and a collection of roles. These are
+ * represented in shiro.ini in the following format:
+ * <code>urlPattern=roles[atLeastOneCommaSeperatedRole]</code>
+ *
+ * RBACRules are immutable; that is, you cannot change the url pattern or the
+ * roles after creation. This is done for security purposes. RBACRules are
+ * created through utilizing a static factory method:
+ * <code>RBACRule.createRBACRule()</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class RBACRule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RBACRule.class);
+
+    /**
+     * a url pattern that can optional contain asterisk characters (*)
+     */
+    private String urlPattern;
+
+    /**
+     * a collection of role names, such as "admin" and "user"
+     */
+    private Collection<String> roles = new HashSet<String>();
+
+    /**
+     * Creates an RBAC Rule. Made private for static factory method.
+     *
+     * @param urlPattern
+     *            Cannot be null or the empty string.
+     * @param roles
+     *            Must contain at least one role.
+     * @throws NullPointerException
+     *             if <code>urlPattern</code> or <code>roles</code> is null
+     * @throws IllegalArgumentException
+     *             if <code>urlPattern</code> is an empty string or
+     *             <code>roles</code> is an empty collection.
+     */
+    private RBACRule(final String urlPattern, final Collection<String> roles)
+            throws NullPointerException, IllegalArgumentException {
+
+        this.setUrlPattern(urlPattern);
+        this.setRoles(roles);
+    }
+
+    /**
+     * The static factory method used to create RBACRules.
+     *
+     * @param urlPattern
+     *            Cannot be null or the empty string.
+     * @param roles
+     *            Cannot be null or an emtpy collection.
+     * @return An immutable RBACRule
+     */
+    public static RBACRule createAuthorizationRule(final String urlPattern,
+            final Collection<String> roles) {
+
+        RBACRule authorizationRule = null;
+        try {
+            authorizationRule = new RBACRule(urlPattern, roles);
+        } catch (Exception e) {
+            LOG.error("Cannot instantiate the AuthorizationRule", e);
+        }
+        return authorizationRule;
+    }
+
+    /**
+     *
+     * @return the urlPattern for the RBACRule
+     */
+    public String getUrlPattern() {
+        return urlPattern;
+    }
+
+    /*
+     * helper to ensure the url pattern is not the empty string
+     */
+    private static void checkUrlPatternLength(final String urlPattern)
+            throws IllegalArgumentException {
+
+        final String EXCEPTION_MESSAGE = "Empty String is not allowed for urlPattern";
+        if (urlPattern.isEmpty()) {
+            throw new IllegalArgumentException(EXCEPTION_MESSAGE);
+        }
+    }
+
+    private void setUrlPattern(final String urlPattern) throws NullPointerException,
+            IllegalArgumentException {
+
+        Preconditions.checkNotNull(urlPattern);
+        checkUrlPatternLength(urlPattern);
+        this.urlPattern = urlPattern;
+    }
+
+    /**
+     *
+     * @return a copy of the rule, so any modifications to the returned
+     *         reference do not affect the immutable <code>RBACRule</code>.
+     */
+    public Collection<String> getRoles() {
+        // Returns a copy of the roles collection such that the original set
+        // keeps
+        // its contract of remaining immutable.
+        //
+        // Since this method is only called at shiro initialiation time,
+        // memory consumption of creating a new set is a non-issue.
+        return Sets.newHashSet(roles);
+    }
+
+    /*
+     * check to ensure the roles collection is not empty
+     */
+    private static void checkRolesCollectionSize(final Collection<String> roles)
+            throws IllegalArgumentException {
+
+        final String EXCEPTION_MESSAGE = "roles must contain at least 1 role";
+        if (roles.isEmpty()) {
+            throw new IllegalArgumentException(EXCEPTION_MESSAGE);
+        }
+    }
+
+    private void setRoles(final Collection<String> roles) throws NullPointerException,
+            IllegalArgumentException {
+
+        Preconditions.checkNotNull(roles);
+        checkRolesCollectionSize(roles);
+        this.roles = roles;
+    }
+
+    /**
+     * Generates a string representation of the <code>RBACRule</code> roles in
+     * shiro form.
+     *
+     * @return roles string representation in the form
+     *         <code>roles[roleOne,roleTwo]</code>
+     */
+    public String getRolesInShiroFormat() {
+        final String ROLES_STRING = "roles";
+        return ROLES_STRING + Arrays.toString(roles.toArray());
+    }
+
+    /**
+     * Generates the string representation of the <code>RBACRule</code> in shiro
+     * form. For example: <code>urlPattern=roles[admin,user]</code>
+     */
+    @Override
+    public String toString() {
+        return String.format("%s=%s", urlPattern, getRolesInShiroFormat());
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
new file mode 100644
index 00000000..47dd9549
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import org.apache.shiro.web.servlet.ShiroFilter;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The RESTCONF AAA JAX-RS 1.X Web Filter. This class is also responsible for
+ * delivering debug information; to enable these debug statements, please issue
+ * the following in the karaf shell:
+ *
+ * <code>log:set debug org.opendaylight.aaa.shiro.filters.AAAFilter</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>javax.servlet.Filter</code>
+ * @see <code>org.apache.shiro.web.servlet.ShiroFilter</code>
+ */
+public class AAAFilter extends ShiroFilter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AAAFilter.class);
+
+    public AAAFilter() {
+        super();
+        final String DEBUG_MESSAGE = "Creating the AAAFilter";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * Adds context clues that aid in debugging. Also initializes the enable
+     * status to correspond with
+     * <code>ServiceProxy.getInstance.getEnabled()</code>.
+     *
+     * @see org.apache.shiro.web.servlet.ShiroFilter#init()
+     */
+    @Override
+    public void init() throws Exception {
+        super.init();
+        final String DEBUG_MESSAGE = "Initializing the AAAFilter";
+        LOG.debug(DEBUG_MESSAGE);
+        // sets the filter to the startup value. Because of non-determinism in
+        // bundle loading, this passes an instance of itself along so that if
+        // the
+        // enable status changes, then AAAFilter enable status is changed.
+        setEnabled(ServiceProxy.getInstance().getEnabled(this));
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * Adds context clues to aid in debugging whether the filter is enabled.
+     *
+     * @see
+     * org.apache.shiro.web.servlet.OncePerRequestFilter#setEnabled(boolean)
+     */
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        final String DEBUG_MESSAGE = "Setting AAAFilter enabled to " + enabled;
+        LOG.debug(DEBUG_MESSAGE);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java
new file mode 100644
index 00000000..530acfac
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAShiroFilter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import org.apache.shiro.web.servlet.ShiroFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default AAA JAX-RS 1.X Web Filter.  Unlike AAAFilter, which is aimed towards
+ * supporting RESTCONF and its existing API mechanisms, AAAShiroFilter is a generic
+ * <code>ShiroFilter</code> for use with any other ODL Servlets.  The main difference
+ * is that <code>AAAFilter</code> was designed to support the existing noauth
+ * mechanism, while this filter cannot be disabled.
+ *
+ * This class is also responsible for delivering debug information; to enable these
+ * debug statements, please issue the following in the karaf shell:
+ *
+ * <code>log:set debug org.opendaylight.aaa.shiro.filters.AAAShiroFilter</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>javax.servlet.Filter</code>
+ * @see <code>org.apache.shiro.web.servlet.ShiroFilter</code>
+ */
+public class AAAShiroFilter extends ShiroFilter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AAAShiroFilter.class);
+
+    public AAAShiroFilter() {
+        LOG.debug("Creating the AAAShiroFilter");
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * Adds context clues that aid in debugging.
+     *
+     * @see org.apache.shiro.web.servlet.ShiroFilter#init()
+     */
+    @Override
+    public void init() throws Exception {
+        super.init();
+        LOG.debug("Initializing the AAAShiroFilter");
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java
new file mode 100644
index 00000000..080ab114
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationListener.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Follows the event-listener pattern;  the <code>Authenticator</code> notifies this class about
+ * authentication attempts.  <code>AuthenticationListener</code> logs successful and unsuccessful
+ * authentication attempts appropriately.  Log messages are emitted at the <code>DEBUG</code> log
+ * level.  To enable the messages out of the box, use the following command from karaf:
+ * <code>log:set DEBUG org.opendaylight.aaa.shiro.authc.AuthenicationListener</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationListener implements org.apache.shiro.authc.AuthenticationListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthenticationListener.class);
+
+    @Override
+    public void onSuccess(final AuthenticationToken authenticationToken, final AuthenticationInfo authenticationInfo) {
+        if (LOG.isDebugEnabled()) {
+            final String successMessage = AuthenticationTokenUtils.generateSuccessfulAuthenticationMessage(authenticationToken);
+            LOG.debug(successMessage);
+        }
+    }
+
+    @Override
+    public void onFailure(final AuthenticationToken authenticationToken, final AuthenticationException e) {
+        if (LOG.isDebugEnabled()) {
+            final String failureMessage = AuthenticationTokenUtils.generateUnsuccessfulAuthenticationMessage(authenticationToken);
+            LOG.debug(failureMessage);
+        }
+    }
+
+    @Override
+    public void onLogout(final PrincipalCollection principalCollection) {
+        // Do nothing;  AAA is aimed at RESTCONF, which stateless by definition.
+        // Including this output would very quickly pollute the log.
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java
new file mode 100644
index 00000000..a5f0c10d
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtils.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import com.google.common.base.Preconditions;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+
+/**
+ * Utility methods for forming audit trail output based on an <code>AuthenticationToken</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationTokenUtils {
+
+    /**
+     * default value used in messaging when the "user" field is unparsable from the HTTP REST request
+     */
+    static final String DEFAULT_USERNAME = "an unknown user";
+
+    /**
+     * default value used in messaging when the "user" field is not present in the HTTP REST request, implying
+     * a different implementation of <code>AuthenticationToken</code> such as <code>CasToken</code>.
+     */
+    static final String DEFAULT_TOKEN = "an un-parsable token type";
+
+    /**
+     * default value used in messaging when the "host" field cannot be determined.
+     */
+    static final String DEFAULT_HOSTNAME = "an unknown host";
+
+    private AuthenticationTokenUtils() {
+        // private to prevent instantiation
+    }
+
+    /**
+     * Determines whether the supplied <code>Token</code> is a <code>UsernamePasswordToken</code>.
+     *
+     * @param token A generic <code>Token</code>, which might be a <code>UsernamePasswordToken</code>
+     * @return Whether the supplied <code>Token</code> is a <code>UsernamePasswordToken</code>
+     */
+    public static boolean isUsernamePasswordToken(final AuthenticationToken token) {
+        return token instanceof UsernamePasswordToken;
+    }
+
+    /**
+     * Extracts the username if possible.  If the supplied token is a <code>UsernamePasswordToken</code>
+     * and the username field is not set, <code>DEFAULT_USERNAME</code> is returned.  If the supplied
+     * token is not a <code>UsernamePasswordToken</code> (i.e., a <code>CasToken</code> or other
+     * implementation of <code>AuthenticationToken</code>), then <code>DEFAULT_TOKEN</code> is
+     * returned.
+     *
+     * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+     * @return the username, <code>DEFAULT_USERNAME</code> or <code>DEFAULT_TOKEN</code> depending on input
+     */
+    public static String extractUsername(final AuthenticationToken token) {
+        if (isUsernamePasswordToken(token)) {
+            final UsernamePasswordToken upt = (UsernamePasswordToken) token;
+            return extractField(upt.getUsername(), DEFAULT_USERNAME);
+        }
+        return DEFAULT_TOKEN;
+    }
+
+    /**
+     * Extracts the hostname if possible.  If the supplied token is a <code>UsernamePasswordToken</code>
+     * and the hostname field is not set, <code>DEFAULT_HOSTNAME</code> is returned.  If the supplied
+     * token is not a <code>UsernamePasswordToken</code> (i.e., a <code>CasToken</code> or other
+     * implementation of <code>AuthenticationToken</code>), then <code>DEFAULT_HOSTNAME</code> is
+     * returned.
+     *
+     * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+     * @return the hostname, or <code>DEFAULT_USERNAME</code> depending on input
+     */
+    public static String extractHostname(final AuthenticationToken token) {
+        if (isUsernamePasswordToken(token)) {
+            final UsernamePasswordToken upt = (UsernamePasswordToken) token;
+            return extractField(upt.getHost(), DEFAULT_HOSTNAME);
+        }
+        return DEFAULT_HOSTNAME;
+    }
+
+    /**
+     * Utility method to generate a generic message indicating Authentication was unsuccessful.
+     *
+     * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+     * @return A message indicating authentication was unsuccessful
+     */
+    public static String generateUnsuccessfulAuthenticationMessage(final AuthenticationToken token) {
+        final String username = extractUsername(token);
+        final String remoteHostname = extractHostname(token);
+        return String.format("Unsuccessful authentication attempt by %s from %s", username, remoteHostname);
+    }
+
+    /**
+     * Utility method to generate a generic message indicating Authentication was successful.
+     *
+     * @param token An <code>AuthenticationToken</code>, possibly a <code>UsernamePasswordToken</code>
+     * @return A message indicating authentication was successful
+     */
+    public static String generateSuccessfulAuthenticationMessage(final AuthenticationToken token) {
+        final String username = extractUsername(token);
+        final String remoteHostname = extractHostname(token);
+        return String.format("Successful authentication attempt by %s from %s", username, remoteHostname);
+    }
+
+    /**
+     * Utility method that returns <code>field</code>, or <code>defaultValue</code> if <code>field</code> is null.
+     *
+     * @param field A generic string, which is possibly null.
+     * @param defaultValue A non-null value returned if <code>field</code> is null
+     * @return <code>field</code> or <code>defaultValue</code> if field is null
+     * @throws IllegalArgumentException If <code>defaultValue</code> is null
+     */
+    private static String extractField(final String field, final String defaultValue)
+        throws IllegalArgumentException {
+
+        Preconditions.checkNotNull(defaultValue, "defaultValue can't be null");
+        if (field != null) {
+            return field;
+        }
+        return defaultValue;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
new file mode 100644
index 00000000..241b7c28
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/MoonOAuthFilter.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.shiro.moon.MoonPrincipal;
+import org.opendaylight.aaa.sts.OAuthRequest;
+import org.opendaylight.aaa.sts.ServiceLocator;
+
+/**
+ * MoonOAuthFilter filters oauth1 requests form token based authentication
+ * @author Alioune BA alioune.ba@orange.com
+ *
+ */
+public class MoonOAuthFilter extends AuthenticatingFilter{
+
+    private static final String DOMAIN_SCOPE_REQUIRED = "Domain scope required";
+    private static final String NOT_IMPLEMENTED = "not_implemented";
+    private static final String UNAUTHORIZED = "unauthorized";
+    private static final String UNAUTHORIZED_CREDENTIALS = "Unauthorized: Login/Password incorrect";
+
+    static final String TOKEN_GRANT_ENDPOINT = "/token";
+    static final String TOKEN_REVOKE_ENDPOINT = "/revoke";
+    static final String TOKEN_VALIDATE_ENDPOINT = "/validate";
+
+    @Override
+    protected UsernamePasswordToken createToken(ServletRequest request, ServletResponse response) throws Exception {
+        // TODO Auto-generated method stub
+        HttpServletRequest httpRequest = (HttpServletRequest) request;
+        OAuthRequest oauthRequest = new OAuthRequest(httpRequest);
+        return new UsernamePasswordToken(oauthRequest.getUsername(),oauthRequest.getPassword());
+    }
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        // TODO Auto-generated method stub
+        Subject currentUser = SecurityUtils.getSubject();
+        return executeLogin(request, response);
+    }
+
+    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
+            ServletRequest request, ServletResponse response) throws Exception {
+        HttpServletResponse httpResponse= (HttpServletResponse) response;
+        MoonPrincipal principal = (MoonPrincipal) subject.getPrincipals().getPrimaryPrincipal();
+        Claim claim = principal.principalToClaim();
+        oauthAccessTokenResponse(httpResponse,claim,"",principal.getToken());
+        return true;
+    }
+
+    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e,
+            ServletRequest request, ServletResponse response) {
+        HttpServletResponse resp = (HttpServletResponse) response;
+        error(resp, SC_BAD_REQUEST, UNAUTHORIZED_CREDENTIALS);
+        return false;
+    }
+
+    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
+
+        HttpServletRequest req= (HttpServletRequest) request;
+        HttpServletResponse resp = (HttpServletResponse) response;
+        try {
+            if (req.getServletPath().equals(TOKEN_GRANT_ENDPOINT)) {
+                UsernamePasswordToken token = createToken(request, response);
+                if (token == null) {
+                    String msg = "A valid non-null AuthenticationToken " +
+                            "must be created in order to execute a login attempt.";
+                    throw new IllegalStateException(msg);
+                }
+                try {
+                    Subject subject = getSubject(request, response);
+                    subject.login(token);
+                    return onLoginSuccess(token, subject, request, response);
+                } catch (AuthenticationException e) {
+                    return onLoginFailure(token, e, request, response);
+                }
+            } else if (req.getServletPath().equals(TOKEN_REVOKE_ENDPOINT)) {
+                //TODO: deleteAccessToken(req, resp);
+            } else if (req.getServletPath().equals(TOKEN_VALIDATE_ENDPOINT)) {
+                //TODO: validateToken(req, resp);
+            }
+        } catch (AuthenticationException e) {
+            error(resp, SC_UNAUTHORIZED, e.getMessage());
+        } catch (OAuthProblemException oe) {
+            error(resp, oe);
+        } catch (Exception e) {
+            error(resp, e);
+        }
+        return false;
+    }
+
+    private void oauthAccessTokenResponse(HttpServletResponse resp, Claim claim, String clientId, String token)
+            throws OAuthSystemException, IOException {
+        if (claim == null) {
+            throw new AuthenticationException(UNAUTHORIZED);
+        }
+
+        // Cache this token...
+        Authentication auth = new AuthenticationBuilder(new ClaimBuilder(claim).setClientId(
+                clientId).build()).setExpiration(tokenExpiration()).build();
+        ServiceLocator.getInstance().getTokenStore().put(token, auth);
+
+        OAuthResponse r = OAuthASResponse.tokenResponse(SC_CREATED).setAccessToken(token)
+                                         .setTokenType(TokenType.BEARER.toString())
+                                         .setExpiresIn(Long.toString(auth.expiration()))
+                                         .buildJSONMessage();
+        write(resp, r);
+    }
+
+    private void write(HttpServletResponse resp, OAuthResponse r) throws IOException {
+        resp.setStatus(r.getResponseStatus());
+        PrintWriter pw = resp.getWriter();
+        pw.print(r.getBody());
+        pw.flush();
+        pw.close();
+    }
+
+    private long tokenExpiration() {
+        return ServiceLocator.getInstance().getTokenStore().tokenExpiration();
+    }
+
+    // Emit an error OAuthResponse with the given HTTP code
+    private void error(HttpServletResponse resp, int httpCode, String error) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(httpCode).setError(error)
+                                           .buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    private void error(HttpServletResponse resp, OAuthProblemException e) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(SC_BAD_REQUEST).error(e)
+                                           .buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+    private void error(HttpServletResponse resp, Exception e) {
+        try {
+            OAuthResponse r = OAuthResponse.errorResponse(SC_INTERNAL_SERVER_ERROR)
+                                           .setError(e.getClass().getName())
+                                           .setErrorDescription(e.getMessage()).buildJSONMessage();
+            write(resp, r);
+        } catch (Exception e1) {
+            // Nothing to do here
+        }
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java
new file mode 100644
index 00000000..90b0101e
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/ODLHttpAuthenticationFilter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extends <code>BasicHttpAuthenticationFilter</code> to include ability to
+ * authenticate OAuth2 tokens, which is needed for backwards compatibility with
+ * <code>TokenAuthFilter</code>.
+ *
+ * This behavior is enabled by default for backwards compatibility. To disable
+ * OAuth2 functionality, just comment out the following line from the
+ * <code>etc/shiro.ini</code> file:
+ * <code>authcBasic = org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter</code>
+ * then restart the karaf container.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class ODLHttpAuthenticationFilter extends BasicHttpAuthenticationFilter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ODLHttpAuthenticationFilter.class);
+
+    // defined in lower-case for more efficient string comparison
+    protected static final String BEARER_SCHEME = "bearer";
+
+    protected static final String OPTIONS_HEADER = "OPTIONS";
+
+    public ODLHttpAuthenticationFilter() {
+        super();
+        LOG.info("Creating the ODLHttpAuthenticationFilter");
+    }
+
+    @Override
+    protected String[] getPrincipalsAndCredentials(String scheme, String encoded) {
+        final String decoded = Base64.decodeToString(encoded);
+        // attempt to decode username/password; otherwise decode as token
+        if (decoded.contains(":")) {
+            return decoded.split(":");
+        }
+        return new String[] { encoded };
+    }
+
+    @Override
+    protected boolean isLoginAttempt(String authzHeader) {
+        final String authzScheme = getAuthzScheme().toLowerCase();
+        final String authzHeaderLowerCase = authzHeader.toLowerCase();
+        return authzHeaderLowerCase.startsWith(authzScheme)
+                || authzHeaderLowerCase.startsWith(BEARER_SCHEME);
+    }
+
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
+            Object mappedValue) {
+        final HttpServletRequest httpRequest = WebUtils.toHttp(request);
+        final String httpMethod = httpRequest.getMethod();
+        if (OPTIONS_HEADER.equalsIgnoreCase(httpMethod)) {
+            return true;
+        } else {
+            return super.isAccessAllowed(httpRequest, response, mappedValue);
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonPrincipal.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonPrincipal.java
new file mode 100644
index 00000000..9dd2fd4f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonPrincipal.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.moon;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import org.opendaylight.aaa.api.Claim;
+
+/**
+ * MoonPrincipal contains all user's information returned by moon on successful authentication
+ * @author Alioune BA alioune.ba@orange.com
+ *
+ */
+public  class MoonPrincipal {
+
+    private final String username;
+    private final String domain;
+    private final String userId;
+    private final Set<String> roles;
+    private final String token;
+
+
+    public MoonPrincipal(String username, String domain, String userId, Set<String> roles, String token) {
+        this.username = username;
+        this.domain = domain;
+        this.userId = userId;
+        this.roles = roles;
+        this.token = token;
+    }
+
+    public MoonPrincipal createODLPrincipal(String username, String domain,
+            String userId, Set<String> roles, String token) {
+
+        return new MoonPrincipal(username, domain, userId, roles,token);
+    }
+
+    public Claim principalToClaim (){
+        return new MoonClaim("", this.getUserId(), this.getUsername(), this.getDomain(), this.getRoles());
+    }
+
+    public String getUsername() {
+        return this.username;
+    }
+
+    public String getDomain() {
+        return this.domain;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+
+    public Set<String> getRoles() {
+        return this.roles;
+    }
+
+    public String getToken(){
+        return this.token;
+    }
+
+    public class MoonClaim implements Claim, Serializable {
+        private static final long serialVersionUID = -8115027645190209125L;
+        private int hashCode = 0;
+        private String clientId;
+        private String userId;
+        private String user;
+        private String domain;
+        private ImmutableSet<String> roles;
+
+        public MoonClaim(String clientId, String userId, String user, String domain, Set<String> roles) {
+            this.clientId = clientId;
+            this.userId = userId;
+            this.user = user;
+            this.domain = domain;
+            this.roles = ImmutableSet.<String> builder().addAll(roles).build();
+
+            if (userId.isEmpty() || user.isEmpty() || roles.isEmpty() || roles.contains("")) {
+                throw new IllegalStateException("The Claim is missing one or more of the required fields.");
+            }
+        }
+
+        @Override
+        public String clientId() {
+            return clientId;
+        }
+
+        @Override
+        public String userId() {
+            return userId;
+        }
+
+        @Override
+        public String user() {
+            return user;
+        }
+
+        @Override
+        public String domain() {
+            return domain;
+        }
+
+        @Override
+        public Set<String> roles() {
+            return roles;
+        }
+        public String getClientId() {
+            return clientId;
+        }
+
+        public void setClientId(String clientId) {
+            this.clientId = clientId;
+        }
+
+        public String getUserId() {
+            return userId;
+        }
+
+        public void setUserId(String userId) {
+            this.userId = userId;
+        }
+
+        public String getUser() {
+            return user;
+        }
+
+        public void setUser(String user) {
+            this.user = user;
+        }
+
+        public String getDomain() {
+            return domain;
+        }
+
+        public void setDomain(String domain) {
+            this.domain = domain;
+        }
+
+        public ImmutableSet<String> getRoles() {
+            return roles;
+        }
+
+        public void setRoles(ImmutableSet<String> roles) {
+            this.roles = roles;
+        }
+
+        @Override
+        public String toString() {
+            return "clientId:" + clientId + "," + "userId:" + userId + "," + "userName:" + user
+                    + "," + "domain:" + domain + "," + "roles:" + roles ;
+        }
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonTokenEndpoint.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonTokenEndpoint.java
new file mode 100644
index 00000000..a954a606
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/moon/MoonTokenEndpoint.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.moon;
+
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MoonTokenEndpoint extends HttpServlet{
+
+    private static final long serialVersionUID = 4980356362831585417L;
+    private static final Logger LOG = LoggerFactory.getLogger(MoonTokenEndpoint.class);
+
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        LOG.debug("MoonTokenEndpoint Servlet doPost");
+    }
+
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/MoonRealm.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/MoonRealm.java
new file mode 100644
index 00000000..9ebbb4d7
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/MoonRealm.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.realm;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.opendaylight.aaa.shiro.moon.MoonPrincipal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * MoonRealm is a Shiro Realm that authenticates users from OPNFV/moon platform
+ * @author Alioune BA alioune.ba@orange.com
+ *
+ */
+public class MoonRealm extends AuthorizingRealm{
+
+    private static final Logger LOG = LoggerFactory.getLogger(MoonRealm.class);
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+        // TODO Auto-generated method stub
+        String username = "";
+        String password = "";
+        String domain = "sdn";
+        username = (String) authenticationToken.getPrincipal();
+        final UsernamePasswordToken upt = (UsernamePasswordToken) authenticationToken;
+        password =  new String(upt.getPassword());
+        final MoonPrincipal moonPrincipal = moonAuthenticate(username,password,domain);
+        if (moonPrincipal!=null){
+            return new SimpleAuthenticationInfo(moonPrincipal, password.toCharArray(),getName());
+        }else{
+            return null;
+        }
+    }
+
+    public MoonPrincipal moonAuthenticate(String username, String password, String domain){
+
+        String output = "";
+        ClientConfig config = new DefaultClientConfig();
+        Client client = Client.create(config);
+        JSONTokener tokener;
+        JSONObject object =null;
+        Set<String> UserRoles = new LinkedHashSet<>();
+
+        String server = System.getenv("MOON_SERVER_ADDR");
+        String port = System.getenv("MOON_SERVER_PORT");
+        String URL = "http://" +server+ ":" +port+ "/moon/auth/tokens";
+        LOG.debug("Moon server is at: {} ", server);
+        WebResource webResource = client.resource(URL);
+        String input = "{\"username\": \""+ username + "\"," + "\"password\":" + "\"" + password + "\"," + "\"project\":" + "\"" + domain + "\"" + "}";;
+        ClientResponse response = webResource.type("application/json").post(ClientResponse.class, input);
+        output = response.getEntity(String.class);
+        tokener = new JSONTokener(output);
+        object = new JSONObject(tokener);
+        try {
+            if (object.getString("token")!=null){
+                String token = object.getString("token");
+                String userID = username+"@"+domain;
+                for (int i=0; i< object.getJSONArray("roles").length(); i++){
+                    UserRoles.add((String) object.getJSONArray("roles").get(i));
+                }
+                MoonPrincipal principal = new MoonPrincipal(username,domain,userID,UserRoles,token);
+                return principal;
+            }
+        }catch (JSONException e){
+            throw new IllegalStateException("Authentication Error : "+ object.getJSONObject("error").getString("title"));
+        }
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealm.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealm.java
new file mode 100644
index 00000000..7d0bafd7
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealm.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015, 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.ldap.JndiLdapRealm;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.realm.ldap.LdapUtils;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.Nameable;
+import org.opendaylight.aaa.shiro.accounting.Accounter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An extended implementation of
+ * <code>org.apache.shiro.realm.ldap.JndiLdapRealm</code> which includes
+ * additional Authorization capabilities.  To enable this Realm, add the
+ * following to <code>shiro.ini</code>:
+ *
+ *<code>#ldapRealm = org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealmAuthNOnly
+ *#ldapRealm.userDnTemplate = uid={0},ou=People,dc=DOMAIN,dc=TLD
+ *#ldapRealm.contextFactory.url = ldap://URL:389
+ *#ldapRealm.searchBase = dc=DOMAIN,dc=TLD
+ *#ldapRealm.ldapAttributeForComparison = objectClass
+ *# The CSV list of enabled realms.  In order to enable a realm, add it to the
+ *# list below:
+ * securityManager.realms = $tokenAuthRealm, $ldapRealm</code>
+ *
+ * The values above are specific to the deployed LDAP domain.  If the defaults
+ * are not sufficient, alternatives can be derived through enabling
+ * <code>TRACE</code> level logging.  To enable <code>TRACE</code> level
+ * logging, issue the following command in the karaf shell:
+ * <code>log:set TRACE org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealm</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @see <code>org.apache.shiro.realm.ldap.JndiLdapRealm</code>
+ * @see <a
+ *      href="https://shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/realm/ldap/JndiLdapRealm.html">Shiro
+ *      documentation</a>
+ */
+public class ODLJndiLdapRealm extends JndiLdapRealm implements Nameable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ODLJndiLdapRealm.class);
+
+    /**
+     * When an LDAP Authorization lookup is made for a user account, a list of
+     * attributes are returned.  The attributes are used to determine LDAP
+     * grouping, which is equivalent to ODL role(s).  The default value is
+     * set to "objectClass", which is common attribute for LDAP systems.
+     * The actual value may be configured through setting
+     * <code>ldapAttributeForComparison</code>.
+     */
+    private static final String DEFAULT_LDAP_ATTRIBUTE_FOR_COMPARISON = "objectClass";
+
+    /**
+     * The LDAP nomenclature for user ID, which is used in the authorization query process.
+     */
+    private static final String UID = "uid";
+
+    /**
+     * The searchBase for the ldap query, which indicates the LDAP realms to
+     * search.  By default, this is set to the
+     * <code>super.getUserDnSuffix()</code>.
+     */
+    private String searchBase = super.getUserDnSuffix();
+
+    /**
+     * When an LDAP Authorization lookup is made for a user account, a list of
+     * attributes is returned.  The attributes are used to determine LDAP
+     * grouping, which is equivalent to ODL role(s).  The default is set to
+     * <code>DEFAULT_LDAP_ATTRIBUTE_FOR_COMPARISON</code>.
+     */
+    private String ldapAttributeForComparison = DEFAULT_LDAP_ATTRIBUTE_FOR_COMPARISON;
+
+    /*
+     * Adds debugging information surrounding creation of ODLJndiLdapRealm
+     */
+    public ODLJndiLdapRealm() {
+        super();
+        final String DEBUG_MESSAGE = "Creating ODLJndiLdapRealm";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+    /*
+     * (non-Javadoc) Overridden to expose important audit trail information for
+     * accounting.
+     *
+     * @see
+     * org.apache.shiro.realm.ldap.JndiLdapRealm#doGetAuthenticationInfo(org
+     * .apache.shiro.authc.AuthenticationToken)
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+            throws AuthenticationException {
+
+        // Delegates all AuthN lookup responsibility to the super class
+        try {
+            final String username = getUsername(token);
+            logIncomingConnection(username);
+            return super.doGetAuthenticationInfo(token);
+        } catch (ClassCastException e) {
+            LOG.info("Couldn't service the LDAP connection", e);
+        }
+        return null;
+    }
+
+    /**
+     * Logs an incoming LDAP connection
+     *
+     * @param username
+     *            the requesting user
+     */
+    protected void logIncomingConnection(final String username) {
+        LOG.info("AAA LDAP connection from {}", username);
+        Accounter.output("AAA LDAP connection from " + username);
+    }
+
+    /**
+     * Extracts the username from <code>token</code>
+     *
+     * @param token Encoded token which could contain a username
+     * @return The extracted username
+     * @throws ClassCastException
+     *             The incoming token is not username/password (i.e., X.509
+     *             certificate)
+     */
+    public static String getUsername(AuthenticationToken token) throws ClassCastException {
+        if (null == token) {
+            return null;
+        }
+        return (String) token.getPrincipal();
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+
+        AuthorizationInfo ai = null;
+        try {
+            ai = this.queryForAuthorizationInfo(principals, getContextFactory());
+        } catch (NamingException e) {
+            LOG.error("Unable to query for AuthZ info", e);
+        }
+        return ai;
+    }
+
+    /**
+     * extracts a username from <code>principals</code>
+     *
+     * @param principals A single principal extracted for the username
+     * @return The username if possible
+     * @throws ClassCastException
+     *             the PrincipalCollection contains an element that is not in
+     *             username/password form (i.e., X.509 certificate)
+     */
+    protected String getUsername(final PrincipalCollection principals) throws ClassCastException {
+
+        if (null == principals) {
+            return null;
+        }
+        return (String) getAvailablePrincipal(principals);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * This method is only called if doGetAuthenticationInfo(...) completes successfully AND
+     * the requested endpoint has an RBAC restriction.  To add an RBAC restriction, edit the
+     * etc/shiro.ini file and add a url to the url section.  E.g.,
+     *
+     * <code>/** = authcBasic, roles[person]</code>
+     *
+     * @see org.apache.shiro.realm.ldap.JndiLdapRealm#queryForAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection, org.apache.shiro.realm.ldap.LdapContextFactory)
+     */
+    @Override
+    protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
+            LdapContextFactory ldapContextFactory) throws NamingException {
+
+        AuthorizationInfo authorizationInfo = null;
+        try {
+            final String username = getUsername(principals);
+            final LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
+            final Set<String> roleNames;
+
+            try {
+                roleNames = getRoleNamesForUser(username, ldapContext);
+                authorizationInfo = buildAuthorizationInfo(roleNames);
+            } finally {
+                LdapUtils.closeContext(ldapContext);
+            }
+        } catch (ClassCastException e) {
+            LOG.error("Unable to extract a valid user", e);
+        }
+        return authorizationInfo;
+    }
+
+    public static AuthorizationInfo buildAuthorizationInfo(final Set<String> roleNames) {
+        if (null == roleNames) {
+            return null;
+        }
+        return new SimpleAuthorizationInfo(roleNames);
+    }
+
+    /**
+     * extracts the Set of roles associated with a user based on the username
+     * and ldap context (server).
+     *
+     * @param username The username for the request
+     * @param ldapContext The specific system context provided by <code>shiro.ini</code>
+     * @return A set of roles
+     * @throws NamingException If the ldap search fails
+     */
+    protected Set<String> getRoleNamesForUser(final String username, final LdapContext ldapContext)
+            throws NamingException {
+
+        // Stores the role names, which are equivalent to the set of group names extracted
+        // from the LDAP query.
+        final Set<String> roleNames = new LinkedHashSet<String>();
+
+        final SearchControls searchControls = createSearchControls();
+
+        LOG.debug("Asking the configured LDAP about which groups uid=\"{}\" belongs to using "
+                + "searchBase=\"{}\" ldapAttributeForComparison=\"{}\"",
+                username, searchBase, ldapAttributeForComparison);
+        final NamingEnumeration<SearchResult> answer = ldapContext.search(searchBase,
+                String.format("%s=%s", UID, username), searchControls);
+
+        // Cursor based traversal over the LDAP query result
+        while (answer.hasMoreElements()) {
+            final SearchResult searchResult = answer.next();
+            final Attributes attrs = searchResult.getAttributes();
+            if (attrs != null) {
+                // Extract the attributes from the LDAP search.
+                // attrs.getAttr(String) was not chosen, since all attributes should be exposed
+                // in trace logging should the operator wish to use an alternate attribute.
+                final NamingEnumeration<? extends Attribute> ae = attrs.getAll();
+                while (ae.hasMore()) {
+                    final Attribute attr = ae.next();
+                    LOG.trace("LDAP returned \"{}\" attribute for \"{}\"", attr.getID(), username);
+                    if (attr.getID().equals(ldapAttributeForComparison)) {
+                        // Stresses the point that LDAP groups are EQUIVALENT to ODL role names
+                        // TODO make this configurable via a Strategy pattern so more interesting mappings can be made
+                        final Collection<String> groupNamesExtractedFromLdap = LdapUtils.getAllAttributeValues(attr);
+                        final Collection<String> roleNamesFromLdapGroups = groupNamesExtractedFromLdap;
+                        if (LOG.isTraceEnabled()) {
+                            for (String roleName : roleNamesFromLdapGroups) {
+                                LOG.trace("Mapped the \"{}\" LDAP group to ODL role for \"{}\"", roleName, username);
+                            }
+                        }
+                        roleNames.addAll(roleNamesFromLdapGroups);
+                    }
+                }
+            }
+        }
+        return roleNames;
+    }
+
+    /**
+     * A utility method to help create the search controls for the LDAP lookup
+     *
+     * @return A generic set of search controls for LDAP scoped to subtree
+     */
+    protected static SearchControls createSearchControls() {
+        SearchControls searchControls = new SearchControls();
+        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+        return searchControls;
+    }
+
+    @Override
+    public String getUserDnSuffix() {
+        return super.getUserDnSuffix();
+    }
+
+    /**
+     * Injected from <code>shiro.ini</code> configuration.
+     *
+     * @param searchBase The desired value for searchBase
+     */
+    public void setSearchBase(final String searchBase) {
+        // public for injection reasons
+        this.searchBase = searchBase;
+    }
+
+    /**
+     * Injected from <code>shiro.ini</code> configuration.
+     *
+     * @param ldapAttributeForComparison The attribute from which groups are extracted
+     */
+    public void setLdapAttributeForComparison(final String ldapAttributeForComparison) {
+        // public for injection reasons
+        this.ldapAttributeForComparison = ldapAttributeForComparison;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmAuthNOnly.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmAuthNOnly.java
new file mode 100644
index 00000000..978266c5
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmAuthNOnly.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.realm.ldap.JndiLdapRealm;
+import org.opendaylight.aaa.shiro.accounting.Accounter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wrapper class for <code>org.apache.shiro.realm.ldap.JndiLdapRealm</code>.
+ * This implementation disables Authorization so any LDAP user is able to access
+ * server resources. This is particularly useful for quickly prototyping ODL
+ * without worrying about resolving LDAP attributes (groups) to OpenDaylight
+ * roles.
+ *
+ * The motivation for subclassing Shiro's implementation is two-fold: 1) Enhance
+ * the default logging of Shiro. This allows us to more easily log incoming
+ * connections, providing some security auditing. 2) Provide a common package in
+ * the classpath for ODL supported Realm implementations (i.e.,
+ * <code>org.opendaylight.aaa.shiro.realm</code>), which consolidates the number
+ * of <code>Import-Package</code> statements consumers need to enumerate. For
+ * example, the netconf project only needs to import
+ * <code>org.opendaylight.aaa.shiro.realm</code>, and does not need to worry
+ * about importing Shiro packages.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class ODLJndiLdapRealmAuthNOnly extends JndiLdapRealm {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ODLJndiLdapRealmAuthNOnly.class);
+
+    private static final String LDAP_CONNECTION_MESSAGE = "AAA LDAP connection from ";
+
+    /*
+     * Adds debugging information surrounding creation of ODLJndiLdapRealm
+     */
+    public ODLJndiLdapRealmAuthNOnly() {
+        super();
+        LOG.debug("Creating ODLJndiLdapRealmAuthNOnly");
+    }
+
+    /*
+     * (non-Javadoc) Overridden to expose important audit trail information for
+     * accounting.
+     *
+     * @see
+     * org.apache.shiro.realm.ldap.JndiLdapRealm#doGetAuthenticationInfo(org
+     * .apache.shiro.authc.AuthenticationToken)
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+            throws AuthenticationException {
+
+        try {
+            final String username = getUsername(token);
+            logIncomingConnection(username);
+            return super.doGetAuthenticationInfo(token);
+        } catch (ClassCastException e) {
+            LOG.info("Couldn't service the LDAP connection", e);
+        }
+        return null;
+    }
+
+    /**
+     * Logs an incoming LDAP connection
+     *
+     * @param username
+     *            the requesting user
+     */
+    protected void logIncomingConnection(final String username) {
+        final String message = LDAP_CONNECTION_MESSAGE + username;
+        LOG.info(message);
+        Accounter.output(message);
+    }
+
+    /**
+     * Extracts the username from <code>token</code>
+     *
+     * @param token Which possibly contains a username
+     * @return the username if it can be extracted
+     * @throws ClassCastException
+     *             The incoming token is not username/password (i.e., X.509
+     *             certificate)
+     */
+    public static String getUsername(AuthenticationToken token) throws ClassCastException {
+        if (null == token) {
+            return null;
+        }
+        return (String) token.getPrincipal();
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/RadiusRealm.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/RadiusRealm.java
new file mode 100644
index 00000000..51d4bfbf
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/RadiusRealm.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.realm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+
+/**
+ * Implementation of a Radius AuthorizingRealm.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class RadiusRealm extends AuthorizingRealm {
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+        // TODO use JRadius to extract Authorization Info
+        return null;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0)
+            throws AuthenticationException {
+        // TODO use JRadius to extract Authentication Info
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TACACSRealm.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TACACSRealm.java
new file mode 100644
index 00000000..38d7d91a
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TACACSRealm.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+
+/**
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class TACACSRealm extends AuthorizingRealm {
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+        // TODO Extract AuthorizationInfo using JNetLib
+        return null;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0)
+            throws AuthenticationException {
+        // TODO Extract AuthenticationInfo using JNetLib
+        return null;
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java
new file mode 100644
index 00000000..f9ae5051
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealm.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import com.google.common.base.Strings;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenAuth;
+import org.opendaylight.aaa.basic.HttpBasicAuth;
+import org.opendaylight.aaa.sts.ServiceLocator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TokenAuthRealm is an adapter between the AAA shiro subsystem and the existing
+ * <code>TokenAuth</code> mechanisms. Thus, one can enable use of
+ * <code>IDMStore</code> and <code>IDMMDSALStore</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class TokenAuthRealm extends AuthorizingRealm {
+
+    private static final String USERNAME_DOMAIN_SEPARATOR = "@";
+
+    /**
+     * The unique identifying name for <code>TokenAuthRealm</code>
+     */
+    private static final String TOKEN_AUTH_REALM_DEFAULT_NAME = "TokenAuthRealm";
+
+    /**
+     * The message that is displayed if no <code>TokenAuth</code> interface is
+     * available yet
+     */
+    private static final String AUTHENTICATION_SERVICE_UNAVAILABLE_MESSAGE = "{\"error\":\"Authentication service unavailable\"}";
+
+    /**
+     * The message that is displayed if credentials are missing or malformed
+     */
+    private static final String FATAL_ERROR_DECODING_CREDENTIALS = "{\"error\":\"Unable to decode credentials\"}";
+
+    /**
+     * The message that is displayed if non-Basic Auth is attempted
+     */
+    private static final String FATAL_ERROR_BASIC_AUTH_ONLY = "{\"error\":\"Only basic authentication is supported by TokenAuthRealm\"}";
+
+    /**
+     * The purposefully generic message displayed if <code>TokenAuth</code> is
+     * unable to validate the given credentials
+     */
+    private static final String UNABLE_TO_AUTHENTICATE = "{\"error\":\"Could not authenticate\"}";
+
+    private static final Logger LOG = LoggerFactory.getLogger(TokenAuthRealm.class);
+
+    public TokenAuthRealm() {
+        super();
+        super.setName(TOKEN_AUTH_REALM_DEFAULT_NAME);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * Roles are derived from <code>TokenAuth.authenticate()</code>. Shiro roles
+     * are identical to existing IDM roles.
+     *
+     * @see
+     * org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache
+     * .shiro.subject.PrincipalCollection)
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+        final Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
+        final ODLPrincipal odlPrincipal;
+        try {
+            odlPrincipal = (ODLPrincipal) primaryPrincipal;
+            return new SimpleAuthorizationInfo(odlPrincipal.getRoles());
+        } catch(ClassCastException e) {
+            LOG.error("Couldn't decode authorization request", e);
+        }
+        return new SimpleAuthorizationInfo();
+    }
+
+    /**
+     * Bridge new to old style <code>TokenAuth</code> interface.
+     *
+     * @param username The request username
+     * @param password The request password
+     * @param domain The request domain
+     * @return <code>username:password:domain</code>
+     */
+    static String getUsernamePasswordDomainString(final String username, final String password,
+            final String domain) {
+        return username + HttpBasicAuth.AUTH_SEP + password  + HttpBasicAuth.AUTH_SEP + domain;
+    }
+
+    /**
+     *
+     * @param credentialToken
+     * @return Base64 encoded token
+     */
+    static String getEncodedToken(final String credentialToken) {
+        return Base64.encodeToString(credentialToken.getBytes());
+    }
+
+    /**
+     *
+     * @param encodedToken
+     * @return Basic <code>encodedToken</code>
+     */
+    static String getTokenAuthHeader(final String encodedToken) {
+        return HttpBasicAuth.BASIC_PREFIX + encodedToken;
+    }
+
+    /**
+     *
+     * @param tokenAuthHeader
+     * @return a map with the basic auth header
+     */
+    Map<String, List<String>> formHeadersWithToken(final String tokenAuthHeader) {
+        final Map<String, List<String>> headers = new HashMap<String, List<String>>();
+        final List<String> headerValue = new ArrayList<String>();
+        headerValue.add(tokenAuthHeader);
+        headers.put(HttpBasicAuth.AUTH_HEADER, headerValue);
+        return headers;
+    }
+
+    /**
+     * Adapter between basic authentication mechanism and existing
+     * <code>TokenAuth</code> interface.
+     *
+     * @param username Username from the request
+     * @param password Password from the request
+     * @param domain Domain from the request
+     * @return input map for <code>TokenAuth.validate()</code>
+     */
+    Map<String, List<String>> formHeaders(final String username, final String password,
+            final String domain) {
+        String usernamePasswordToken = getUsernamePasswordDomainString(username, password, domain);
+        String encodedToken = getEncodedToken(usernamePasswordToken);
+        String tokenAuthHeader = getTokenAuthHeader(encodedToken);
+        return formHeadersWithToken(tokenAuthHeader);
+    }
+
+    /**
+     * Adapter to check for available <code>TokenAuth<code> implementations.
+     *
+     * @return
+     */
+    boolean isTokenAuthAvailable() {
+        return ServiceLocator.getInstance().getAuthenticationService() != null;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * Authenticates against any <code>TokenAuth</code> registered with the
+     * <code>ServiceLocator</code>
+     *
+     * @see
+     * org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org
+     * .apache.shiro.authc.AuthenticationToken)
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
+            throws AuthenticationException {
+
+        String username = "";
+        String password = "";
+        String domain = HttpBasicAuth.DEFAULT_DOMAIN;
+
+        try {
+            final String qualifiedUser = extractUsername(authenticationToken);
+            if (qualifiedUser.contains(USERNAME_DOMAIN_SEPARATOR)) {
+                final String [] qualifiedUserArray = qualifiedUser.split(USERNAME_DOMAIN_SEPARATOR);
+                try {
+                    username = qualifiedUserArray[0];
+                    domain = qualifiedUserArray[1];
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    LOG.trace("Couldn't parse domain from {}; trying without one",
+                            qualifiedUser, e);
+                }
+            } else {
+                username = qualifiedUser;
+            }
+            password = extractPassword(authenticationToken);
+
+        } catch (NullPointerException e) {
+            throw new AuthenticationException(FATAL_ERROR_DECODING_CREDENTIALS, e);
+        } catch (ClassCastException e) {
+            throw new AuthenticationException(FATAL_ERROR_BASIC_AUTH_ONLY, e);
+        }
+
+        // check to see if there are TokenAuth implementations available
+        if (!isTokenAuthAvailable()) {
+            throw new AuthenticationException(AUTHENTICATION_SERVICE_UNAVAILABLE_MESSAGE);
+        }
+
+        // if the password is empty, this is an OAuth2 request, not a Basic HTTP
+        // Auth request
+        if (!Strings.isNullOrEmpty(password)) {
+            if (ServiceLocator.getInstance().getAuthenticationService().isAuthEnabled()) {
+                Map<String, List<String>> headers = formHeaders(username, password, domain);
+                // iterate over <code>TokenAuth</code> implementations and
+                // attempt to
+                // authentication with each one
+                final List<TokenAuth> tokenAuthCollection = ServiceLocator.getInstance()
+                        .getTokenAuthCollection();
+                for (TokenAuth ta : tokenAuthCollection) {
+                    try {
+                        LOG.debug("Authentication attempt using {}", ta.getClass().getName());
+                        final Authentication auth = ta.validate(headers);
+                        if (auth != null) {
+                            LOG.debug("Authentication attempt successful");
+                            ServiceLocator.getInstance().getAuthenticationService().set(auth);
+                            final ODLPrincipal odlPrincipal = ODLPrincipal.createODLPrincipal(auth);
+                            return new SimpleAuthenticationInfo(odlPrincipal, password.toCharArray(),
+                                    getName());
+                        }
+                    } catch (AuthenticationException ae) {
+                        LOG.debug("Authentication attempt unsuccessful");
+                        throw new AuthenticationException(UNABLE_TO_AUTHENTICATE, ae);
+                    }
+                }
+            }
+        }
+
+        // extract the authentication token and attempt validation of the token
+        final String token = extractUsername(authenticationToken);
+        final Authentication auth;
+        try {
+            auth = validate(token);
+            if (auth != null) {
+                final ODLPrincipal odlPrincipal = ODLPrincipal.createODLPrincipal(auth);
+                return new SimpleAuthenticationInfo(odlPrincipal, "", getName());
+            }
+        } catch (AuthenticationException e) {
+            LOG.debug("Unknown OAuth2 Token Access Request", e);
+        }
+
+        LOG.debug("Authentication failed: exhausted TokenAuth resources");
+        return null;
+    }
+
+    private Authentication validate(final String token) {
+        Authentication auth = ServiceLocator.getInstance().getTokenStore().get(token);
+        if (auth == null) {
+            throw new AuthenticationException("Could not validate the token " + token);
+        } else {
+            ServiceLocator.getInstance().getAuthenticationService().set(auth);
+        }
+        return auth;
+    }
+
+    /**
+     * extract the username from an <code>AuthenticationToken</code>
+     *
+     * @param authenticationToken
+     * @return
+     * @throws ClassCastException
+     * @throws NullPointerException
+     */
+    static String extractUsername(final AuthenticationToken authenticationToken)
+            throws ClassCastException, NullPointerException {
+
+        return (String) authenticationToken.getPrincipal();
+    }
+
+    /**
+     * extract the password from an <code>AuthenticationToken</code>
+     *
+     * @param authenticationToken
+     * @return
+     * @throws ClassCastException
+     * @throws NullPointerException
+     */
+    static String extractPassword(final AuthenticationToken authenticationToken)
+            throws ClassCastException, NullPointerException {
+
+        final UsernamePasswordToken upt = (UsernamePasswordToken) authenticationToken;
+        return new String(upt.getPassword());
+    }
+
+    /**
+     * Since <code>TokenAuthRealm</code> is an <code>AuthorizingRealm</code>, it supports
+     * individual steps for authentication and authorization.  In ODL's existing <code>TokenAuth</code>
+     * mechanism, authentication and authorization are currently done in a single monolithic step.
+     * <code>ODLPrincipal</code> is abstracted as a DTO between the two steps.  It fulfills the
+     * responsibility of a <code>Principal</code>, since it contains identification information
+     * but no credential information.
+     *
+     * @author Ryan Goulding (ryandgoulding@gmail.com)
+     */
+    private static class ODLPrincipal {
+
+        private final String username;
+        private final String domain;
+        private final String userId;
+        private final Set<String> roles;
+
+        private ODLPrincipal(final String username, final String domain, final String userId, final Set<String> roles) {
+            this.username = username;
+            this.domain = domain;
+            this.userId = userId;
+            this.roles = roles;
+        }
+
+        /**
+         * A static factory method to create <code>ODLPrincipal</code> instances.
+         *
+         * @param username The authenticated user
+         * @param domain The domain <code>username</code> belongs to.
+         * @param userId The unique key for <code>username</code>
+         * @param roles The roles associated with <code>username</code>@<code>domain</code>
+         * @return A Principal for the given session;  essentially a DTO.
+         */
+        static ODLPrincipal createODLPrincipal(final String username, final String domain,
+                final String userId, final Set<String> roles) {
+
+            return new ODLPrincipal(username, domain, userId, roles);
+        }
+
+        /**
+         * A static factory method to create <code>ODLPrincipal</code> instances.
+         *
+         * @param auth Contains identifying information for the particular request.
+         * @return A Principal for the given session;  essentially a DTO.
+         */
+        static ODLPrincipal createODLPrincipal(final Authentication auth) {
+            return createODLPrincipal(auth.user(), auth.domain(), auth.userId(), auth.roles());
+        }
+
+        String getUsername() {
+            return this.username;
+        }
+
+        String getDomain() {
+            return this.domain;
+        }
+
+        String getUserId() {
+            return this.userId;
+        }
+
+        Set<String> getRoles() {
+            return this.roles;
+        }
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironment.java b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironment.java
new file mode 100644
index 00000000..acf4022c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironment.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.web.env;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.config.Ini.Section;
+import org.apache.shiro.web.env.IniWebEnvironment;
+import org.opendaylight.aaa.shiro.accounting.Accounter;
+import org.opendaylight.aaa.shiro.authorization.DefaultRBACRules;
+import org.opendaylight.aaa.shiro.authorization.RBACRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Identical to <code>IniWebEnvironment</code> except the Ini is loaded from
+ * <code>$KARAF_HOME/etc/shiro.ini</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class KarafIniWebEnvironment extends IniWebEnvironment {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KarafIniWebEnvironment.class);
+    public static final String DEFAULT_SHIRO_INI_FILE = "etc/shiro.ini";
+    public static final String SHIRO_FILE_PREFIX = "file:/";
+
+    public KarafIniWebEnvironment() {
+    }
+
+    @Override
+    public void init() {
+        // Initialize the Shiro environment from etc/shiro.ini then delegate to
+        // the parent class
+        Ini ini;
+        try {
+            ini = createDefaultShiroIni();
+            // appendCustomIniRules(ini);
+            setIni(ini);
+        } catch (FileNotFoundException e) {
+            final String ERROR_MESSAGE = "Could not find etc/shiro.ini";
+            LOG.error(ERROR_MESSAGE, e);
+        }
+        super.init();
+    }
+
+    /**
+     * A hook for installing custom default RBAC rules for security purposes.
+     *
+     * @param ini
+     */
+    private void appendCustomIniRules(final Ini ini) {
+        final String INSTALL_MESSAGE = "Installing the RBAC rule: %s";
+        Section urlSection = getOrCreateUrlSection(ini);
+        Collection<RBACRule> rbacRules = DefaultRBACRules.getInstance().getRBACRules();
+        for (RBACRule rbacRule : rbacRules) {
+            urlSection.put(rbacRule.getUrlPattern(), rbacRule.getRolesInShiroFormat());
+            Accounter.output(String.format(INSTALL_MESSAGE, rbacRule));
+        }
+    }
+
+    /**
+     * Extracts the url section of the Ini file, or creates one if it doesn't
+     * already exist
+     *
+     * @param ini
+     * @return
+     */
+    private Section getOrCreateUrlSection(final Ini ini) {
+        final String URL_SECTION_TITLE = "urls";
+        Section urlSection = ini.getSection(URL_SECTION_TITLE);
+        if (urlSection == null) {
+            LOG.debug("shiro.ini does not contain a [urls] section; creating one");
+            urlSection = ini.addSection(URL_SECTION_TITLE);
+        } else {
+            LOG.debug("shiro.ini contains a [urls] section; appending rules to existing");
+        }
+        return urlSection;
+    }
+
+    /**
+     *
+     * @return Ini associated with <code>$KARAF_HOME/etc/shiro.ini</code>
+     * @throws FileNotFoundException
+     */
+    static Ini createDefaultShiroIni() throws FileNotFoundException {
+        return createShiroIni(DEFAULT_SHIRO_INI_FILE);
+    }
+
+    /**
+     *
+     * @param path
+     *            the file path, which is either absolute or relative to
+     *            <code>$KARAF_HOME</code>
+     * @return Ini loaded from <code>path</code>
+     */
+    static Ini createShiroIni(final String path) throws FileNotFoundException {
+        File f = new File(path);
+        Ini ini = new Ini();
+        final String fileBasedIniPath = createFileBasedIniPath(f.getAbsolutePath());
+        ini.loadFromPath(fileBasedIniPath);
+        return ini;
+    }
+
+    /**
+     *
+     * @param path
+     *            the file path, which is either absolute or relative to
+     *            <code>$KARAF_HOME</code>
+     * @return <code>file:/$KARAF_HOME/etc/shiro.ini</code>
+     */
+    static String createFileBasedIniPath(final String path) {
+        String fileBasedIniPath = SHIRO_FILE_PREFIX + path;
+        LOG.debug(fileBasedIniPath);
+        return fileBasedIniPath;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/WEB-INF/web.xml b/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/WEB-INF/web.xml
new file mode 100644
index 00000000..63288c23
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/WEB-INF/web.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+    version="3.0">
+
+    <servlet>
+        <servlet-name>MOON</servlet-name>
+        <servlet-class>org.opendaylight.aaa.shiro.moon.MoonTokenEndpoint</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>MOON</servlet-name>
+        <url-pattern>/token</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>MOON</servlet-name>
+        <url-pattern>/revoke</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>MOON</servlet-name>
+        <url-pattern>/validate</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>MOON</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <!-- Shiro Filter -->
+    <context-param>
+      <param-name>shiroEnvironmentClass</param-name>
+      <param-value>org.opendaylight.aaa.shiro.web.env.KarafIniWebEnvironment</param-value>
+    </context-param>
+
+    <listener>
+        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
+    </listener>
+
+    <filter>
+        <filter-name>ShiroFilter</filter-name>
+        <filter-class>org.opendaylight.aaa.shiro.filters.AAAFilter</filter-class>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>ShiroFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+</web-app>
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/shiro.ini b/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/shiro.ini
new file mode 100644
index 00000000..b48abe96
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/main/resources/shiro.ini
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+#
+
+###############################################################################
+# shiro.ini                                                                   #
+#                                                                             #
+# Configuration of OpenDaylight's aaa-shiro feature.  Provided Realm          #
+# implementations include:                                                    #
+# - TokenAuthRealm (enabled by default)                                       #
+# - ODLJndiLdapRealm (disabled by default)                                    #
+# - ODLJndiLdapRealmAuthNOnly (disabled by default)                           #
+# Basic user configuration through shiro.ini is disabled for security         #
+# purposes.                                                                   #
+###############################################################################
+
+
+
+[main]
+###############################################################################
+# realms                                                                      #
+#                                                                             #
+# This section is dedicated to setting up realms for OpenDaylight.  Realms    #
+# are essentially different methods for providing AAA.  ODL strives to provide#
+# highly-configurable AAA by providing pluggable infrastructure.  By deafult, #
+# TokenAuthRealm is enabled out of the box (which bridges to the existing AAA #
+# mechanisms).  More than one realm can be enabled, and the realms are        #
+# tried Round-Robin until:                                                    #
+# 1) a realm successfully authenticates the incoming request                  #
+# 2) all realms are exhausted, and 401 is returned                            #
+###############################################################################
+
+# ODL provides a few LDAP implementations, which are disabled out of the box.
+# ODLJndiLdapRealm includes authorization functionality based on LDAP elements
+# extracted through and LDAP search.  This requires a bit of knowledge about
+# how your LDAP system is setup.  An example is provided below:
+#ldapRealm = org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealm
+#ldapRealm.userDnTemplate = uid={0},ou=People,dc=DOMAIN,dc=TLD
+#ldapRealm.contextFactory.url = ldap://<URL>:389
+#ldapRealm.searchBase = dc=DOMAIN,dc=TLD
+#ldapRealm.ldapAttributeForComparison = objectClass
+
+# ODL also provides ODLJndiLdapRealmAuthNOnly.  Essentially, this allows
+# access through AAAFilter to any user that can authenticate against the
+# provided LDAP server.
+#ldapRealm = org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealmAuthNOnly
+#ldapRealm.userDnTemplate = uid={0},ou=People,dc=DOMAIN,dc=TLD
+#ldapRealm.contextFactory.url = ldap://<URL>:389
+
+# Bridge to existing h2/idmlight/mdsal authentication/authorization mechanisms.
+# This realm is enabled by default, and utilizes h2-store by default.
+#tokenAuthRealm = org.opendaylight.aaa.shiro.realm.TokenAuthRealm
+# Defining moon realm
+moonAuthRealm = org.opendaylight.aaa.shiro.realm.MoonRealm
+
+# The CSV list of enabled realms.  In order to enable a realm, add it to the
+# list below:
+#securityManager.realms = $tokenAuthRealm
+# Configure the Shiro Security Manager to use Moon Realm
+securityManager.realms = $moonAuthRealm
+
+# adds a custom AuthenticationFilter to support OAuth2 for backwards
+# compatibility.  To disable OAuth2 access, just comment out the next line
+# and authcBasic will default to BasicHttpAuthenticationFilter, a
+# Shiro-provided class.
+authcBasic = org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter
+# OAuth2 Filer for moon token AuthN
+rest = org.opendaylight.aaa.shiro.filters.MoonOAuthFilter
+
+# add in AuthenticationListener, a Listener that records whether
+# authentication attempts are successful or unsuccessful.  This audit
+# information is disabled by default, to avoid log flooding.  To enable,
+# issue the following in karaf:
+# >log:set DEBUG org.opendaylight.aaa.shiro.filters.AuthenticationListener
+accountingListener = org.opendaylight.aaa.shiro.filters.AuthenticationListener
+securityManager.authenticator.authenticationListeners = $accountingListener
+
+
+
+[urls]
+###############################################################################
+# url authorization section                                                   #
+#                                                                             #
+# This section is dedicated to defining url-based authorization according to: #
+# http://shiro.apache.org/web.html                                            #
+###############################################################################
+
+# Restrict AAA endpoints to users w/ admin role
+/v1/users/** = authcBasic
+/v1/domains/** = authcBasic
+/v1/roles/** = authcBasic
+
+#Filter OAuth2 request$
+/token = rest
+
+# General access through AAAFilter requires valid credentials (AuthN only).
+/** = authcBasic
+
+# Access to the credential store is limited to the valid users who have the
+# admin role. The following line is only needed if the mdsal store is enabled
+#(the mdsal store is disabled by default).
+/config/aaa-authn-model** = authcBasic,roles[admin]
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java
new file mode 100644
index 00000000..2d9c8976
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.filters.AAAFilter;
+
+/**
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class ServiceProxyTest {
+
+    @Test
+    public void testGetInstance() {
+        // ensures that singleton pattern is working
+        assertNotNull(ServiceProxy.getInstance());
+    }
+
+    @Test
+    public void testGetSetEnabled() {
+        // combines set and get tests. These are important in this instance,
+        // because getEnabled allows an optional callback Filter.
+        ServiceProxy.getInstance().setEnabled(true);
+        assertTrue(ServiceProxy.getInstance().getEnabled(null));
+
+        AAAFilter testFilter = new AAAFilter();
+        // register the filter
+        ServiceProxy.getInstance().getEnabled(testFilter);
+        assertTrue(testFilter.isEnabled());
+
+        ServiceProxy.getInstance().setEnabled(false);
+        assertFalse(ServiceProxy.getInstance().getEnabled(testFilter));
+        assertFalse(testFilter.isEnabled());
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/TestAppender.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/TestAppender.java
new file mode 100644
index 00000000..ec9375dc
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/TestAppender.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A custom slf4j <code>Appender</code> which stores <code>LoggingEvent</code>(s) in memory
+ * for future retrieval.  This is useful from inside test resources.  This class is specified
+ * within <code>logback-test.xml</code>.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class TestAppender extends AppenderBase<LoggingEvent> {
+
+    /**
+     * stores all log events in memory, instead of file
+     */
+    private List<LoggingEvent> events = new Vector<>();
+
+    /**
+     * Since junit maven & junit instantiate the logging appender (as provided
+     * by logback-test.xml), singleton is not possible.  The next best thing is to track the
+     * current instance so it can be retrieved by Test instances.
+     */
+    private static volatile TestAppender currentInstance;
+
+    /**
+     * keeps track of the current instance
+     */
+    public TestAppender() {
+        currentInstance = this;
+    }
+
+    @Override
+    protected void append(final LoggingEvent e) {
+        events.add(e);
+    }
+
+    /**
+     * Extract the log.
+     *
+     * @return the in-memory representation of <code>LoggingEvent</code>(s)
+     */
+    public List<LoggingEvent> getEvents() {
+        return events;
+    }
+
+    /**
+     * A way to extract the appender from Test instances.
+     *
+     * @return <code>this</code>
+     */
+    public static TestAppender getCurrentInstance() {
+        return currentInstance;
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRulesTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRulesTest.java
new file mode 100644
index 00000000..38658f0c
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/DefaultRBACRulesTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.authorization;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import org.junit.Test;
+
+/**
+ * A few basic test cases for the DefualtRBACRules singleton container.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class DefaultRBACRulesTest {
+
+    @Test
+    public void testGetInstance() {
+        assertNotNull(DefaultRBACRules.getInstance());
+        assertEquals(DefaultRBACRules.getInstance(), DefaultRBACRules.getInstance());
+    }
+
+    @Test
+    public void testGetRBACRules() {
+        Collection<RBACRule> rbacRules = DefaultRBACRules.getInstance().getRBACRules();
+        assertNotNull(rbacRules);
+
+        // check that a copy was returned
+        int originalSize = rbacRules.size();
+        rbacRules.add(RBACRule.createAuthorizationRule("fakeurl/*", Sets.newHashSet("admin")));
+        assertEquals(originalSize, DefaultRBACRules.getInstance().getRBACRules().size());
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/RBACRuleTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/RBACRuleTest.java
new file mode 100644
index 00000000..825fe626
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/authorization/RBACRuleTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.authorization;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.HashSet;
+import org.junit.Test;
+
+public class RBACRuleTest {
+
+    private static final String BASIC_RBAC_RULE_URL_PATTERN = "/*";
+    private static final Collection<String> BASIC_RBAC_RULE_ROLES = Sets.newHashSet("admin");
+    private RBACRule basicRBACRule = RBACRule.createAuthorizationRule(BASIC_RBAC_RULE_URL_PATTERN,
+            BASIC_RBAC_RULE_ROLES);
+
+    private static final String COMPLEX_RBAC_RULE_URL_PATTERN = "/auth/v1/";
+    private static final Collection<String> COMPLEX_RBAC_RULE_ROLES = Sets.newHashSet("admin",
+            "user");
+    private RBACRule complexRBACRule = RBACRule.createAuthorizationRule(
+            COMPLEX_RBAC_RULE_URL_PATTERN, COMPLEX_RBAC_RULE_ROLES);
+
+    @Test
+    public void testCreateAuthorizationRule() {
+        // positive test cases
+        assertNotNull(RBACRule.createAuthorizationRule(BASIC_RBAC_RULE_URL_PATTERN,
+                BASIC_RBAC_RULE_ROLES));
+        assertNotNull(RBACRule.createAuthorizationRule(COMPLEX_RBAC_RULE_URL_PATTERN,
+                COMPLEX_RBAC_RULE_ROLES));
+
+        // negative test cases
+        // both null
+        assertNull(RBACRule.createAuthorizationRule(null, null));
+
+        // url pattern is null
+        assertNull(RBACRule.createAuthorizationRule(null, BASIC_RBAC_RULE_ROLES));
+        // url pattern is empty string
+        assertNull(RBACRule.createAuthorizationRule("", BASIC_RBAC_RULE_ROLES));
+
+        // roles is null
+        assertNull(RBACRule.createAuthorizationRule(BASIC_RBAC_RULE_URL_PATTERN, null));
+        // roles is empty collection
+        assertNull(RBACRule.createAuthorizationRule(COMPLEX_RBAC_RULE_URL_PATTERN,
+                new HashSet<String>()));
+    }
+
+    @Test
+    public void testGetUrlPattern() {
+        assertEquals(BASIC_RBAC_RULE_URL_PATTERN, basicRBACRule.getUrlPattern());
+        assertEquals(COMPLEX_RBAC_RULE_URL_PATTERN, complexRBACRule.getUrlPattern());
+    }
+
+    @Test
+    public void testGetRoles() {
+        assertTrue(BASIC_RBAC_RULE_ROLES.containsAll(basicRBACRule.getRoles()));
+        basicRBACRule.getRoles().clear();
+        // test that getRoles() produces a new object
+        assertFalse(basicRBACRule.getRoles().isEmpty());
+        assertTrue(basicRBACRule.getRoles().containsAll(BASIC_RBAC_RULE_ROLES));
+
+        assertTrue(COMPLEX_RBAC_RULE_ROLES.containsAll(complexRBACRule.getRoles()));
+        complexRBACRule.getRoles().add("newRole");
+        // test that getRoles() produces a new object
+        assertFalse(complexRBACRule.getRoles().contains("newRole"));
+        assertTrue(complexRBACRule.getRoles().containsAll(COMPLEX_RBAC_RULE_ROLES));
+    }
+
+    @Test
+    public void testGetRolesInShiroFormat() {
+        final String BASIC_RBAC_RULE_EXPECTED_SHIRO_FORMAT = "roles[admin]";
+        assertEquals(BASIC_RBAC_RULE_EXPECTED_SHIRO_FORMAT, basicRBACRule.getRolesInShiroFormat());
+
+        // set ordering is not predictable, so both formats must be considered
+        final String COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_1 = "roles[admin, user]";
+        final String COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_2 = "roles[user, admin]";
+        assertTrue(COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_1.equals(complexRBACRule
+                .getRolesInShiroFormat())
+                || COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_2.equals(complexRBACRule
+                        .getRolesInShiroFormat()));
+    }
+
+    @Test
+    public void testToString() {
+        final String BASIC_RBAC_RULE_EXPECTED_SHIRO_FORMAT = "/*=roles[admin]";
+        assertEquals(BASIC_RBAC_RULE_EXPECTED_SHIRO_FORMAT, basicRBACRule.toString());
+
+        // set ordering is not predictable,s o both formats must be considered
+        final String COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_1 = "/auth/v1/=roles[admin, user]";
+        final String COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_2 = "/auth/v1/=roles[user, admin]";
+        assertTrue(COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_1.equals(complexRBACRule.toString())
+                || COMPLEX_RBAC_RULE_EXPECTED_SHIRO_FORMAT_2.equals(complexRBACRule.toString()));
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationListenerTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationListenerTest.java
new file mode 100644
index 00000000..1c823525
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationListenerTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import static org.junit.Assert.*;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+
+import java.util.List;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.TestAppender;
+import org.opendaylight.aaa.shiro.filters.AuthenticationListener;
+
+/**
+ * Test AuthenticationListener, which is responsible for logging Accounting events.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationListenerTest {
+
+    @Test
+    public void testOnSuccess() throws Exception {
+        // sets up a successful authentication attempt
+        final AuthenticationListener authenticationListener = new AuthenticationListener();
+        final UsernamePasswordToken authenticationToken = new UsernamePasswordToken();
+        authenticationToken.setUsername("successfulUser1");
+        authenticationToken.setHost("successfulHost1");
+        final SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo();
+        // the following call produces accounting output
+        authenticationListener.onSuccess(authenticationToken, simpleAuthenticationInfo);
+
+        // grab the latest log output and make sure it is in line with what is expected
+        final List<LoggingEvent> loggingEvents = TestAppender.getCurrentInstance().getEvents();
+        // the latest logging event is the one we need to inspect
+        final int whichLoggingEvent = loggingEvents.size() - 1;
+        final LoggingEvent latestLoggingEvent = loggingEvents.get(whichLoggingEvent);
+        final String latestLogMessage = latestLoggingEvent.getMessage();
+        assertEquals("Successful authentication attempt by successfulUser1 from successfulHost1",
+                latestLogMessage);
+    }
+
+    @Test
+    public void testOnFailure() throws Exception {
+        // variables for an unsucessful authentication attempt
+        final AuthenticationListener authenticationListener = new AuthenticationListener();
+        final UsernamePasswordToken authenticationToken = new UsernamePasswordToken();
+        authenticationToken.setUsername("unsuccessfulUser1");
+        authenticationToken.setHost("unsuccessfulHost1");
+        final AuthenticationException authenticationException =
+                new AuthenticationException("test auth exception");
+        // produces unsuccessful authentication attempt output
+        authenticationListener.onFailure(authenticationToken, authenticationException);
+
+        // grab the latest log output and ensure it is in line with what is expected
+        final List<LoggingEvent> loggingEvents = TestAppender.getCurrentInstance().getEvents();
+        final int whichLoggingEvent = loggingEvents.size() - 1;
+        final LoggingEvent latestLoggingEvent = loggingEvents.get(whichLoggingEvent);
+        final String latestLogMessage = latestLoggingEvent.getMessage();
+        assertEquals("Unsuccessful authentication attempt by unsuccessfulUser1 from unsuccessfulHost1",
+                latestLogMessage);
+    }
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtilsTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtilsTest.java
new file mode 100644
index 00000000..09331c52
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/filters/AuthenticationTokenUtilsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.filters;
+
+import static org.junit.Assert.*;
+
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.filters.AuthenticationTokenUtils;
+
+/**
+ * Tests authentication token output utilities.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class AuthenticationTokenUtilsTest {
+
+    /**
+     * A sample non-UsernamePasswordToken implementation for testing.
+     */
+    private final class NotUsernamePasswordToken implements AuthenticationToken {
+
+        @Override
+        public Object getPrincipal() {
+            return null;
+        }
+
+        @Override
+        public Object getCredentials() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testIsUsernamePasswordToken() throws Exception {
+        // null test
+        final AuthenticationToken nullUsernamePasswordToken = null;
+        assertFalse(AuthenticationTokenUtils.isUsernamePasswordToken(nullUsernamePasswordToken));
+
+        // alternate implementation of AuthenticationToken
+        final AuthenticationToken notUsernamePasswordToken = new NotUsernamePasswordToken();
+        assertFalse(AuthenticationTokenUtils.isUsernamePasswordToken(notUsernamePasswordToken));
+
+        // positive test case
+        final AuthenticationToken positiveUsernamePasswordToken = new UsernamePasswordToken();
+        assertTrue(AuthenticationTokenUtils.isUsernamePasswordToken(positiveUsernamePasswordToken));
+
+    }
+
+    @Test
+    public void testExtractUsername() throws Exception {
+        // null test
+        final AuthenticationToken nullAuthenticationToken = null;
+        assertEquals(AuthenticationTokenUtils.DEFAULT_TOKEN,
+                AuthenticationTokenUtils.extractUsername(nullAuthenticationToken));
+
+        // non-UsernamePasswordToken test
+        final AuthenticationToken notUsernamePasswordToken = new NotUsernamePasswordToken();
+        assertEquals(AuthenticationTokenUtils.DEFAULT_TOKEN,
+                AuthenticationTokenUtils.extractUsername(notUsernamePasswordToken));
+
+        // null username test
+        final UsernamePasswordToken nullUsername = new UsernamePasswordToken();
+        nullUsername.setUsername(null);
+        assertEquals(AuthenticationTokenUtils.DEFAULT_USERNAME,
+                AuthenticationTokenUtils.extractUsername(nullUsername));
+
+        // positive test
+        final UsernamePasswordToken positiveUsernamePasswordToken = new UsernamePasswordToken();
+        final String testUsername = "testUser1";
+        positiveUsernamePasswordToken.setUsername(testUsername);
+        assertEquals(testUsername, AuthenticationTokenUtils.extractUsername(positiveUsernamePasswordToken));
+    }
+
+    @Test
+    public void testExtractHostname() throws Exception {
+        // null test
+        final AuthenticationToken nullAuthenticationToken = null;
+        assertEquals(AuthenticationTokenUtils.DEFAULT_HOSTNAME,
+                AuthenticationTokenUtils.extractHostname(nullAuthenticationToken));
+
+        // non-UsernamePasswordToken test
+        final AuthenticationToken notUsernamePasswordToken = new NotUsernamePasswordToken();
+        assertEquals(AuthenticationTokenUtils.DEFAULT_HOSTNAME,
+                AuthenticationTokenUtils.extractHostname(notUsernamePasswordToken));
+
+        // null hostname test
+        final UsernamePasswordToken nullHostname = new UsernamePasswordToken();
+        nullHostname.setHost(null);
+        assertEquals(AuthenticationTokenUtils.DEFAULT_HOSTNAME,
+                AuthenticationTokenUtils.extractHostname(nullHostname));
+
+        // positive test
+        final UsernamePasswordToken positiveUsernamePasswordToken = new UsernamePasswordToken();
+        final String testUsername = "testHostname1";
+        positiveUsernamePasswordToken.setHost(testUsername);
+        assertEquals(testUsername, AuthenticationTokenUtils.extractHostname(positiveUsernamePasswordToken));
+    }
+
+    @Test
+    public void testGenerateUnsuccessfulAuthenticationMessage() throws Exception {
+        final UsernamePasswordToken unsuccessfulToken = new UsernamePasswordToken();
+        unsuccessfulToken.setUsername("unsuccessfulUser1");
+        unsuccessfulToken.setHost("unsuccessfulHost1");
+        assertEquals("Unsuccessful authentication attempt by unsuccessfulUser1 from unsuccessfulHost1",
+                AuthenticationTokenUtils.generateUnsuccessfulAuthenticationMessage(unsuccessfulToken));
+    }
+
+    @Test
+    public void testGenerateSuccessfulAuthenticationMessage() throws Exception {
+        final UsernamePasswordToken successfulToken = new UsernamePasswordToken();
+        successfulToken.setUsername("successfulUser1");
+        successfulToken.setHost("successfulHost1");
+        assertEquals("Successful authentication attempt by successfulUser1 from successfulHost1",
+                AuthenticationTokenUtils.generateSuccessfulAuthenticationMessage(successfulToken));
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmTest.java
new file mode 100644
index 00000000..22ce203f
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.junit.Test;
+
+/**
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class ODLJndiLdapRealmTest {
+
+    /**
+     * throw-away anonymous test class
+     */
+    class TestNamingEnumeration implements NamingEnumeration<SearchResult> {
+
+        /**
+         * state variable
+         */
+        boolean first = true;
+
+        /**
+         * returned the first time <code>next()</code> or
+         * <code>nextElement()</code> is called.
+         */
+        SearchResult searchResult = new SearchResult("testuser", null, new BasicAttributes(
+                "objectClass", "engineering"));
+
+        /**
+         * returns true the first time, then false for subsequent calls
+         */
+        @Override
+        public boolean hasMoreElements() {
+            return first;
+        }
+
+        /**
+         * returns <code>searchResult</code> then null for subsequent calls
+         */
+        @Override
+        public SearchResult nextElement() {
+            if (first) {
+                first = false;
+                return searchResult;
+            }
+            return null;
+        }
+
+        /**
+         * does nothing because close() doesn't require any special behavior
+         */
+        @Override
+        public void close() throws NamingException {
+        }
+
+        /**
+         * returns true the first time, then false for subsequent calls
+         */
+        @Override
+        public boolean hasMore() throws NamingException {
+            return first;
+        }
+
+        /**
+         * returns <code>searchResult</code> then null for subsequent calls
+         */
+        @Override
+        public SearchResult next() throws NamingException {
+            if (first) {
+                first = false;
+                return searchResult;
+            }
+            return null;
+        }
+    };
+
+    /**
+     * throw away test class
+     *
+     * @author ryan
+     */
+    class TestPrincipalCollection implements PrincipalCollection {
+        /**
+     *
+     */
+        private static final long serialVersionUID = -1236759619455574475L;
+
+        Vector<String> collection = new Vector<String>();
+
+        public TestPrincipalCollection(String element) {
+            collection.add(element);
+        }
+
+        @Override
+        public Iterator<String> iterator() {
+            return collection.iterator();
+        }
+
+        @Override
+        public List<String> asList() {
+            return collection;
+        }
+
+        @Override
+        public Set<String> asSet() {
+            HashSet<String> set = new HashSet<String>();
+            set.addAll(collection);
+            return set;
+        }
+
+        @Override
+        public <T> Collection<T> byType(Class<T> arg0) {
+            return null;
+        }
+
+        @Override
+        public Collection<String> fromRealm(String arg0) {
+            return collection;
+        }
+
+        @Override
+        public Object getPrimaryPrincipal() {
+            return collection.firstElement();
+        }
+
+        @Override
+        public Set<String> getRealmNames() {
+            return null;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return collection.isEmpty();
+        }
+
+        @Override
+        public <T> T oneByType(Class<T> arg0) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    };
+
+    @Test
+    public void testGetUsernameAuthenticationToken() {
+        AuthenticationToken authenticationToken = null;
+        assertNull(ODLJndiLdapRealm.getUsername(authenticationToken));
+        AuthenticationToken validAuthenticationToken = new UsernamePasswordToken("test",
+                "testpassword");
+        assertEquals("test", ODLJndiLdapRealm.getUsername(validAuthenticationToken));
+    }
+
+    @Test
+    public void testGetUsernamePrincipalCollection() {
+        PrincipalCollection pc = null;
+        assertNull(new ODLJndiLdapRealm().getUsername(pc));
+        TestPrincipalCollection tpc = new TestPrincipalCollection("testuser");
+        String username = new ODLJndiLdapRealm().getUsername(tpc);
+        assertEquals("testuser", username);
+    }
+
+    @Test
+    public void testQueryForAuthorizationInfoPrincipalCollectionLdapContextFactory()
+            throws NamingException {
+        LdapContext ldapContext = mock(LdapContext.class);
+        // emulates an ldap search and returns the mocked up test class
+        when(
+                ldapContext.search((String) any(), (String) any(),
+                        (SearchControls) any())).thenReturn(new TestNamingEnumeration());
+        LdapContextFactory ldapContextFactory = mock(LdapContextFactory.class);
+        when(ldapContextFactory.getSystemLdapContext()).thenReturn(ldapContext);
+        AuthorizationInfo authorizationInfo = new ODLJndiLdapRealm().queryForAuthorizationInfo(
+                new TestPrincipalCollection("testuser"), ldapContextFactory);
+        assertNotNull(authorizationInfo);
+        assertFalse(authorizationInfo.getRoles().isEmpty());
+        assertTrue(authorizationInfo.getRoles().contains("engineering"));
+    }
+
+    @Test
+    public void testBuildAuthorizationInfo() {
+        assertNull(ODLJndiLdapRealm.buildAuthorizationInfo(null));
+        Set<String> roleNames = new HashSet<String>();
+        roleNames.add("engineering");
+        AuthorizationInfo authorizationInfo = ODLJndiLdapRealm.buildAuthorizationInfo(roleNames);
+        assertNotNull(authorizationInfo);
+        assertFalse(authorizationInfo.getRoles().isEmpty());
+        assertTrue(authorizationInfo.getRoles().contains("engineering"));
+    }
+
+    @Test
+    public void testGetRoleNamesForUser() throws NamingException {
+        ODLJndiLdapRealm ldapRealm = new ODLJndiLdapRealm();
+        LdapContext ldapContext = mock(LdapContext.class);
+
+        // emulates an ldap search and returns the mocked up test class
+        when(
+                ldapContext.search((String) any(), (String) any(),
+                        (SearchControls) any())).thenReturn(new TestNamingEnumeration());
+
+        // extracts the roles for "testuser" and ensures engineering is returned
+        Set<String> roles = ldapRealm.getRoleNamesForUser("testuser", ldapContext);
+        assertFalse(roles.isEmpty());
+        assertTrue(roles.iterator().next().equals("engineering"));
+    }
+
+    @Test
+    public void testCreateSearchControls() {
+        SearchControls searchControls = ODLJndiLdapRealm.createSearchControls();
+        assertNotNull(searchControls);
+        int expectedSearchScope = SearchControls.SUBTREE_SCOPE;
+        int actualSearchScope = searchControls.getSearchScope();
+        assertEquals(expectedSearchScope, actualSearchScope);
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealmTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealmTest.java
new file mode 100644
index 00000000..f2eb92b5
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/TokenAuthRealmTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.realm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Lists;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.junit.Test;
+
+/**
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ *
+ */
+public class TokenAuthRealmTest extends TokenAuthRealm {
+
+    private TokenAuthRealm testRealm = new TokenAuthRealm();
+
+    @Test
+    public void testTokenAuthRealm() {
+        assertEquals("TokenAuthRealm", testRealm.getName());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testDoGetAuthorizationInfoPrincipalCollectionNullCacheToken() {
+        testRealm.doGetAuthorizationInfo(null);
+    }
+
+    @Test
+    public void testGetUsernamePasswordDomainString() {
+        final String username = "user";
+        final String password = "password";
+        final String domain = "domain";
+        final String expectedUsernamePasswordString = "user:password:domain";
+        assertEquals(expectedUsernamePasswordString, getUsernamePasswordDomainString(username, password, domain));
+    }
+
+    @Test
+    public void testGetEncodedToken() {
+        final String stringToEncode = "admin1:admin1";
+        final byte[] bytesToEncode = stringToEncode.getBytes();
+        final String expectedToken = org.apache.shiro.codec.Base64.encodeToString(bytesToEncode);
+        assertEquals(expectedToken, getEncodedToken(stringToEncode));
+    }
+
+    @Test
+    public void testGetTokenAuthHeader() {
+        final String encodedCredentials = getEncodedToken(getUsernamePasswordDomainString("user1",
+                "password", "sdn"));
+        final String expectedTokenAuthHeader = "Basic " + encodedCredentials;
+        assertEquals(expectedTokenAuthHeader, getTokenAuthHeader(encodedCredentials));
+    }
+
+    @Test
+    public void testFormHeadersWithToken() {
+        final String authHeader = getEncodedToken(getTokenAuthHeader(getUsernamePasswordDomainString(
+                "user1", "password", "sdn")));
+        final Map<String, List<String>> expectedHeaders = new HashMap<String, List<String>>();
+        expectedHeaders.put("Authorization", Lists.newArrayList(authHeader));
+        final Map<String, List<String>> actualHeaders = formHeadersWithToken(authHeader);
+        List<String> value;
+        for (String key : expectedHeaders.keySet()) {
+            value = expectedHeaders.get(key);
+            assertTrue(actualHeaders.get(key).equals(value));
+        }
+    }
+
+    @Test
+    public void testFormHeaders() {
+        final String username = "basicUser";
+        final String password = "basicPassword";
+        final String domain = "basicDomain";
+        final String authHeader = getTokenAuthHeader(getEncodedToken(getUsernamePasswordDomainString(
+                username, password, domain)));
+        final Map<String, List<String>> expectedHeaders = new HashMap<String, List<String>>();
+        expectedHeaders.put("Authorization", Lists.newArrayList(authHeader));
+        final Map<String, List<String>> actualHeaders = formHeaders(username, password, domain);
+        List<String> value;
+        for (String key : expectedHeaders.keySet()) {
+            value = expectedHeaders.get(key);
+            assertTrue(actualHeaders.get(key).equals(value));
+        }
+    }
+
+    @Test
+    public void testIsTokenAuthAvailable() {
+        assertFalse(testRealm.isTokenAuthAvailable());
+    }
+
+    @Test(expected = org.apache.shiro.authc.AuthenticationException.class)
+    public void testDoGetAuthenticationInfoAuthenticationToken() {
+        testRealm.doGetAuthenticationInfo(null);
+    }
+
+    @Test
+    public void testExtractUsernameNullUsername() {
+        AuthenticationToken at = mock(AuthenticationToken.class);
+        when(at.getPrincipal()).thenReturn(null);
+        assertNull(extractUsername(at));
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void testExtractPasswordNullPassword() {
+        AuthenticationToken at = mock(AuthenticationToken.class);
+        when(at.getPrincipal()).thenReturn("username");
+        when(at.getCredentials()).thenReturn(null);
+        extractPassword(at);
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void testExtractUsernameBadUsernameClass() {
+        AuthenticationToken at = mock(AuthenticationToken.class);
+        when(at.getPrincipal()).thenReturn(new Integer(1));
+        extractUsername(at);
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void testExtractPasswordBadPasswordClass() {
+        AuthenticationToken at = mock(AuthenticationToken.class);
+        when(at.getPrincipal()).thenReturn("username");
+        when(at.getCredentials()).thenReturn(new Integer(1));
+        extractPassword(at);
+    }
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironmentTest.java b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironmentTest.java
new file mode 100644
index 00000000..141d0ce5
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironmentTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro.web.env;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.config.Ini.Section;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class KarafIniWebEnvironmentTest {
+    private static File iniFile;
+
+    @BeforeClass
+    public static void setup() throws IOException {
+        iniFile = createShiroIniFile();
+        assertTrue(iniFile.exists());
+    }
+
+    @AfterClass
+    public static void teardown() {
+        iniFile.delete();
+    }
+
+    private static String createFakeShiroIniContents() {
+        return "[users]\n" + "admin=admin, ROLE_ADMIN \n" + "[roles]\n" + "ROLE_ADMIN = *\n"
+                + "[urls]\n" + "/** = authcBasic";
+    }
+
+    private static File createShiroIniFile() throws IOException {
+        File shiroIni = File.createTempFile("shiro", "ini");
+        FileWriter writer = new FileWriter(shiroIni);
+        writer.write(createFakeShiroIniContents());
+        writer.flush();
+        writer.close();
+        return shiroIni;
+    }
+
+    @Test
+    public void testCreateShiroIni() throws IOException {
+        Ini ini = KarafIniWebEnvironment.createShiroIni(iniFile.getAbsolutePath());
+        assertNotNull(ini);
+        assertNotNull(ini.getSection("users"));
+        assertNotNull(ini.getSection("roles"));
+        assertNotNull(ini.getSection("urls"));
+        Section usersSection = ini.getSection("users");
+        assertTrue(usersSection.containsKey("admin"));
+        assertTrue(usersSection.get("admin").contains("admin"));
+        assertTrue(usersSection.get("admin").contains("ROLE_ADMIN"));
+    }
+
+    @Test
+    public void testCreateFileBasedIniPath() {
+        String testPath = "/shiro.ini";
+        String expectedFileBasedIniPath = KarafIniWebEnvironment.SHIRO_FILE_PREFIX + testPath;
+        String actualFileBasedIniPath = KarafIniWebEnvironment.createFileBasedIniPath(testPath);
+        assertEquals(expectedFileBasedIniPath, actualFileBasedIniPath);
+    }
+
+}
diff --git a/odl-aaa-moon/aaa/aaa-shiro/src/test/resources/logback-test.xml b/odl-aaa-moon/aaa/aaa-shiro/src/test/resources/logback-test.xml
new file mode 100644
index 00000000..68ceeabc
--- /dev/null
+++ b/odl-aaa-moon/aaa/aaa-shiro/src/test/resources/logback-test.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <appender name="TEST-APPENDER" class="org.opendaylight.aaa.shiro.TestAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <Pattern>
+                %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
+            </Pattern>
+        </layout>
+    </appender>
+
+    <logger name="org.opendaylight.aaa.shiro.authc" level="debug"
+        additivity="false">
+        <appender-ref ref="TEST-APPENDER" />
+    </logger>
+
+    <root level="debug">
+        <appender-ref ref="TEST-APPENDER" />
+    </root>
+
+</configuration>
diff --git a/odl-aaa-moon/aaa/artifacts/pom.xml b/odl-aaa-moon/aaa/artifacts/pom.xml
new file mode 100644
index 00000000..3f811507
--- /dev/null
+++ b/odl-aaa-moon/aaa/artifacts/pom.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Robert Varga. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>org.opendaylight.odlparent</groupId>
+      <artifactId>odlparent-lite</artifactId>
+      <version>1.6.2-Beryllium-SR2</version>
+      <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-artifacts</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>pom</packaging>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn</artifactId>
+                <version>${project.version}</version>
+                <type>cfg</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-basic</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-federation</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-federation</artifactId>
+                <version>${project.version}</version>
+                <type>cfg</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-keystone</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-mdsal-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-mdsal-store-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-mdsal-config</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-shiro</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-shiro-act</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-sssd</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-store</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-store</artifactId>
+                <version>${project.version}</version>
+                <type>cfg</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-sts</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authz-model</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authz-service</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>authz-service-config</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>authz-restconf-config</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>config</classifier>
+            </dependency>
+
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-credential-store-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-idmlight</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-idmlight</artifactId>
+                <version>${project.version}</version>
+                <type>xml</type>
+                <classifier>config</classifier>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-authn-idpmapping</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-aaa-api</artifactId>
+                <version>${project.version}</version>
+                <classifier>features</classifier>
+                <type>xml</type>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-aaa-authn</artifactId>
+                <version>${project.version}</version>
+                <classifier>features</classifier>
+                <type>xml</type>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-aaa-authz</artifactId>
+                <version>${project.version}</version>
+                <classifier>features</classifier>
+                <type>xml</type>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-h2-store</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>aaa-h2-store</artifactId>
+                <version>${project.version}</version>
+                <classifier>config</classifier>
+                <type>xml</type>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-aaa-shiro</artifactId>
+                <version>${project.version}</version>
+                <classifier>features</classifier>
+                <type>xml</type>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>features-aaa</artifactId>
+                <version>${project.version}</version>
+                <classifier>features</classifier>
+                <type>xml</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+  <properties>
+    <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
+  </properties>
+
+  <distributionManagement>
+    <!-- OpenDayLight Released artifact -->
+    <repository>
+      <id>opendaylight-release</id>
+      <url>${nexusproxy}/repositories/opendaylight.release/</url>
+    </repository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <snapshotRepository>
+      <id>opendaylight-snapshot</id>
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+    </snapshotRepository>
+  </distributionManagement>
+</project>
diff --git a/odl-aaa-moon/aaa/commons/docs/AuthNusecases.vsd b/odl-aaa-moon/aaa/commons/docs/AuthNusecases.vsd
new file mode 100644
index 00000000..ddd59fb3
Binary files /dev/null and b/odl-aaa-moon/aaa/commons/docs/AuthNusecases.vsd differ
diff --git a/odl-aaa-moon/aaa/commons/docs/direct_authn.png b/odl-aaa-moon/aaa/commons/docs/direct_authn.png
new file mode 100644
index 00000000..f63f038e
Binary files /dev/null and b/odl-aaa-moon/aaa/commons/docs/direct_authn.png differ
diff --git a/odl-aaa-moon/aaa/commons/docs/federated_authn1.png b/odl-aaa-moon/aaa/commons/docs/federated_authn1.png
new file mode 100644
index 00000000..199f6f4d
Binary files /dev/null and b/odl-aaa-moon/aaa/commons/docs/federated_authn1.png differ
diff --git a/odl-aaa-moon/aaa/commons/docs/federated_authn2.png b/odl-aaa-moon/aaa/commons/docs/federated_authn2.png
new file mode 100644
index 00000000..b71e9aa7
Binary files /dev/null and b/odl-aaa-moon/aaa/commons/docs/federated_authn2.png differ
diff --git a/odl-aaa-moon/aaa/commons/federation/README b/odl-aaa-moon/aaa/commons/federation/README
new file mode 100644
index 00000000..dd9cdbf0
--- /dev/null
+++ b/odl-aaa-moon/aaa/commons/federation/README
@@ -0,0 +1,271 @@
+README
+===============================================================================
+Federated AAA is deployed using several config files.  This file explains a
+simple scenario utilizing two servers:
+a) ipa.example.com
+   - Runs the IPA Server Software
+b) odl.example.com
+   - Runs the IPA Client Software
+   - Runs an Apache proxy frontend (AuthN through mod_lookup_identity.so)
+   - Runs ODL
+
+This setup for this scenario is illustrated in Figure 1 below:
+
+      -----------------------
+     | odl.example.com       |
+     | (Fedora 20 Linux)     |
+     |                       |
+     |  -------------------  |
+     | | ODL Jetty Server  | |
+     | | (Port 8181 & 8383)| |
+     |  -------------------  |
+     |   ^              .    |
+     |   .   (Apache    .    |  SSSD Requests/Responses
+     |   .    Reverse   .    |           /
+     |   .     Proxy)   .    |          /
+     |   .              v    |         /
+     |  -------------------  |        |          ------------------
+     | | Apache            |<|..................| ipa.example.com  |
+     | | (Port 80)         |.|.................>| (FreeIPA         |
+     |  -------------------  |                  |   Kerberos And   |
+     | ______________________|                  |     LDAP)        |
+                                                 ------------------
+Figure 1: Shows the setup for a simple Federated AAA use case utilizing
+FreeIPA as an identity provider.
+
+
+These instructions were written for Fedora 20, since SSSD is unique to RHEL based
+distributions.  SSSD is NOT a requirement for Federation though;  you can use
+any supported linux flavor.  At this time, SSSD is the only Filter available
+with regards to capturing IdP attributes that can be used in making advanced mapping
+decisions (such as IdP group membership information).
+
+
+
+1) Install FreeIPA Server on ipa.example.com.  This is achieved through running:
+# yum install freeipa-server bind bind-dyndb-ldap
+# ipa-server-intall
+
+
+
+2) Add a FreeIPA user called testuser:
+$ kinit admin@EXAMPLE.COM
+$ ipa group-add odl_users --desc "ODL Users"
+$ ipa group-add odl_admin --desc "ODL Admin"
+$ ipa user-add testuser --first Test --last USER --email test.user@example.com
+$ ipa group-add-member odl_users --user testuser
+$ ipa group-add-member odl_admin --user testuser
+
+
+
+3) Install FreeIPA Client on odl.example.com.  This is achieved through running:
+# yum install freeipa-client
+# ipa-client-install
+
+
+
+4) Set up Client keytab for HTTP access on odl.example.com:
+# ipa-getkeytab -p HTTP/odl.brcd-sssd-tb.com@BRCD-SSSD-TB.COM \
+    -s freeipa.brcd-sssd-tb.com -k /etc/krb5.keytab
+# chmod 644 /etc/krb5.keytab
+NOTE: The second command allows Apache to read the keytab.  There are more
+secure methods to support such access through SELINUX, but they are outside
+the scope of this tutorial.
+
+
+
+5) Install Apache on odl.example.com.  This is achieved through running:
+# yum install httpd
+
+
+
+6) Create an Apache application to broker federation between ODL and FreeIPA.
+Create the following file on odl.example.com:
+
+[root@odl /]# cat /etc/httpd/conf.d/my_app.conf
+<Location "/*">
+  AuthType Kerberos
+  AuthName "Kerberos Login"
+  KrbMethodNegotiate On
+  KrbMethodK5Passwd on
+  KrbAuthRealms EXAMPLE.COM
+  Krb5KeyTab /etc/krb5.keytab
+  require valid-user
+</Location>
+
+
+<LocationMatch "/*">
+
+ RequestHeader set X-SSSD-REMOTE_USER expr=%{REMOTE_USER}
+ RequestHeader set X-SSSD-AUTH_TYPE expr=%{AUTH_TYPE}
+ RequestHeader set X-SSSD-REMOTE_HOST expr=%{REMOTE_HOST}
+ RequestHeader set X-SSSD-REMOTE_ADDR expr=%{REMOTE_ADDR}
+ LookupUserAttr mail REMOTE_USER_EMAIL
+ RequestHeader set X-SSSD-REMOTE_USER_EMAIL %{REMOTE_USER_EMAIL}e
+ LookupUserAttr givenname REMOTE_USER_FIRSTNAME
+ RequestHeader set X-SSSD-REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e
+ LookupUserAttr sn REMOTE_USER_LASTNAME
+ RequestHeader set X-SSSD-REMOTE_USER_LASTNAME %{REMOTE_USER_LASTNAME}e
+ LookupUserGroups REMOTE_USER_GROUPS ":"
+ RequestHeader set X-SSSD-REMOTE_USER_GROUPS %{REMOTE_USER_GROUPS}e
+</LocationMatch>
+
+ProxyPass / http://localhost:8383/
+ProxyPassReverse / http://localhost:8383/
+
+
+
+7) Install the ODL distribution in the /opt folder on odl.example.com.
+
+
+
+8) Add a federation connector to the jetty server hosting ODL on
+odl.example.com:
+
+[user@odl distribution]$ cat etc/jetty.xml
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//
+DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+
+<Configure class="org.eclipse.jetty.server.Server">
+
+    <!-- =========================================================== -->
+    <!-- Set connectors -->
+    <!-- =========================================================== -->
+    <!-- One of each type! -->
+    <!-- =========================================================== -->
+
+    <!-- Use this connector for many frequently idle connections and for
+        threadless continuations. -->
+    <Call name="addConnector">
+        <Arg>
+            <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+                <Set name="host">
+                    <Property name="jetty.host" />
+                </Set>
+                <Set name="port">
+                    <Property name="jetty.port" default="8181" />
+                </Set>
+                <Set name="maxIdleTime">300000</Set>
+                <Set name="Acceptors">2</Set>
+                <Set name="statsOn">false</Set>
+                <Set name="confidentialPort">8443</Set>
+                <Set name="lowResourcesConnections">20000</Set>
+                <Set name="lowResourcesMaxIdleTime">5000</Set>
+            </New>
+        </Arg>
+    </Call>
+    <!-- Trusted Authentication Federation proxy connection -->
+    <Call name="addConnector">
+     <Arg>
+         <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+           <Set name="host">127.0.0.1</Set>
+     <Set name="port">8383</Set>
+     <Set name="maxIdleTime">300000</Set>
+     <Set name="Acceptors">2</Set>
+     <Set name="statsOn">false</Set>
+     <Set name="confidentialPort">8445</Set>
+     <Set name="name">federationConn</Set>
+     <Set name="lowResourcesConnections">20000</Set>
+     <Set name="lowResourcesMaxIdleTime">5000</Set>
+    </New>
+   </Arg>
+ </Call>
+    <!-- =========================================================== -->
+    <!-- Configure Authentication Realms -->
+    <!-- Realms may be configured for the entire server here, or -->
+    <!-- they can be configured for a specific web app in a context -->
+    <!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
+    <!-- example). -->
+    <!-- =========================================================== -->
+    <Call name="addBean">
+        <Arg>
+            <New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
+                <Set name="name">karaf</Set>
+                <Set name="loginModuleName">karaf</Set>
+                <Set name="roleClassNames">
+                    <Array type="java.lang.String">
+                        <Item>org.apache.karaf.jaas.boot.principal.RolePrincipal
+                        </Item>
+                    </Array>
+                </Set>
+            </New>
+        </Arg>
+    </Call>
+    <Call name="addBean">
+        <Arg>
+            <New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
+                <Set name="name">default</Set>
+                <Set name="loginModuleName">karaf</Set>
+                <Set name="roleClassNames">
+                    <Array type="java.lang.String">
+                        <Item>org.apache.karaf.jaas.boot.principal.RolePrincipal
+                        </Item>
+                    </Array>
+                </Set>
+            </New>
+        </Arg>
+    </Call>
+</Configure>
+
+
+
+9) Add the idp_mapping rules file on odl.example.com
+
+[user@odl distribution]$ cat etc/idp_mapping_rules.json
+[
+   {
+      "mapping":{
+         "ClientId":"1",
+         "UserId":"1",
+         "User":"admin",
+         "Domain":"BRCD-SSSD-TB.COM",
+         "roles":"$roles"
+      },
+      "statement_blocks":[
+         [
+            [
+               "set",
+               "$groups",
+               [
+
+               ]
+            ],
+            [
+               "set",
+               "$roles",
+               [
+                  "admin",
+                  "user"
+               ]
+            ]
+         ]
+      ]
+   }
+]
+
+NOTE:  This is a very basic mapping example in which all federated users are
+mapped into the default "admin" account.
+
+
+
+10) Start ODL and install the following features on odl.example.com:
+# bin/karaf
+karaf> feature:install odl-aaa-authn-sssd-no-cluster odl-restconf
+
+
+
+11) Get a refresh_token on odl.example.com through Apache proxy port (80 forwarded to 8383):
+[user@odl distribution]$ kinit testuser
+[user@odl distribution]$ curl -s --negotiate -u : -X POST http://odl.example.com/oauth2/federation/
+
+
+
+12) Obtain an access_token on odl.example.com through normal port (8181):
+[user@odl distribution]$ curl -s -d 'grant_type=refresh_token&refresh_token=<PUT RESULT FROM ABOVE STEP HERE>&scope=sdn' http://odl.example.com:8181/oauth2/token
+
+
+
+13) Use the access_token to make authenticated rest calls from odl.example.com through normal port (8181):
+[user@odl distribution]$ curl -s -H 'Authorization: Bearer <PUT RESULT FROM ABOVE STEP HERE>' http://odl.brcd-sssd-tb.com:8181/restconf/streams/
+
diff --git a/odl-aaa-moon/aaa/commons/federation/idp_mapping_rules.json.example b/odl-aaa-moon/aaa/commons/federation/idp_mapping_rules.json.example
new file mode 100644
index 00000000..98bacb0a
--- /dev/null
+++ b/odl-aaa-moon/aaa/commons/federation/idp_mapping_rules.json.example
@@ -0,0 +1,30 @@
+[
+   {
+      "mapping":{
+         "ClientId":"1",
+         "UserId":"1",
+         "User":"admin",
+         "Domain":"BRCD-SSSD-TB.COM",
+         "roles":"$roles"
+      },
+      "statement_blocks":[
+         [
+            [
+               "set",
+               "$groups",
+               [
+
+               ]
+            ],
+            [
+               "set",
+               "$roles",
+               [
+                  "admin",
+                  "user"
+               ]
+            ]
+         ]
+      ]
+   }
+]
diff --git a/odl-aaa-moon/aaa/commons/federation/jetty.xml.example b/odl-aaa-moon/aaa/commons/federation/jetty.xml.example
new file mode 100644
index 00000000..c4cb2a7d
--- /dev/null
+++ b/odl-aaa-moon/aaa/commons/federation/jetty.xml.example
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//
+DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+
+<Configure class="org.eclipse.jetty.server.Server">
+
+    <!-- =========================================================== -->
+    <!-- Set connectors -->
+    <!-- =========================================================== -->
+    <!-- One of each type! -->
+    <!-- =========================================================== -->
+
+    <!-- Use this connector for many frequently idle connections and for
+        threadless continuations. -->
+    <Call name="addConnector">
+        <Arg>
+            <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+                <Set name="host">
+                    <Property name="jetty.host" />
+                </Set>
+                <Set name="port">
+                    <Property name="jetty.port" default="8181" />
+                </Set>
+                <Set name="maxIdleTime">300000</Set>
+                <Set name="Acceptors">2</Set>
+                <Set name="statsOn">false</Set>
+                <Set name="confidentialPort">8443</Set>
+                <Set name="lowResourcesConnections">20000</Set>
+                <Set name="lowResourcesMaxIdleTime">5000</Set>
+            </New>
+        </Arg>
+    </Call>
+    <!-- Trusted Authentication Federation proxy connection -->
+    <Call name="addConnector">
+     <Arg>
+         <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+           <Set name="host">127.0.0.1</Set>
+     <Set name="port">8383</Set>
+     <Set name="maxIdleTime">300000</Set>
+     <Set name="Acceptors">2</Set>
+     <Set name="statsOn">false</Set>
+     <Set name="confidentialPort">8445</Set>
+     <Set name="name">federationConn</Set>
+     <Set name="lowResourcesConnections">20000</Set>
+     <Set name="lowResourcesMaxIdleTime">5000</Set>
+    </New>
+   </Arg>
+ </Call>
+    <!-- =========================================================== -->
+    <!-- Configure Authentication Realms -->
+    <!-- Realms may be configured for the entire server here, or -->
+    <!-- they can be configured for a specific web app in a context -->
+    <!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
+    <!-- example). -->
+    <!-- =========================================================== -->
+    <Call name="addBean">
+        <Arg>
+            <New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
+                <Set name="name">karaf</Set>
+                <Set name="loginModuleName">karaf</Set>
+                <Set name="roleClassNames">
+                    <Array type="java.lang.String">
+                        <Item>org.apache.karaf.jaas.boot.principal.RolePrincipal
+                        </Item>
+                    </Array>
+                </Set>
+            </New>
+        </Arg>
+    </Call>
+    <Call name="addBean">
+        <Arg>
+            <New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
+                <Set name="name">default</Set>
+                <Set name="loginModuleName">karaf</Set>
+                <Set name="roleClassNames">
+                    <Array type="java.lang.String">
+                        <Item>org.apache.karaf.jaas.boot.principal.RolePrincipal
+                        </Item>
+                    </Array>
+                </Set>
+            </New>
+        </Arg>
+    </Call>
+</Configure>
+
diff --git a/odl-aaa-moon/aaa/commons/federation/my_app.conf.example b/odl-aaa-moon/aaa/commons/federation/my_app.conf.example
new file mode 100644
index 00000000..71c8ad87
--- /dev/null
+++ b/odl-aaa-moon/aaa/commons/federation/my_app.conf.example
@@ -0,0 +1,31 @@
+LoadModule lookup_identity_module modules/mod_lookup_identity.so
+
+<Location "/*">
+  AuthType Kerberos
+  AuthName "Kerberos Login"
+  KrbMethodNegotiate On
+  KrbMethodK5Passwd on
+  KrbAuthRealms EXAMPLE.COM
+  Krb5KeyTab /etc/krb5.keytab
+  require valid-user
+</Location>
+
+
+<LocationMatch "/*">
+
+ RequestHeader set X-SSSD-REMOTE_USER expr=%{REMOTE_USER}
+ RequestHeader set X-SSSD-AUTH_TYPE expr=%{AUTH_TYPE}
+ RequestHeader set X-SSSD-REMOTE_HOST expr=%{REMOTE_HOST}
+ RequestHeader set X-SSSD-REMOTE_ADDR expr=%{REMOTE_ADDR}
+ LookupUserAttr mail REMOTE_USER_EMAIL
+ RequestHeader set X-SSSD-REMOTE_USER_EMAIL %{REMOTE_USER_EMAIL}e
+ LookupUserAttr givenname REMOTE_USER_FIRSTNAME
+ RequestHeader set X-SSSD-REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e
+ LookupUserAttr sn REMOTE_USER_LASTNAME
+ RequestHeader set X-SSSD-REMOTE_USER_LASTNAME %{REMOTE_USER_LASTNAME}e
+ LookupUserGroups REMOTE_USER_GROUPS ":"
+ RequestHeader set X-SSSD-REMOTE_USER_GROUPS %{REMOTE_USER_GROUPS}e
+</LocationMatch>
+
+ProxyPass / http://localhost:8383/
+ProxyPassReverse / http://localhost:8383/
diff --git a/odl-aaa-moon/aaa/commons/postman_examples/AAA_AuthZ_MDSAL.json.postman_collection b/odl-aaa-moon/aaa/commons/postman_examples/AAA_AuthZ_MDSAL.json.postman_collection
new file mode 100644
index 00000000..15193a70
--- /dev/null
+++ b/odl-aaa-moon/aaa/commons/postman_examples/AAA_AuthZ_MDSAL.json.postman_collection
@@ -0,0 +1,77 @@
+{
+	"id": "273974a1-2df8-b0a6-57f9-1397cd1628d7",
+	"name": "AAA AuthZ MDSAL",
+	"description": "This Postman collection contains some of the common operations that are necessary to \"provision\" authorization services on top of ODL.",
+	"order": [
+		"7959a1f4-703a-417a-9d4c-70ab56c0e57f",
+		"262c9b05-04a6-8dfa-5eb3-c9f9f90b3c4a",
+		"4df58109-fd50-dbdf-b982-7e59d3475544"
+	],
+	"folders": [],
+	"timestamp": 1439405060911,
+	"owner": 0,
+	"remoteLink": "",
+	"public": false,
+	"requests": [
+		{
+			"id": "262c9b05-04a6-8dfa-5eb3-c9f9f90b3c4a",
+			"headers": "Authorization: Basic YWRtaW46YWRtaW4=\n",
+			"url": "http://localhost:8181/restconf/config/authorization-schema:simple-authorization/policies/RestConfService/",
+			"pathVariables": {},
+			"preRequestScript": "",
+			"method": "GET",
+			"collectionId": "273974a1-2df8-b0a6-57f9-1397cd1628d7",
+			"data": [],
+			"dataMode": "raw",
+			"name": "Get configuration authorization schema with admin role",
+			"description": "",
+			"descriptionFormat": "html",
+			"time": 1439405954342,
+			"version": 2,
+			"responses": [],
+			"tests": "",
+			"currentHelper": "normal",
+			"helperAttributes": {},
+			"rawModeData": ""
+		},
+		{
+			"id": "4df58109-fd50-dbdf-b982-7e59d3475544",
+			"headers": "Authorization: Basic dXNlcjp1c2Vy\n",
+			"url": "http://localhost:8181/restconf/config/authorization-schema:simple-authorization/policies/RestConfService/",
+			"preRequestScript": "",
+			"pathVariables": {},
+			"method": "GET",
+			"data": [],
+			"dataMode": "params",
+			"version": 2,
+			"tests": "",
+			"currentHelper": "normal",
+			"helperAttributes": {},
+			"time": 1439406616859,
+			"name": "Get configuration authorization schema with user role",
+			"description": "",
+			"collectionId": "273974a1-2df8-b0a6-57f9-1397cd1628d7",
+			"responses": []
+		},
+		{
+			"id": "7959a1f4-703a-417a-9d4c-70ab56c0e57f",
+			"headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+			"url": "http://localhost:8181/restconf/config/authorization-schema:simple-authorization/policies/RestConfService/",
+			"preRequestScript": "",
+			"pathVariables": {},
+			"method": "PUT",
+			"data": [],
+			"dataMode": "raw",
+			"version": 2,
+			"tests": "",
+			"currentHelper": "normal",
+			"helperAttributes": {},
+			"time": 1439405844861,
+			"name": "Secure RestConfService for admin role",
+			"description": "",
+			"collectionId": "273974a1-2df8-b0a6-57f9-1397cd1628d7",
+			"responses": [],
+			"rawModeData": "{\n    \"policies\": {\n        \"resource\": \"*\",\n        \"service\":\"RestConfService\",\n        \"role\": \"admin\"\n    }\n}"
+		}
+	]
+}
\ No newline at end of file
diff --git a/odl-aaa-moon/aaa/distribution-karaf/pom.xml b/odl-aaa-moon/aaa/distribution-karaf/pom.xml
new file mode 100644
index 00000000..7f5c9287
--- /dev/null
+++ b/odl-aaa-moon/aaa/distribution-karaf/pom.xml
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.aaa</groupId>
+        <artifactId>aaa-parent</artifactId>
+        <version>0.3.2-Beryllium-SR2</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+
+    <artifactId>distribution-karaf</artifactId>
+    <packaging>pom</packaging>
+    <prerequisites>
+        <maven>3.0</maven>
+    </prerequisites>
+
+    <dependencies>
+        <!-- Basic Karaf dependencies -->
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>framework</artifactId>
+            <version>${karaf.version}</version>
+            <type>kar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>standard</artifactId>
+            <version>${karaf.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- ODL Branding -->
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>karaf.branding</artifactId>
+            <version>${karaf.branding.version}</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <!-- ODL Resources needed for karaf -->
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>opendaylight-karaf-resources</artifactId>
+            <version>${karaf.resources.version}</version>
+        </dependency>
+
+        <!-- Project local feautures -->
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa-api</artifactId>
+            <classifier>features</classifier>
+            <version>${project.version}</version>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa</artifactId>
+            <classifier>features</classifier>
+            <version>${project.version}</version>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa-authz</artifactId>
+            <classifier>features</classifier>
+            <version>${project.version}</version>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa-shiro</artifactId>
+            <classifier>features</classifier>
+            <version>${project.version}</version>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.felix</groupId>
+                                        <artifactId>maven-bundle-plugin</artifactId>
+                                        <versionRange>[0,)</versionRange>
+                                        <goals>
+                                            <goal>cleanVersions</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.maven.plugins</groupId>
+                                        <artifactId>maven-dependency-plugin</artifactId>
+                                        <versionRange>[0,)</versionRange>
+                                        <goals>
+                                            <goal>copy</goal>
+                                            <goal>unpack</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.karaf.tooling</groupId>
+                                        <artifactId>karaf-maven-plugin</artifactId>
+                                        <versionRange>[0,)</versionRange>
+                                        <goals>
+                                            <goal>commands-generate-help</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.fusesource.scalate</groupId>
+                                        <artifactId>maven-scalate-plugin</artifactId>
+                                        <versionRange>[0,)</versionRange>
+                                        <goals>
+                                            <goal>sitegen</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.servicemix.tooling</groupId>
+                                        <artifactId>depends-maven-plugin</artifactId>
+                                        <versionRange>[0,)</versionRange>
+                                        <goals>
+                                            <goal>generate-depends-file</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <bootFeatures>
+                        <feature>standard</feature>
+                        <!-- Optional TODO: Add entries here for the features
+                            you want in your local distro Note: odl-restconf is a separate feature from
+                            odl-mdsal-broker. If you want restconf, you need to list it here explicitely.
+                            Examples: <feature>odl-toaster</feature> <feature>odl-restconf</feature> -->
+                        <!-- Final TODO: Remove TODO Comments ;) -->
+                    </bootFeatures>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>process-resources</id>
+                        <goals>
+                            <goal>install-kars</goal>
+                        </goals>
+                        <phase>process-resources</phase>
+                    </execution>
+                    <execution>
+                        <id>package</id>
+                        <goals>
+                            <goal>instance-create-archive</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.6</version>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <phase>generate-resources</phase>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.opendaylight.controller</groupId>
+                                    <artifactId>karaf.branding</artifactId>
+                                    <version>${karaf.branding.version}</version>
+                                    <outputDirectory>target/assembly/lib</outputDirectory>
+                                    <destFileName>karaf.branding-${karaf.branding.version}.jar</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>unpack-karaf-resources</id>
+                        <goals>
+                            <goal>unpack-dependencies</goal>
+                        </goals>
+                        <phase>prepare-package</phase>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/assembly</outputDirectory>
+                            <groupId>org.opendaylight.controller</groupId>
+                            <includeArtifactIds>opendaylight-karaf-resources</includeArtifactIds>
+                            <excludes>META-INF\/**</excludes>
+                            <excludeTransitive>true</excludeTransitive>
+                            <ignorePermissions>false</ignorePermissions>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <tasks>
+                                <chmod perm="755">
+                                    <fileset
+                                        dir="${project.build.directory}/assembly/bin">
+                                        <include name="karaf" />
+                                        <include name="instance" />
+                                        <include name="start" />
+                                        <include name="stop" />
+                                        <include name="status" />
+                                        <include name="client" />
+                                        <include name="shell" />
+                                    </fileset>
+                                </chmod>
+                            </tasks>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+      <!-- DO NOT install or deploy the karaf artifact -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git.opendaylight.org/gerrit/gitweb?p=aaa.git;a=summary</url>
+    </scm>
+</project>
diff --git a/odl-aaa-moon/aaa/features/api/pom.xml b/odl-aaa-moon/aaa/features/api/pom.xml
new file mode 100644
index 00000000..80545866
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/api/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>features-parent</artifactId>
+        <version>1.6.2-Beryllium-SR2</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>features-aaa-api</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+        <mdsal.version>2.0.2-Beryllium-SR2</mdsal.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- This project -->
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-artifacts</artifactId>
+                <version>${project.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+
+            <!-- YANG tools -->
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yangtools-artifacts</artifactId>
+                <version>${yangtools.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-credential-store-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>features-yangtools</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>features-mdsal</artifactId>
+            <version>2.0.2-Beryllium-SR2</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+    </dependencies>
+
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git.opendaylight.org/gerrit/gitweb?p=aaa.git;a=summary</url>
+    </scm>
+</project>
diff --git a/odl-aaa-moon/aaa/features/api/src/main/features/features.xml b/odl-aaa-moon/aaa/features/api/src/main/features/features.xml
new file mode 100644
index 00000000..c526e174
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/api/src/main/features/features.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<features name="odl-aaa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features</repository>
+        <repository>mvn:org.opendaylight.mdsal/features-mdsal/{{VERSION}}/xml/features</repository>
+    <feature name='odl-aaa-api' description='OpenDaylight :: AAA :: APIs'
+        version='${project.version}'>
+        <bundle>mvn:com.sun.jersey/jersey-server/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-credential-store-api/{{VERSION}}</bundle>
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
+    </feature>
+</features>
diff --git a/odl-aaa-moon/aaa/features/authn/pom.xml b/odl-aaa-moon/aaa/features/authn/pom.xml
new file mode 100644
index 00000000..0df53fbd
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/authn/pom.xml
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2014-2015 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>features-parent</artifactId>
+        <version>1.6.2-Beryllium-SR2</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>features-aaa</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <config.version>0.4.2-Beryllium-SR2</config.version>
+        <mdsal.version>2.0.2-Beryllium-SR2</mdsal.version>
+        <controller.mdsal.version>1.3.2-Beryllium-SR2</controller.mdsal.version>
+        <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- This project -->
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-parent</artifactId>
+                <version>${project.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <!-- odl-aaa-authn -->
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+        </dependency>
+        <!-- jersey client for moon APIs calls -->
+        <dependency>
+           <groupId>com.sun.jersey</groupId>
+           <artifactId>jersey-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.metatype</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jta_1.1_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish</groupId>
+            <artifactId>javax.json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-json-org</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-json-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-jaxb-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa-api</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro-act</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-sts</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-basic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-idmlight</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-idmlight</artifactId>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-idmlight</artifactId>
+            <version>${project.version}</version>
+            <type>py</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-federation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-mdsal-config</artifactId>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+            <type>cfg</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-store</artifactId>
+            <type>cfg</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-federation</artifactId>
+            <type>cfg</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-h2-store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-h2-store</artifactId>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.enterprise</artifactId>
+            <version>4.2.0</version>
+        </dependency>
+
+        <!-- AuthN MD-SAL Cache dependencies -->
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-mdsal-store-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-mdsal-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>features-yangtools</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-mdsal</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-config</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-impl</artifactId>
+        </dependency>
+
+        <!-- odl-aaa-sssd -->
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-sssd</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-idpmapping</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-keystone</artifactId>
+        </dependency>
+    </dependencies>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git.opendaylight.org/gerrit/gitweb?p=aaa.git;a=summary</url>
+    </scm>
+</project>
diff --git a/odl-aaa-moon/aaa/features/authn/src/main/features/features.xml b/odl-aaa-moon/aaa/features/authn/src/main/features/features.xml
new file mode 100644
index 00000000..2796e467
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/authn/src/main/features/features.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2014-2015 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<features name="odl-aaa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.aaa/features-aaa-api/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-config/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.mdsal/features-mdsal/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
+
+    <feature name='odl-aaa-authn-no-cluster' description='OpenDaylight :: AAA :: Authentication - NO CLUSTER'
+             version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-api</feature>
+
+        <!-- MD-SAL -->
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
+        <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+        <feature version='${config.version}'>odl-config-core</feature>
+
+        <!-- REST -->
+        <feature>war</feature>
+        <bundle>mvn:com.sun.jersey/jersey-servlet/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-server/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
+
+        <!-- OSGi -->
+        <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/{{VERSION}}</bundle>
+
+        <!-- EhCache -->
+        <bundle>mvn:net.sf.ehcache/ehcache/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/{{VERSION}}</bundle>
+
+        <!-- OAuth -->
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.authzserver/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.resourceserver/{{VERSION}}</bundle>
+        <bundle>mvn:commons-codec/commons-codec/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.json/json/{{VERSION}}</bundle>
+
+        <!-- commons-lang -->
+        <bundle>wrap:mvn:org.apache.commons/commons-lang3/{{VERSION}}</bundle>
+
+        <!-- AuthN -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro-act/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-core/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-web/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-sts/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-store/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-basic/{{VERSION}}</bundle>
+        <bundle>mvn:com.google.guava/guava/{{VERSION}}</bundle>
+
+        <!--H2 Store -->
+        <bundle>mvn:org.osgi/org.osgi.enterprise/4.2.0</bundle>
+        <bundle>wrap:mvn:com.h2database/h2/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-h2-store/{{VERSION}}</bundle>
+        <configfile finalname="etc/opendaylight/karaf/08-aaa-h2-store-config.xml">mvn:org.opendaylight.aaa/aaa-h2-store/{{VERSION}}/xml/config</configfile>
+
+        <!-- IDMLight -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}</bundle>
+        <configfile finalname="etc/opendaylight/karaf/08-aaa-idmlight-config.xml">mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}/xml/config</configfile>
+        <configfile finalname="etc/idmtool">mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}/py/config</configfile>
+
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/{{VERSION}}</bundle>
+
+        <!-- Federation -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-idpmapping/{{VERSION}}</bundle>
+        <bundle>mvn:org.glassfish/javax.json/{{VERSION}}</bundle>
+
+        <configfile finalname="/etc/org.opendaylight.aaa.authn.cfg">mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}/cfg/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.tokens.cfg">mvn:org.opendaylight.aaa/aaa-authn-store/{{VERSION}}/cfg/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.federation.cfg">mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}/cfg/config</configfile>
+    </feature>
+
+    <feature name='odl-aaa-authn' description='OpenDaylight :: AAA :: Authentication - NO CLUSTER'
+             version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-api</feature>
+
+        <!-- MD-SAL -->
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
+        <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+        <feature version='${config.version}'>odl-config-core</feature>
+
+        <!-- REST -->
+        <feature>war</feature>
+        <bundle>mvn:com.sun.jersey/jersey-servlet/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-server/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
+
+        <!-- OSGi -->
+        <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/{{VERSION}}</bundle>
+
+        <!-- EhCache -->
+        <bundle>mvn:net.sf.ehcache/ehcache/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/{{VERSION}}</bundle>
+
+        <!-- OAuth -->
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.authzserver/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.resourceserver/{{VERSION}}</bundle>
+        <bundle>mvn:commons-codec/commons-codec/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.json/json/{{VERSION}}</bundle>
+
+        <!-- commons-lang -->
+        <bundle>wrap:mvn:org.apache.commons/commons-lang3/{{VERSION}}</bundle>
+
+        <!-- AuthN -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro-act/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-core/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-web/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-sts/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-store/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-basic/{{VERSION}}</bundle>
+        <bundle>mvn:com.google.guava/guava/{{VERSION}}</bundle>
+
+        <!--H2 Store -->
+        <bundle>mvn:org.osgi/org.osgi.enterprise/4.2.0</bundle>
+        <bundle>wrap:mvn:com.h2database/h2/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-h2-store/{{VERSION}}</bundle>
+        <configfile finalname="etc/opendaylight/karaf/08-aaa-h2-store-config.xml">mvn:org.opendaylight.aaa/aaa-h2-store/{{VERSION}}/xml/config</configfile>
+
+        <!-- IDMLight -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}</bundle>
+        <configfile finalname="etc/opendaylight/karaf/08-aaa-idmlight-config.xml">mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}/xml/config</configfile>
+        <configfile finalname="etc/idmtool">mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}/py/config</configfile>
+
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/{{VERSION}}</bundle>
+
+        <!-- Federation -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-idpmapping/{{VERSION}}</bundle>
+        <bundle>mvn:org.glassfish/javax.json/{{VERSION}}</bundle>
+
+        <configfile finalname="/etc/org.opendaylight.aaa.authn.cfg">mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}/cfg/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.tokens.cfg">mvn:org.opendaylight.aaa/aaa-authn-store/{{VERSION}}/cfg/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.federation.cfg">mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}/cfg/config</configfile>
+    </feature>
+
+    <feature name='odl-aaa-authn-mdsal-cluster' description='OpenDaylight :: AAA :: Authentication :: MD-SAL'
+             version='${project.version}'>
+
+        <!-- MD-SAL -->
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
+        <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+        <feature version='${config.version}'>odl-config-core</feature>
+
+
+        <!-- OSGi -->
+        <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/{{VERSION}}</bundle>
+
+        <!-- OAuth -->
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.authzserver/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.resourceserver/{{VERSION}}</bundle>
+        <bundle>mvn:commons-codec/commons-codec/1.8</bundle>
+        <bundle>wrap:mvn:org.json/json/{{VERSION}}</bundle>
+
+        <!-- AuthN -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro-act/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-core/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-web/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-sts/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-mdsal-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-mdsal-store-impl/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-basic/{{VERSION}}</bundle>
+        <bundle>mvn:com.google.guava/guava/{{VERSION}}</bundle>
+
+        <!-- IDMLight -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}</bundle>
+        <configfile finalname="etc/opendaylight/karaf/08-aaa-idmlight-config.xml">mvn:org.opendaylight.aaa/aaa-idmlight/{{VERSION}}/xml/config</configfile>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/{{VERSION}}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:com.h2database/h2/{{VERSION}}</bundle>
+
+        <!-- Federation -->
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-idpmapping/{{VERSION}}</bundle>
+        <bundle>mvn:org.glassfish/javax.json/1.0.4</bundle>
+
+        <!-- REST -->
+        <feature>war</feature>
+        <bundle>mvn:com.sun.jersey/jersey-servlet/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-server/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
+
+        <configfile finalname="etc/opendaylight/karaf/08-authn-config.xml">mvn:org.opendaylight.aaa/aaa-authn-mdsal-config/{{VERSION}}/xml/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.authn.cfg">mvn:org.opendaylight.aaa/aaa-authn/{{VERSION}}/cfg/config</configfile>
+        <configfile finalname="/etc/org.opendaylight.aaa.federation.cfg">mvn:org.opendaylight.aaa/aaa-authn-federation/{{VERSION}}/cfg/config</configfile>
+
+    </feature>
+
+    <feature name='odl-aaa-keystone-plugin' description='OpenDaylight :: AAA :: Keystone Plugin - NO CLUSTER'
+             version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-authn</feature>
+        <bundle>mvn:org.apache.httpcomponents/httpclient-osgi/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.httpcomponents/httpcore-osgi/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-keystone/{{VERSION}}</bundle>
+    </feature>
+
+    <feature name='odl-aaa-sssd-plugin' description='OpenDaylight :: AAA :: SSSD Federation Plugin'
+             version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-authn</feature>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-sssd/{{VERSION}}</bundle>
+    </feature>
+
+    <feature name='odl-aaa-authn-sssd-no-cluster' description='OpenDaylight :: AAA :: SSSD Federation - NO CLUSTER'
+             version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-authn-no-cluster</feature>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authn-sssd/{{VERSION}}</bundle>
+    </feature>
+</features>
diff --git a/odl-aaa-moon/aaa/features/authz/pom.xml b/odl-aaa-moon/aaa/features/authz/pom.xml
new file mode 100644
index 00000000..2ff41307
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/authz/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>features-parent</artifactId>
+        <version>1.6.2-Beryllium-SR2</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>features-aaa-authz</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <config.version>0.4.2-Beryllium-SR2</config.version>
+        <mdsal.version>2.0.2-Beryllium-SR2</mdsal.version>
+        <controller.mdsal.version>1.3.2-Beryllium-SR2</controller.mdsal.version>
+        <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- This project -->
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-parent</artifactId>
+                <version>${project.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa-api</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <!-- odl-aaa-authz -->
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>features-yangtools</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>features-mdsal</artifactId>
+            <classifier>features</classifier>
+            <version>${mdsal.version}</version>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-config</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-mdsal</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>authz-restconf-config</artifactId>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authz-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authz-service</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>authz-service-config</artifactId>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
+    </dependencies>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git.opendaylight.org/gerrit/gitweb?p=aaa.git;a=summary</url>
+    </scm>
+</project>
diff --git a/odl-aaa-moon/aaa/features/authz/src/main/features/features.xml b/odl-aaa-moon/aaa/features/authz/src/main/features/features.xml
new file mode 100644
index 00000000..c5239045
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/authz/src/main/features/features.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2014 Hewlett-Packard Development Company, L.P. and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<features name="odl-aaa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-config/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.mdsal/features-mdsal/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
+    <repository>mvn:org.opendaylight.aaa/features-aaa-api/{{VERSION}}/xml/features</repository>
+
+    <feature name='odl-aaa-authz' description='OpenDaylight :: AAA :: Authorization'
+        version='${project.version}'>
+        <feature version='${project.version}'>odl-aaa-api</feature>
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
+        <feature version='${controller.mdsal.version}'>odl-mdsal-broker</feature>
+        <feature version='${config.version}'>odl-config-core</feature>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authz-model/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-authz-service/{{VERSION}}</bundle>
+        <configfile
+            finalname="/etc/opendaylight/karaf/08-authz-config.xml">mvn:org.opendaylight.aaa/authz-service-config/{{VERSION}}/xml/config</configfile>
+        <configfile
+            finalname="/etc/opendaylight/karaf/09-rest-connector.xml">mvn:org.opendaylight.aaa/authz-restconf-config/{{VERSION}}/xml/config</configfile>
+    </feature>
+
+</features>
diff --git a/odl-aaa-moon/aaa/features/pom.xml b/odl-aaa-moon/aaa/features/pom.xml
new file mode 100644
index 00000000..548a240b
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/pom.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+  <groupId>org.opendaylight.aaa</groupId>
+  <artifactId>features-aggregator</artifactId>
+  <packaging>pom</packaging>
+  <modules>
+    <module>shiro</module>
+    <module>api</module>
+    <module>authn</module>
+    <module>authz</module>
+  </modules>
+</project>
diff --git a/odl-aaa-moon/aaa/features/shiro/pom.xml b/odl-aaa-moon/aaa/features/shiro/pom.xml
new file mode 100644
index 00000000..04114355
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/shiro/pom.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2015 Brocade Communications Systems and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>features-parent</artifactId>
+        <version>1.6.2-Beryllium-SR2</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>features-aaa-shiro</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <javax.annotation.api.version>1.2</javax.annotation.api.version>
+        <servicemix.version>1.8.3_2</servicemix.version>
+    </properties>
+    <dependencyManagement>
+        <dependencies>
+            <!-- This project -->
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-parent</artifactId>
+                <version>${project.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+        <groupId>com.google.code.findbugs</groupId>
+        <artifactId>jsr305</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+             <artifactId>features-aaa</artifactId>
+             <version>0.3.2-Beryllium-SR2</version>
+             <classifier>features</classifier>
+             <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro-act</artifactId>
+            <version>0.3.2-Beryllium-SR2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
+            <version>0.3.2-Beryllium-SR2</version>
+            <type>cfg</type>
+            <classifier>configuration</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
+        </dependency>
+        <dependency>
+              <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-sts</artifactId>
+            <version>0.3.2-Beryllium-SR2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+            <version>0.3.2-Beryllium-SR2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-server</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.metatype</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-authn-sts</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>${javax.annotation.api.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.metatype</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-beanutils</artifactId>
+            <version>${servicemix.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+    </dependencies>
+
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git.opendaylight.org/gerrit/gitweb?p=aaa.git;a=summary</url>
+    </scm>
+</project>
diff --git a/odl-aaa-moon/aaa/features/shiro/src/main/features/features.xml b/odl-aaa-moon/aaa/features/shiro/src/main/features/features.xml
new file mode 100644
index 00000000..c6073a2a
--- /dev/null
+++ b/odl-aaa-moon/aaa/features/shiro/src/main/features/features.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2015 Brocade Communications Systems and others.
+    All rights reserved. This program and the accompanying materials are made
+    available under the terms of the Eclipse Public License v1.0 which accompanies
+    this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<features name="odl-aaa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+
+    <repository>mvn:org.opendaylight.aaa/features-aaa/{{VERSION}}/xml/features</repository>
+
+    <!-- odl-aaa-shiro feature which combines all aspects of AAA into one feature -->
+    <feature name='odl-aaa-shiro' description='OpenDaylight :: AAA :: Shiro'
+             version='${project.version}'>
+
+        <!-- OSGI -->
+        <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/{{VERSION}}</bundle>
+
+        <!-- Existing AAA infrastructure -->
+        <feature version='${project.version}'>odl-aaa-authn</feature>
+
+        <bundle>mvn:org.apache.shiro/shiro-web/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.shiro/shiro-core/{{VERSION}}</bundle>
+
+        <bundle>mvn:com.google.guava/guava/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:javax.annotation/javax.annotation-api/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:com.google.code.findbugs/jsr305/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:commons-codec/commons-codec/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.resourceserver/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.authzserver/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/{{VERSION}}</bundle>
+        <bundle>wrap:mvn:org.json/json/{{VERSION}}</bundle>
+        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-beanutils/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}</bundle>
+
+        <!-- AAA configuration file -->
+        <configfile finalname="/etc/shiro.ini">mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}/cfg/configuration</configfile>
+    </feature>
+
+</features>
diff --git a/odl-aaa-moon/aaa/parent/pom.xml b/odl-aaa-moon/aaa/parent/pom.xml
new file mode 100644
index 00000000..42bf03b0
--- /dev/null
+++ b/odl-aaa-moon/aaa/parent/pom.xml
@@ -0,0 +1,278 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>odlparent</artifactId>
+        <version>1.6.2-Beryllium-SR2</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <packaging>pom</packaging>
+    <prerequisites>
+        <maven>3.0.4</maven>
+    </prerequisites>
+
+    <properties>
+        <!-- Karaf -->
+        <karaf.branding.version>1.2.2-Beryllium-SR2</karaf.branding.version>
+        <karaf.resources.version>1.6.2-Beryllium-SR2</karaf.resources.version>
+
+        <!-- OSGi -->
+        <osgi.metatype.version>1.0.10</osgi.metatype.version>
+
+        <!-- Local project version, needed for import -->
+        <aaa.version>${project.version}</aaa.version>
+        <parent-path>${basedir}</parent-path>
+
+        <!-- AuthZ -->
+        <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+        <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
+        <salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
+        <mdsal.version>2.0.2-Beryllium-SR2</mdsal.version>
+        <mdsal.model.version>0.8.2-Beryllium-SR2</mdsal.model.version>
+        <controller.mdsal.version>1.3.2-Beryllium-SR2</controller.mdsal.version>
+        <restconf.version>1.3.2-Beryllium-SR2</restconf.version>
+        <config.version>0.4.2-Beryllium-SR2</config.version>
+        <config.authz.service.configfile>08-authz-config.xml</config.authz.service.configfile>
+        <config.restconf.configfile>09-rest-connector.xml</config.restconf.configfile>
+        <config.configfile.directory>etc/opendaylight/karaf</config.configfile.directory>
+
+        <!-- AuthN -->
+        <glassfish.json.version>1.0.4</glassfish.json.version>
+        <ehcache.version>2.8.3</ehcache.version>
+        <jta.version>1.1.1</jta.version>
+        <oltu.version>1.0.0</oltu.version>
+
+        <config.authn.store.configfile>08-authn-config.xml</config.authn.store.configfile>
+
+        <!-- IdmLight -->
+        <h2.version>1.4.185</h2.version>
+
+        <!-- Keystone plugin -->
+        <httpclient.version>4.4</httpclient.version>
+
+        <!-- Test -->
+        <javax.inject.version>1</javax.inject.version>
+        <servlet.tester.version>7.0.0.M2</servlet.tester.version>
+        <features.test.version>1.6.2-Beryllium-SR2</features.test.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- ODL -->
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-artifacts</artifactId>
+                <version>${aaa.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yangtools-artifacts</artifactId>
+                <version>${yangtools.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.mdsal</groupId>
+                <artifactId>mdsal-artifacts</artifactId>
+                <version>${mdsal.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.mdsal.model</groupId>
+                <artifactId>mdsal-model-artifacts</artifactId>
+                <version>${mdsal.model.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>mdsal-artifacts</artifactId>
+                <version>${controller.mdsal.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>config-artifacts</artifactId>
+                <version>${config.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- Third-party -->
+            <dependency>
+                <groupId>org.glassfish</groupId>
+                <artifactId>javax.json</artifactId>
+                <version>${glassfish.json.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.metatype</artifactId>
+                <version>${osgi.metatype.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>net.sf.ehcache</groupId>
+                <artifactId>ehcache</artifactId>
+                <version>${ehcache.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.specs</groupId>
+                <artifactId>geronimo-jta_1.1_spec</artifactId>
+                <version>${jta.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.oltu.oauth2</groupId>
+                <artifactId>org.apache.oltu.oauth2.common</artifactId>
+                <version>${oltu.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.oltu.oauth2</groupId>
+                <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+                <version>${oltu.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.oltu.oauth2</groupId>
+                <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+                <version>${oltu.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.h2database</groupId>
+                <artifactId>h2</artifactId>
+                <version>${h2.version}</version>
+            </dependency>
+
+            <!-- Test stuff -->
+            <dependency>
+                <groupId>org.opendaylight.odlparent</groupId>
+                <artifactId>features-test</artifactId>
+                <version>${features.test.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>javax.inject</groupId>
+                <artifactId>javax.inject</artifactId>
+                <version>${javax.inject.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-servlet-tester</artifactId>
+                <version>${servlet.tester.version}</version>
+                <scope>test</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>org.opendaylight.aaa.*</include>
+                    </includes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>pre-test</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>post-test</id>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                        <phase>test</phase>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <configuration>
+                    <!-- checkstyle is evil -->
+                    <skip>false</skip>
+                    <failOnViolation>true</failOnViolation>
+                    <configLocation>checkstyle-logging.xml</configLocation>
+                    <consoleOutput>true</consoleOutput>
+                    <includeTestSourceDirectory>true</includeTestSourceDirectory>
+                    <sourceDirectory>${project.basedir}</sourceDirectory>
+                    <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang</includes>
+                    <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/src/main/yang-gen-config\/,**\/src/main/yang-gen-sal\/</excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <phase>process-sources</phase>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>checkstyle-logging</artifactId>
+                        <version>${yangtools.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${jmxGeneratorPath}</source>
+                                <source>${salGeneratorPath}</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <url>https://wiki.opendaylight.org/view/AAA:Main</url>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+        <tag>HEAD</tag>
+    </scm>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>${findbugs.maven.plugin.version}</version>
+                <configuration>
+                    <effort>Max</effort>
+                    <threshold>Low</threshold>
+                    <goal>site</goal>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>jdepend-maven-plugin</artifactId>
+                <version>${jdepend.maven.plugin.version}</version>
+            </plugin>
+        </plugins>
+    </reporting>
+</project>
diff --git a/odl-aaa-moon/aaa/pom.xml b/odl-aaa-moon/aaa/pom.xml
new file mode 100644
index 00000000..bafd03a2
--- /dev/null
+++ b/odl-aaa-moon/aaa/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.2-Beryllium-SR2</version>
+    <relativePath>parent</relativePath>
+  </parent>
+
+  <groupId>org.opendaylight.aaa</groupId>
+  <artifactId>aaa.project</artifactId>
+  <version>0.3.2-Beryllium-SR2</version>
+  <packaging>pom</packaging>
+  <name>aaa</name> <!-- Used by Sonar to set project name -->
+  <prerequisites>
+    <maven>3.0</maven>
+  </prerequisites>
+
+  <modules>
+    <module>aaa-authn-api</module>
+    <module>aaa-authn</module>
+    <module>aaa-idp-mapping</module>
+    <module>aaa-authn-sts</module>
+    <module>aaa-authn-store</module>
+    <module>aaa-authn-federation</module>
+    <module>aaa-authn-sssd</module>
+    <module>aaa-authn-keystone</module>
+    <module>aaa-authn-basic</module>
+    <module>aaa-idmlight</module>
+    <module>aaa-authn-mdsal-store</module>
+    <module>aaa-authz</module>
+    <module>aaa-credential-store-api</module>
+    <module>artifacts</module>
+    <module>features</module>
+    <module>distribution-karaf</module>
+    <module>parent</module>
+    <module>aaa-shiro</module>
+    <module>aaa-shiro-act</module>
+    <module>aaa-h2-store</module>
+  </modules>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/aaa.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/AAA:Main</url>
+  </scm>
+
+</project>
-- 
cgit