[AAF-21] Initial code import 91/6691/1
authorsg481n <sg481n@att.com>
Thu, 3 Aug 2017 21:39:12 +0000 (17:39 -0400)
committersg481n <sg481n@att.com>
Thu, 3 Aug 2017 21:39:12 +0000 (17:39 -0400)
Change-Id: Ia1dd196befd061f6ba0c2be6bf4456a30ea50f97
Signed-off-by: sg481n <sg481n@att.com>
253 files changed:
aaf/.gitignore [new file with mode: 0644]
aaf/pom.xml [new file with mode: 0644]
aaf/src/assemble/cadi-aaf-test.xml [new file with mode: 0644]
aaf/src/assemble/cadi-aaf.xml [new file with mode: 0644]
aaf/src/main/java/Examples.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/PermEval.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/client/Examples.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/CertException.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/CmAgent.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/Factory.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java [new file with mode: 0644]
aaf/src/main/java/com/att/cadi/sso/AAFSSO.java [new file with mode: 0644]
aaf/src/src/assemble/cadi-aaf-test.xml [new file with mode: 0644]
aaf/src/src/assemble/cadi-aaf.xml [new file with mode: 0644]
aaf/src/src/main/java/Examples.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/AAFPermission.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/AAFTransmutate.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/PermEval.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/client/ErrMessage.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/client/Examples.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/ArtifactDir.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/CertException.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/CmAgent.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/Factory.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifact.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java [new file with mode: 0644]
aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java [new file with mode: 0644]
aaf/src/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java [new file with mode: 0644]
aaf/src/src/test/resources/cadi.properties [new file with mode: 0644]
aaf/src/src/test/resources/log4j.properties [new file with mode: 0644]
aaf/src/src/test/resources/logging.props [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/content/JU_Content.java [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/example/CadiTest.java [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/example/ExampleAuthCheck.java [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0.java [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0_DME2.java [new file with mode: 0644]
aaf/src/test/java/com/att/aaf/example/X509Test.java [new file with mode: 0644]
aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_JMeter.java [new file with mode: 0644]
aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_Lur2_0Call.java [new file with mode: 0644]
aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_PermEval.java [new file with mode: 0644]
aaf/src/test/java/com/att/cadi/lur/aaf/test/MultiThreadPermHit.java [new file with mode: 0644]
aaf/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java [new file with mode: 0644]
aaf/src/test/resources/cadi.properties [new file with mode: 0644]
aaf/src/test/resources/log4j.properties [new file with mode: 0644]
aaf/src/test/resources/logging.props [new file with mode: 0644]
cass/.gitignore [new file with mode: 0644]
cass/etc/cadi.properties [new file with mode: 0644]
cass/pom.xml [new file with mode: 0644]
cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticatedUser.java [new file with mode: 0644]
cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticator.java [new file with mode: 0644]
cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthorizer.java [new file with mode: 0644]
cass/src/main/java/com/att/cadi/aaf/cass/AAFBase.java [new file with mode: 0644]
cass/src/test/java/com/att/aaf/cass/JU_CASS.java [new file with mode: 0644]
cass/src/test/java/com/att/cadi/aaf/cass/test/JU_CASS.java [new file with mode: 0644]
client/.gitignore [new file with mode: 0644]
client/pom.xml [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/AAFClient.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/AbsBasicAuth.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/AbsTransferSS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Delete.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/EClient.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/EnvAccess.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Future.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Get.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Holder.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Post.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/PropertyLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Put.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/RawClient.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Rcli.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Result.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/client/Retryable.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DEClient.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DME2Locator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DME2x509SS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dme2/DRcli.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HBasicAuthSS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HClient.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HMangr.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HRcli.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HTransferSS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/http/HX509SS.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/locator/DME2Locator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/locator/DNSLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/locator/HotPeerLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/locator/PropertyLocator.java [new file with mode: 0644]
client/src/main/java/com/att/cadi/routing/GreatCircle.java [new file with mode: 0644]
client/src/test/java/com/client/test/BasicDME2Client.java [new file with mode: 0644]
client/src/test/java/com/client/test/JU_DNSLocator.java [new file with mode: 0644]
client/src/test/java/com/client/test/JU_PropertyLocator.java [new file with mode: 0644]
client/src/test/java/com/client/test/PaulUzee.java [new file with mode: 0644]
client/src/test/java/com/client/test/TestAccess.java [new file with mode: 0644]
client/src/test/java/com/client/test/TestDME2Client.java [new file with mode: 0644]
client/src/test/java/com/client/test/TestDME2RcliClient.java [new file with mode: 0644]
client/src/test/java/com/client/test/TestHClient.java [new file with mode: 0644]
core/.gitignore [new file with mode: 0644]
core/conf/cadi.properties [new file with mode: 0644]
core/pom.xml [new file with mode: 0644]
core/src/assemble/cadi.xml [new file with mode: 0644]
core/src/assemble/poll.xml [new file with mode: 0644]
core/src/main/java/com/att/cadi/AES.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/AbsCachedPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/AbsUserCache.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Access.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/BasicCred.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/BufferedCadiWrap.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/BufferedServletInputStream.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CachedPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CachingLur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CadiException.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CadiWrap.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Capacitor.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CmdLine.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Connector.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/CredVal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/GetCred.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Hash.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Locator.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/LocatorException.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Lur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Permission.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/PropAccess.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Revalidator.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/SLF4JAccess.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/SecuritySetter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/ServletContextAccess.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/StrLur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Symm.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Taf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/Transmutate.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/TrustChecker.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/User.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/UserChain.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/Config.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/Get.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/GetAccess.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/MultiGet.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/SecurityInfo.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/SecurityInfoC.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/config/UsersDump.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/AUTHZ.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/AUTHZServlet.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/AccessGetter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/CadiAccess.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/CadiFilter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/CadiHTTPManip.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/FCGet.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/MapPermConverter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/NullPermConverter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/PathFilter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/PermConverter.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/RolesAllowed.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/filter/ServletImpl.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/lur/ConfigPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/lur/EpiLur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/lur/LocalLur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/lur/LocalPermission.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/lur/NullLur.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/BasicPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/BearerPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/CSPPrincipal_T.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/CachedBasicPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/TGuardPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/TGuardPrincipal_T.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/TrustPrincipal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/principal/X509Principal.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/AbsTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/EpiTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/HttpEpiTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/HttpTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/LoginPageTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/NullTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/NullTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/PuntTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/Redirectable.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/TafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/TrustNotTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/TrustTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/basic/BasicHttpTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/basic/BasicHttpTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/cert/CertIdentity.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/cert/X509HttpTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/cert/X509Taf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/localhost/LocalhostTaf.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/taf/localhost/LocalhostTafResp.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/Chmod.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/JsonOutputStream.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/MaskFormatException.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/MyConsole.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/NetMask.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/Split.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/SubStandardConsole.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/TheConsole.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/UserChainManip.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/util/Vars.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/wsse/Action.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/wsse/Match.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/wsse/WSSEParser.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/wsse/XEvent.java [new file with mode: 0644]
core/src/main/java/com/att/cadi/wsse/XReader.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/JU_AES.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/lur/test/JU_LocalLur.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/lur/test/TestAccess.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_Base64.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_BufferedServletInputStream.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_Capacitor.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_Hash.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_Passcode.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_UserChainManip.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/JU_Vars.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/test/Test.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/wsse/test/JU_WSSE_Read.java [new file with mode: 0644]
core/src/test/java/com/att/cadi/wsse/test/JU_XReader.java [new file with mode: 0644]
pom.xml [new file with mode: 0644]

diff --git a/aaf/.gitignore b/aaf/.gitignore
new file mode 100644 (file)
index 0000000..cf85207
--- /dev/null
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/aaf/pom.xml b/aaf/pom.xml
new file mode 100644 (file)
index 0000000..9673067
--- /dev/null
@@ -0,0 +1,189 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<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">\r
+       <parent>\r
+               <groupId>com.att.cadi</groupId>\r
+               <artifactId>parent</artifactId>\r
+               <version>1.3.2</version>\r
+               <relativePath>..</relativePath>\r
+       </parent>\r
+\r
+       <modelVersion>4.0.0</modelVersion>\r
+       <name>CADI AAF (Application Authorization Framework) LUR</name>\r
+       <packaging>jar</packaging>\r
+       <url>https://github.com/att/AAF</url>\r
+       <description>CADI</description>\r
+       <artifactId>cadi-aaf</artifactId>\r
+       <dependencies>\r
+               <dependency>\r
+                       <groupId>com.att.authz</groupId>\r
+                       <artifactId>authz-client</artifactId>\r
+               </dependency>\r
+\r
+                 <dependency>\r
+                       <groupId>com.att.cadi</groupId>\r
+                       <artifactId>cadi-client</artifactId>\r
+               </dependency> \r
+\r
+               <dependency>\r
+                       <groupId>com.att.cadi</groupId>\r
+                       <artifactId>cadi-client</artifactId>\r
+               </dependency>\r
+               \r
+               <dependency>\r
+                       <groupId>com.att.aft</groupId>\r
+                       <artifactId>dme2</artifactId>\r
+                       <scope>provided</scope>\r
+               </dependency>\r
+               \r
+               <dependency>\r
+                   <groupId>javax.servlet</groupId>\r
+                   <artifactId>javax.servlet-api</artifactId>\r
+                   <version>3.0.1</version>\r
+                       <scope>provided</scope>\r
+               </dependency>\r
+\r
+               <dependency>\r
+                       <groupId>org.slf4j</groupId>\r
+                   <artifactId>slf4j-log4j12</artifactId>\r
+                   <version>1.7.5</version>\r
+                   <scope>test</scope>\r
+               </dependency>\r
+\r
+       </dependencies>\r
+       <build>\r
+               <plugins> \r
+                       <plugin>\r
+                               <groupId>org.apache.maven.plugins</groupId>\r
+                               <artifactId>maven-compiler-plugin</artifactId>\r
+                               <version>2.3.2</version>\r
+                       </plugin>\r
+               \r
+                               <!-- We want to create a Jar with Rosetta built in (since I don't want \r
+                               a separate deployment at this time Use this one as the jar to put in SWM \r
+                               packages -->\r
+                       <plugin>\r
+                               <artifactId>maven-assembly-plugin</artifactId>\r
+                               <configuration>\r
+                                       <classifier>tests</classifier>\r
+                                       <archive>\r
+                                               <manifest>\r
+                                                       <mainClass>com.att.cadi.cm.CmAgent</mainClass>\r
+                                               </manifest>\r
+\r
+                                               <manifestEntries>\r
+                                                       <Sealed>true</Sealed>\r
+                                               </manifestEntries>\r
+                                       </archive>\r
+                               </configuration>\r
+                               <executions>\r
+                                       <execution>\r
+                                               <id>full</id>\r
+                                               <phase>package</phase>\r
+                                               <goals>\r
+                                                       <goal>single</goal>\r
+                                               </goals>\r
+                                               <configuration>\r
+                                                       <descriptors>\r
+                                                               <descriptor>src/assemble/cadi-aaf.xml</descriptor>\r
+                                                       </descriptors>\r
+                                               </configuration>\r
+                                       </execution>\r
+                               </executions>\r
+                       </plugin>\r
+               <plugin>\r
+                       <groupId>org.apache.maven.plugins</groupId>\r
+                       <artifactId>maven-javadoc-plugin</artifactId>\r
+                                       <configuration>\r
+                       <failOnError>false</failOnError>\r
+                       </configuration>\r
+                       <executions>\r
+                               <execution>\r
+                                       <id>attach-javadocs</id>\r
+                                       <goals>\r
+                                               <goal>jar</goal>\r
+                                       </goals>\r
+                               </execution>\r
+                       </executions>\r
+               </plugin> \r
+          \r
+          \r
+              <plugin>\r
+                     <groupId>org.apache.maven.plugins</groupId>\r
+                     <artifactId>maven-source-plugin</artifactId>\r
+                     <version>2.2.1</version>\r
+                     <executions>\r
+                       <execution>\r
+                         <id>attach-sources</id>\r
+                         <goals>\r
+                           <goal>jar-no-fork</goal>\r
+                         </goals>\r
+                       </execution>\r
+                     </executions>\r
+                   </plugin>\r
+       \r
+       <plugin>\r
+                       <groupId>org.sonatype.plugins</groupId>\r
+                       <artifactId>nexus-staging-maven-plugin</artifactId>\r
+                       <version>1.6.7</version>\r
+                       <extensions>true</extensions>\r
+                       <configuration>\r
+                       <serverId>ossrhdme</serverId>\r
+                       <nexusUrl>https://oss.sonatype.org/</nexusUrl>\r
+                       <autoReleaseAfterClose>true</autoReleaseAfterClose>\r
+                       </configuration>\r
+               </plugin>\r
+\r
+                       <plugin>\r
+                               <!-- Also sign "full" -->\r
+                               <groupId>org.apache.maven.plugins</groupId>\r
+                               <artifactId>maven-jarsigner-plugin</artifactId>\r
+                               <configuration>\r
+                                       <skip>true</skip>\r
+                               </configuration>\r
+                               <executions>\r
+                                       <execution>\r
+                                               <id>sign-full</id>\r
+                                               <goals>\r
+                                                       <goal>sign</goal>\r
+                                               </goals>\r
+                                               <configuration>\r
+                                                       <archive>target/${project.artifactId}-${project.version}-full.jar</archive>\r
+                                               </configuration>\r
+                                       </execution>\r
+                                       <execution>\r
+                                               <id>verify-full</id>\r
+                                               <goals>\r
+                                                       <goal>verify</goal>\r
+                                               </goals>\r
+                                               <configuration>\r
+                                                       <archive>target/${project.artifactId}-${project.version}-full.jar</archive>\r
+                                               </configuration>\r
+                                       </execution>\r
+                               </executions>\r
+                       </plugin>\r
+               \r
+               </plugins>\r
+       </build>\r
+</project>\r
diff --git a/aaf/src/assemble/cadi-aaf-test.xml b/aaf/src/assemble/cadi-aaf-test.xml
new file mode 100644 (file)
index 0000000..a6671ba
--- /dev/null
@@ -0,0 +1,110 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">\r
+  \r
+  <id>test</id>\r
+  <formats>\r
+    <format>zip</format>\r
+  </formats>\r
+\r
+  <includeBaseDirectory>true</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.cadi:cadi-core</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.cadi:cadi-aaf</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>org.eclipse.jetty.aggregate:jetty-all</include>\r
+      </includes>\r
+    </dependencySet>\r
+\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>org.eclipse.jetty.orbit:javax.servlet</include>\r
+      </includes>\r
+    </dependencySet>\r
+\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>javax:servlet</include>\r
+      </includes>\r
+    </dependencySet>\r
+    \r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.aft:dme2</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.aft.discovery:discovery-clt</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>compile</scope>\r
+      <includes>\r
+       <include>com.att.cssa:rosetta</include>\r
+      </includes>\r
+    </dependencySet>\r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>run</directory>\r
+      <includes>\r
+       <include>cadi.properties</include>\r
+       <include>keyfile</include>\r
+       <include>start.sh</include>\r
+      </includes>\r
+    </fileSet>\r
+      <fileSet>\r
+      <includes>\r
+       <include>../cadi/target/cadi-core*tests.jar</include>\r
+      </includes>\r
+    </fileSet>\r
+   </fileSets>\r
+  \r
+</assembly>\r
diff --git a/aaf/src/assemble/cadi-aaf.xml b/aaf/src/assemble/cadi-aaf.xml
new file mode 100644 (file)
index 0000000..578037b
--- /dev/null
@@ -0,0 +1,53 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">\r
+  \r
+  <id>full</id>\r
+  <formats>\r
+    <format>jar</format>\r
+  </formats>\r
+\r
+  <includeBaseDirectory>false</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <unpack>true</unpack>\r
+      <scope>compile</scope>\r
+      <includes>\r
+       <include>com.att.authz:authz-client</include>\r
+       <include>com.att.cadi:cadi-aaf</include>\r
+       <include>com.att.cadi:cadi-core</include>\r
+       <include>com.att.cadi:cadi-client</include>\r
+       <include>com.att.inno:env</include>\r
+       <include>com.att.inno:rosetta</include>\r
+      </includes>\r
+    </dependencySet>\r
+    \r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>src/main/xsd</directory>\r
+    </fileSet>\r
+   </fileSets>\r
+</assembly>\r
diff --git a/aaf/src/main/java/Examples.java b/aaf/src/main/java/Examples.java
new file mode 100644 (file)
index 0000000..91f313f
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class Examples {\r
+       public static void main(String[] args) {\r
+               if(args.length<1) {\r
+                       System.out.println("Usage: Examples <name> [\"optional\" - will show optional fields]");\r
+               } else {\r
+                       boolean options = args.length>1&&"optional".equals(args[1]);\r
+                       try {\r
+                               RosettaEnv env = new RosettaEnv();\r
+                               System.out.println(com.att.cadi.aaf.client.Examples.print(env, args[0], options));\r
+                       } catch (Exception e) {\r
+                               System.out.println(e.getMessage());\r
+                       }\r
+               }\r
+       }\r
+       \r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java b/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java
new file mode 100644 (file)
index 0000000..e604053
--- /dev/null
@@ -0,0 +1,106 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import com.att.cadi.Permission;\r
+\r
+/**\r
+ * A Class that understands the AAF format of Permission (name/type/action)\r
+ *  or String "name|type|action"\r
+ * \r
+ *\r
+ */\r
+public class AAFPermission implements Permission {\r
+       protected String type,instance,action,key;\r
+\r
+       protected AAFPermission() {}\r
+\r
+       public AAFPermission(String type, String instance, String action) {\r
+               this.type = type;\r
+               this.instance = instance;\r
+               this.action = action;\r
+               key = type + '|' + instance + '|' + action;\r
+       }\r
+       \r
+       /**\r
+        * Match a Permission\r
+        * if Permission is Fielded type "Permission", we use the fields\r
+        * otherwise, we split the Permission with '|'\r
+        * \r
+        * when the type or action starts with REGEX indicator character ( ! ),\r
+        * then it is evaluated as a regular expression.\r
+        * \r
+        * If you want a simple field comparison, it is faster without REGEX\r
+        */\r
+       public boolean match(Permission p) {\r
+               if(p instanceof AAFPermission) {\r
+                       AAFPermission ap = (AAFPermission)p;\r
+                       // Note: In AAF > 1.0, Accepting "*" from name would violate multi-tenancy\r
+                       // Current solution is only allow direct match on Type.\r
+                       // 8/28/2014 - added REGEX ability\r
+                       if(type.equals(ap.getName()))  \r
+                               if(PermEval.evalInstance(instance,ap.getInstance()))\r
+                                       if(PermEval.evalAction(action,ap.getAction()))\r
+                                               return true;\r
+               } else {\r
+                       // Permission is concatenated together: separated by |\r
+                       String[] aaf = p.getKey().split("[\\s]*\\|[\\s]*",3);\r
+                       if(aaf.length>0 && type.equals(aaf[0]))\r
+                               if(PermEval.evalInstance(instance,aaf.length>1?aaf[1]:"*"))\r
+                                       if(PermEval.evalAction(action,aaf.length>2?aaf[2]:"*"))\r
+                                               return true;\r
+               }                               \r
+               return false;\r
+       }\r
+\r
+       public String getName() {\r
+               return type;\r
+       }\r
+       \r
+       public String getInstance() {\r
+               return instance;\r
+       }\r
+       \r
+       public String getAction() {\r
+               return action;\r
+       }\r
+       \r
+       public String getKey() {\r
+               return key;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Permission#permType()\r
+        */\r
+       public String permType() {\r
+               return "AAF";\r
+       }\r
+\r
+       public String toString() {\r
+               return "AAFPermission:\n\tType: " + type + \r
+                               "\n\tInstance: " + instance +\r
+                               "\n\tAction: " + action +\r
+                               "\n\tKey: " + key;\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java b/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
new file mode 100644 (file)
index 0000000..a6a9bb7
--- /dev/null
@@ -0,0 +1,88 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import java.security.Principal;\r
+import java.util.regex.Pattern;\r
+\r
+import com.att.cadi.Transmutate;\r
+import com.att.cadi.lur.ConfigPrincipal;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.CSPPrincipal_T;\r
+\r
+/**\r
+ * AAFTransmutate\r
+ * \r
+ * Each System determines the mechanisms for which one Principal is transmutated to another, such as whether it is created\r
+ * independently, etc.\r
+ * \r
+ * For AAF, the only important thing is that these are valid ATTUID/mechIDs, to avoid unnecessary user hits\r
+ * \r
+ * attUIDs look like ab1234 or AB1234 or AZ123a\r
+ * mechids look like m12345\r
+ * \r
+ *\r
+ */\r
+public final class AAFTransmutate implements Transmutate<Principal> {\r
+       private Pattern pattern = Pattern.compile("[a-zA-Z]\\w\\d\\d\\d\\w");\r
+\r
+       public Principal mutate(Principal p) {\r
+               // Accept these three internal kinds of Principals\r
+               if(p instanceof CSPPrincipal_T \r
+                       || p instanceof BasicPrincipal\r
+                       || p instanceof ConfigPrincipal) { \r
+                       return p;\r
+               } else { \r
+                       \r
+                       final String name = p.getName();\r
+                       final int idx = name.indexOf('@');\r
+                       String shortName;\r
+                       if(idx>0) { // strip off any domain\r
+                               shortName = name.substring(0,idx); \r
+                       } else {\r
+                               shortName = name;\r
+                       }\r
+\r
+                       // Check for ATTUID specs before creating CSP_T\r
+                       return pattern.matcher(shortName).matches()?\r
+                               new CSP_T(name): // Note: use REAL name, short name for CSP_T\r
+                               null;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Essential Principal reflecting CSP Principal\r
+        * \r
+        *\r
+        */\r
+       private final class CSP_T implements CSPPrincipal_T {\r
+               private String name;\r
+               public CSP_T(String name) {\r
+                       this.name = name;\r
+               }\r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java b/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java
new file mode 100644 (file)
index 0000000..070d48d
--- /dev/null
@@ -0,0 +1,459 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.lang.reflect.Field;\r
+import java.net.HttpURLConnection;\r
+import java.net.InetAddress;\r
+import java.net.InetSocketAddress;\r
+import java.net.Socket;\r
+import java.net.URI;\r
+import java.net.UnknownHostException;\r
+import java.util.Date;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.aaf.v2_0.AAFConDME2;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.http.HClient;\r
+import com.att.cadi.http.HX509SS;\r
+import com.att.cadi.locator.DME2Locator;\r
+import com.att.cadi.locator.PropertyLocator;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+import aaf.v2_0.Perms;\r
+\r
+public class ConnectivityTest {\r
+       private static final String PROD = "PROD";\r
+       private static final String SRV_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=%s/routeOffer=%s";\r
+       private static final String GW_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.authz-gw/version=2.0/envContext=%s/routeOffer=%s";\r
+       \r
+       public static void main(String[] args) {\r
+               if(args.length<2) {\r
+                       System.out.println("Usage: ConnectivityTester <TEST|IST|PROD> <cadi_prop_files>");\r
+               } else {\r
+                       print(true,"START OF CONNECTIVITY TESTS",new Date().toString(),System.getProperty("user.name"),\r
+                                       "Note: All API Calls are /authz/perms/user/<MechID/Alias of the caller>");\r
+\r
+                       final String aaf_env = args[0];\r
+                       args[1]=Config.CADI_PROP_FILES+'='+args[1];\r
+                       \r
+                       PropAccess pa = new PropAccess(args);\r
+                       String user = pa.getProperty(Config.AAF_MECHID);\r
+                       String pass = pa.getProperty(Config.AAF_MECHPASS);\r
+                       String alias = pa.getProperty(Config.CADI_ALIAS);\r
+                       if(user==null) {\r
+                               user=alias;\r
+                       }\r
+                       RosettaEnv env = new RosettaEnv(pa.getProperties());\r
+                       \r
+                       try {\r
+                               RosettaDF<Perms> permsDF = env.newDataFactory(Perms.class);\r
+                               SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(pa);\r
+                               HBasicAuthSS hbass = new HBasicAuthSS(pa,si);\r
+                               if(hbass.getID()==null) {\r
+                                       hbass=null; // not configured with ID.\r
+                               }\r
+                               HX509SS hxss=null;\r
+                               AAFCon<?> aafcon;\r
+                               \r
+                               try {\r
+                                       hxss = new HX509SS(user,si);\r
+                               } catch(Exception e) {\r
+                                       e.printStackTrace();\r
+                                       print(false,"Continuing");\r
+                               }\r
+                               String aafurl;\r
+                               if(user==null || (pass==null && alias==null)) {\r
+                                       System.out.printf("ERROR: DME2 Client cannot be tested with out %s and %s properties"\r
+                                                       , Config.AAF_MECHID, Config.AAF_MECHPASS );\r
+                               } else {\r
+                                       if("TEST".equals(aaf_env) || "IST".equals(aaf_env) || "PROD".equals(aaf_env)) {\r
+                                               DME2Manager dm = null;\r
+                                               print(false,"Attempt DME2Manager Load");\r
+                                               if(Class.forName("com.att.aft.dme2.api.DME2Manager")==null) {\r
+                                                       print(true,"DME2 jar is not available:  Skipping DME2 Tests");\r
+                                               } else { // DME2 Client Tests\r
+                                                       pass=pa.decrypt(pass,false);\r
+                                                       // Out of the box DME2\r
+                                                       aafurl = String.format(SRV_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");\r
+                                                       print(true,"TEST CADI Config",aafurl);\r
+                                                       aafcon = testConfig(pa,aafurl);\r
+                                                       test(aafcon,permsDF,user);\r
+                                                       \r
+                                                       print(true,"Find and TEST Connections with DME2Locator",aafurl);\r
+                                                       DME2Locator dl = new DME2Locator(pa,dm,aafurl);\r
+                                                       connectTest(dl);\r
+       \r
+                                                       dm =  new DME2Manager("DME2Manager",pa.getProperties());\r
+       \r
+                                                       dme2RawTest(dm, aafurl,user,pass);\r
+                                                       \r
+                                                       // URL specific Variant\r
+                                                       if((aafurl = specificDME2URL(dl, aafurl))!=null) {\r
+                                                               print(true,"TEST Specific DME2 CADI Config",aafurl);\r
+                                                               aafcon = testConfig(pa,aafurl);\r
+                                                               test(aafcon,permsDF,user);\r
+       \r
+                                                               dme2RawTest(dm,aafurl,user,pass);\r
+                                                       }\r
+                                                       \r
+                                                       print(true,"CADI Direct AAFConDME2 Object Usage",aafurl);\r
+                                                       try {\r
+                                                               pa.setProperty(Config.AAF_URL,aafurl);\r
+                                                               aafcon = new AAFConDME2(pa);\r
+                                                               test(aafcon,permsDF,user);\r
+                                                       } catch(Throwable t) {\r
+                                                               t.printStackTrace();\r
+                                                       }\r
+                                                       \r
+                                                       // find a direct client to code a Direct HTTP with\r
+       //                                              \r
+                                                       if(hbass!=null) {\r
+                                                               print(true,"CADI Http DME2Locator Client Coding Methodology BasicAuth",aafurl);\r
+                                                               hClientTest(dl,hbass,user);\r
+                                                       }\r
+                                                       if(hxss!=null) {\r
+                                                               print(true,"CADI Http DME2Locator Client Coding Methodology X509",aafurl);\r
+                                                               hClientTest(dl,hxss,user);\r
+                                                       }\r
+                                                       \r
+                                                       // ##### PROXY CHECKS\r
+                                                       aafurl = String.format(GW_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");\r
+                                                       print(true,"TEST PROXY DME2 CADI Config",aafurl);\r
+                                                       aafcon = testConfig(pa,aafurl);\r
+                                                       test(aafcon,permsDF,user);\r
+       \r
+       \r
+                                                       dme2RawTest(dm, aafurl,user,pass);\r
+                                                       \r
+                                                       // URL specific Variant\r
+                                                       dl = new DME2Locator(pa,dm,aafurl);\r
+                                                       if((aafurl = specificDME2URL(dl, aafurl))!=null) {\r
+                                                               print(true,"TEST PROXY Specific DME2 CADI Config",aafurl);\r
+                                                               aafcon = testConfig(pa,aafurl);\r
+                                                               test(aafcon,permsDF,user);\r
+       \r
+                                                               dme2RawTest(dm,aafurl,user,pass);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                                       // Prop Locator\r
+                                       PropertyLocator pl = servicePropLocator(aaf_env);\r
+                                       connectTest(pl);\r
+                                       URI uri = pl.get(pl.best());\r
+                                       if(uri!=null) {\r
+                                               aafurl = uri.toString();\r
+                                               print(true,"TEST Service PropertyLocator based Config",aafurl);\r
+                                               aafcon = testConfig(pa,aafurl);\r
+                                               test(aafcon,permsDF,user);\r
+       \r
+                                               if(hbass!=null) {\r
+                                                       print(true,"CADI Service Http PropLocator Client Coding Methodology Basic Auth",aafurl);\r
+                                                       hClientTest(pl,hbass, user);\r
+                                                       print(true,"CADI Service Http PropLocator Client Coding Methodology /authn/basicAuth",aafurl);\r
+                                                       basicAuthTest(pl,hbass);\r
+                                               }\r
+                                               if(hxss!=null) {\r
+                                                       print(true,"CADI Service Http PropLocator Client Coding Methodology X509",aafurl);\r
+                                                       hClientTest(pl,hxss, user);\r
+                                               }\r
+                                       }\r
+                                       pl = proxyPropLocator(aaf_env);\r
+                                       connectTest(pl);\r
+                                       uri = pl.get(pl.best());\r
+                                       if(uri!=null) {\r
+                                               aafurl = uri.toString();\r
+                                               print(true,"TEST PROXY PropertyLocator based Config",aafurl);\r
+                                               aafcon = testConfig(pa,aafurl);\r
+                                               test(aafcon,permsDF,user);\r
+       \r
+                                               if(hbass!=null) {\r
+                                                       print(true,"CADI PROXY Http PropLocator Client Coding Methodology Basic Auth",aafurl);\r
+                                                       hClientTest(pl,hbass, user);\r
+                                                       print(true,"CADI PROXY Http PropLocator Client Coding Methodology /proxy/authn/basicAuth",aafurl);\r
+                                                       basicAuthTest(pl,hbass);\r
+                                               }\r
+                                               if(hxss!=null) {\r
+                                                       print(true,"CADI PROXY Http PropLocator Client Coding Methodology X509",aafurl);\r
+                                                       hClientTest(pl,hxss, user);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                       } catch(Exception e) {\r
+                               e.printStackTrace(System.err);\r
+                       } finally {\r
+                               print(true,"END OF TESTS");\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private static void print(Boolean strong, String ... args) {\r
+               PrintStream out = System.out;\r
+               out.println();\r
+               if(strong) {\r
+                       for(int i=0;i<70;++i) {\r
+                               out.print('=');\r
+                       }\r
+                       out.println();\r
+               }\r
+               for(String s : args) {\r
+                       out.print(strong?"==  ":"------ ");\r
+                       out.print(s);\r
+                       if(!strong) {\r
+                               out.print("  ------");\r
+                       }\r
+                       out.println();\r
+               }\r
+               if(strong) {\r
+                       for(int i=0;i<70;++i) {\r
+                               out.print('=');\r
+                       }\r
+               }\r
+               out.println();\r
+       }\r
+\r
+       private static void test(AAFCon<?> aafcon,RosettaDF<Perms> permsDF,String user) {\r
+               if(aafcon==null) {\r
+                       print(false,"AAFCon is null");\r
+               } else {\r
+                       try {\r
+                               print(false,"Calling with AAFCon");\r
+                               Future<Perms> fp = aafcon.client("2.0").read("/authz/perms/user/"+user, Perms.class, permsDF);\r
+                               if(fp.get(4000)) {\r
+                                       System.out.printf("Found %d Permission(s)\n",fp.value.getPerm().size());\r
+                               } else {\r
+                                       System.out.printf("Error: %d %s\n",fp.code(),fp.body());\r
+                               }\r
+                       } catch (Throwable t) {\r
+                               t.printStackTrace();\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private static AAFCon<?> testConfig(PropAccess pa, String aafurl) {\r
+               try {\r
+                       pa.setProperty(Config.AAF_URL, aafurl);\r
+                       Lur lur = Config.configLur(pa);\r
+                       Config.configHttpTaf(pa, TrustChecker.NOTRUST, null, lur);\r
+                       if(lur != null) {\r
+                               Field f = null;\r
+                               try {\r
+                                       f = lur.getClass().getField("aaf");\r
+                                       return (AAFCon<?>)f.get(lur);\r
+                               } catch (Exception nsfe) {\r
+                               }\r
+                       }\r
+\r
+               } catch(Throwable t) {\r
+                       t.printStackTrace();\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       private static String specificDME2URL(Locator<URI> loc, String aafurl) throws LocatorException {\r
+               Item item = loc.best();\r
+               if(item!=null) {\r
+                       URI uri = loc.get(item);\r
+                       return aafurl.replace("DME2RESOLVE", String.format("%s:%d",uri.getHost(),uri.getPort()));\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private static void connectTest(Locator<URI> dl) throws LocatorException {\r
+               URI uri;\r
+               Socket socket;\r
+               print(false,"TCP/IP Connect test to all Located Services");\r
+               for(Item li = dl.first();li!=null;li=dl.next(li)) {\r
+                       if((uri = dl.get(li)) == null) {\r
+                               System.out.println("Locator Item empty");\r
+                       } else {\r
+                               try {\r
+                                       socket = new Socket();\r
+                                       socket.connect(new InetSocketAddress(uri.getHost(),  uri.getPort()),3000);\r
+                                       System.out.printf("Can Connect a Socket to %s %d\n",uri.getHost(),uri.getPort());\r
+                                       try {\r
+                                               socket.close();\r
+                                       } catch (IOException e1) {\r
+                                               System.out.printf("Could not close Socket Connection: %s\n",e1.getMessage());\r
+                                       }\r
+                               } catch (IOException e) {\r
+                                       System.out.printf("Cannot Connect a Socket to  %s %d: %s\n",uri.getHost(),uri.getPort(),e.getMessage());\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static PropertyLocator servicePropLocator(String env) throws LocatorException {\r
+               String purls;\r
+               switch(env) {\r
+                       case "LOCAL":\r
+                               try {\r
+                                       purls="https://"+InetAddress.getLocalHost().getHostName()+":8100";\r
+                               } catch (UnknownHostException e) {\r
+                                       throw new LocatorException(e);\r
+                               }\r
+                               break;\r
+                       case "DEV":\r
+                               purls="https://aaf.dev.att.com:8100,https://aaf.dev.att.com:8101";\r
+                               break;\r
+                       case "TEST":\r
+                               purls="https://aaftest.test.att.com:8100,https://aaftest.test.att.com:8101";\r
+                               break;\r
+                       case "IST":\r
+                               purls="https://aafist.test.att.com:8100,https://aafist.test.att.com:8101";\r
+                               break;\r
+                       case PROD:\r
+                               purls="https://aaf.it.att.com:8100,https://aaf.it.att.com:8101";\r
+                               break;\r
+                       default:\r
+                               if(env.contains(".")) {\r
+                                       purls="https://"+env+":8100";\r
+                               } else {\r
+                                       throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");\r
+                               }\r
+               }\r
+               System.out.printf("Creating a PropertyLocator for %s\n",purls);\r
+               return new PropertyLocator(purls);\r
+       }\r
+       \r
+       private static PropertyLocator proxyPropLocator(String env) throws LocatorException {\r
+               String purls;\r
+               switch(env) {\r
+                       case "LOCAL":\r
+                               try {\r
+                                       purls="https://"+InetAddress.getLocalHost().getHostAddress()+":8100";\r
+                               } catch (UnknownHostException e) {\r
+                                       throw new LocatorException(e);\r
+                               }\r
+                               break;\r
+                       case "DEV":\r
+                               purls="https://aaf.dev.att.com:8095/proxy";\r
+                               break;\r
+                       case "TEST":\r
+                               purls="https://aaftest.test.att.com:8095/proxy";\r
+                               break;\r
+                       case "IST":\r
+                               purls="https://aafist.test.att.com:8095/proxy";\r
+                               break;\r
+                       case PROD:\r
+                               purls="https://aaf.it.att.com:8095/proxy";\r
+                               break;\r
+                       default:\r
+                               if(env.contains(".")) {\r
+                                       purls="https://"+env+":8095/proxy";\r
+                               } else {\r
+                                       throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");\r
+                               }\r
+\r
+               }\r
+               System.out.printf("Creating a PropertyLocator for %s\n",purls);\r
+               return new PropertyLocator(purls);\r
+       }\r
+               \r
+       \r
+\r
+\r
+       private static void hClientTest(Locator<URI> dl, SecuritySetter<HttpURLConnection> ss, String user)  {\r
+               try {\r
+                       URI uri = dl.get(dl.best());\r
+                       System.out.println("Resolved to: " + uri);\r
+                       HClient client = new HClient(ss, uri, 3000);\r
+                       client.setMethod("GET");\r
+                       client.setPathInfo("/authz/perms/user/"+user);\r
+                       client.send();\r
+                       Future<String> future = client.futureReadString();\r
+                       if(future.get(7000)) {\r
+                               System.out.println(future.body());      \r
+                       } else {\r
+                               System.out.println(future.code() + ":" + future.body());\r
+                       }\r
+               } catch (CadiException | LocatorException | APIException e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+\r
+       private static void basicAuthTest(PropertyLocator dl, SecuritySetter<HttpURLConnection> ss) {\r
+               try {\r
+                       URI uri = dl.get(dl.best());\r
+                       System.out.println("Resolved to: " + uri);\r
+                       HClient client = new HClient(ss, uri, 3000);\r
+                       client.setMethod("GET");\r
+                       client.setPathInfo("/authn/basicAuth");\r
+                       client.addHeader("Accept", "text/plain");\r
+                       client.send();\r
+       \r
+               \r
+                       Future<String> future = client.futureReadString();\r
+                       if(future.get(7000)) {\r
+                               System.out.println("BasicAuth Validated");      \r
+                       } else {\r
+                               System.out.println("Failure " + future.code() + ":" + future.body());\r
+                       }\r
+               } catch (CadiException | LocatorException | APIException e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+       // Regular DME2Client Coding Style\r
+       private static void dme2RawTest(DME2Manager dm, String aafurl, String user, String pass) {\r
+               try { \r
+                       if(dm==null) {\r
+                               return;\r
+                       }\r
+                       URI uri = new URI(aafurl);\r
+                       print(true,"DME2 Direct Client Coding Methodology",uri.toString());\r
+                       DME2Client client = dm.newClient( uri, 3000);\r
+                       client.setMethod("GET"); // FYI, DME2 defaults to "POST"\r
+                       client.setContext("/authz/perms/user/"+user); // DME2 direct requires separate setting of Context from URI\r
+                       if(pass!=null) { // rely on Cert if no pass\r
+                               client.setCredentials(user, pass);\r
+                       }\r
+                       client.setPayload(""); // DME2  will not send without something\r
+                       String resp = client.sendAndWait(7000);\r
+                       System.out.println(resp);\r
+               } catch(Throwable e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/PermEval.java b/aaf/src/main/java/com/att/cadi/aaf/PermEval.java
new file mode 100644 (file)
index 0000000..b661df4
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import com.att.inno.env.util.Split;\r
+\r
+\r
+public class PermEval {\r
+       public static final char START_REGEX_CHAR = '!';\r
+       public static final char START_INST_KEY_CHAR=':';\r
+       public static final char ALT_START_INST_KEY_CHAR='/';\r
+       \r
+       public static final char LIST_SEP = ',';\r
+       public static final String INST_KEY_REGEX = new StringBuilder().append(START_INST_KEY_CHAR).toString();\r
+       public static final String ASTERIX = "*";\r
+       \r
+       /**\r
+        * Evaluate Instance\r
+        * \r
+        * Instance can be more complex.  It can be a string, a Regular Expression, or a ":" separated Key \r
+        * who's parts can also be a String, Regular Expression.\r
+        * \r
+        * sInst = Server's Instance\r
+        * In order to prevent false matches, keys must be the same length to count as equal\r
+        * Changing this will break existing users, like Cassandra.  9-4-2015\r
+        */\r
+        public static boolean evalInstance(String sInst, String pInst) {\r
+                if(sInst==null || pInst == null) {\r
+                        return false;\r
+                }\r
+                 if(ASTERIX.equals(sInst)) {\r
+                         return true;                  // If Server's String is "*", then it accepts every Instance\r
+                 }\r
+                 char firstChar = pInst.charAt(0);\r
+                 char startChar = firstChar==ALT_START_INST_KEY_CHAR?ALT_START_INST_KEY_CHAR:START_INST_KEY_CHAR;\r
+                 switch(pInst.charAt(0)) {                                             // First char\r
+                       case START_REGEX_CHAR:                                                  // Evaluate as Regular Expression\r
+                               String pItem = pInst.substring(1);\r
+                           for(String sItem : Split.split(LIST_SEP,sInst)) {           // allow for "," definition in Action\r
+                               return sItem.matches(pItem);\r
+                           }\r
+                        \r
+                       case START_INST_KEY_CHAR:                                               // Evaluate a special Key field, i.e.:xyz:*:!df.*\r
+                       case ALT_START_INST_KEY_CHAR:                                   // Also allow '/' as special Key Field, i.e. /xyz/*/!.*\r
+                               if(sInst.charAt(0)==startChar) {  // To compare key-to-key, both strings must be keys\r
+                                       String[] skeys=Split.split(startChar,sInst);\r
+                                       String[] pkeys=Split.split(startChar,pInst);\r
+                                       if(skeys.length!=pkeys.length) return false;\r
+                                       \r
+                                       boolean pass = true;\r
+                                       for(int i=1;pass && i<skeys.length;++i) {                               // We start at 1, because the first one, being ":" is always ""\r
+                                               if(ASTERIX.equals(skeys[i]))continue;                           // Server data accepts all for this key spot\r
+                                               pass = false;\r
+                                           for(String sItem : Split.split(LIST_SEP,skeys[i])) {                // allow for "," definition in Action\r
+                                                       if(pkeys[i].length()==0) {\r
+                                                               if(pass=sItem.length()==0) {\r
+                                                                       break;                                                                  // Both Empty, keep checking\r
+                                                               }\r
+//                                                     } else if(pkeys[i].charAt(0)==START_REGEX_CHAR) { \r
+//                                                             if(pass=sItem.matches(pkeys[i].substring(1))) {\r
+//                                                                     break;                                                                  // Matches, keep checking\r
+//                                                             }\r
+                                                       } else if(sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like *\r
+                                                               if(pass=pkeys[i].matches(sItem.substring(1))) {\r
+                                                                       break;                                                                  // Matches, keep checking\r
+                                                               }\r
+                                                       } else if(skeys[i].endsWith(ASTERIX)) {\r
+                                                               if(pass=endAsterixCompare(skeys[i],pkeys[i])) {\r
+                                                                       break;\r
+                                                               }\r
+                                                       } else {\r
+                                                               if(pass=sItem.equals(pkeys[i]))\r
+                                                                       break;                                                                  // Equal, keep checking\r
+                                                       }\r
+                                           }\r
+                                       }\r
+                                       return pass;                                                                                    // return whether passed all key checks\r
+                               }\r
+                               return false;                                                           // if first chars aren't the same, further String compare not necessary\r
+                       default:                                                                                // Evaluate as String Compare\r
+                           for(String sItem : Split.split(LIST_SEP,sInst)) {   // allow for "," separator //TODO is this only for actions?\r
+                               if(sItem.endsWith(ASTERIX)) {\r
+                                       if(endAsterixCompare(sInst, pInst));\r
+                               } else if(sItem.equals(pInst)) {\r
+                                       return true;\r
+                               }\r
+                           }\r
+                           return false;\r
+                 }\r
+        }\r
+        \r
+        private static boolean endAsterixCompare(String sInst, String pInst) {\r
+                       final int len = sInst.length()-1;\r
+                       if(pInst.length()<len) {\r
+                               return false;\r
+                       }\r
+                       for(int j=0;j<len;++j) {\r
+                               if(pInst.charAt(j)!=sInst.charAt(j)) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       return true;\r
+       }\r
+\r
+       /**\r
+         * Evaluate Action\r
+         * \r
+         * sAction = Stored Action...\r
+         * pAction = Present Action... the Permission to validate against.\r
+         * Action is not quite as complex.  But we write it in this function so it can be consistent\r
+         */\r
+         public static boolean evalAction(String sAction,String pAction) {\r
+                 if(ASTERIX.equals(sAction))return true;                    // If Server's String is "*", then it accepts every Action\r
+                 for(String sItem : Split.split(LIST_SEP,sAction)) {            // allow for "," definition in Action\r
+                         if (pAction.charAt(0)==START_REGEX_CHAR?       // First char\r
+                                     sItem.matches(pAction.substring(1)):   // Evaluate as Regular Expression\r
+                                     sItem.equals(pAction))                 // Evaluate as String Compare\r
+                                               return true;\r
+                 }             \r
+                 return false;\r
+         }\r
+        \r
+         /**\r
+          * Split.split by Char\r
+          * \r
+          * Note: I read the String Split.split and Pattern Split.split code, and we can do this more efficiently for a single Character\r
+          */\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java b/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java
new file mode 100644 (file)
index 0000000..ecdaf24
--- /dev/null
@@ -0,0 +1,179 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cert;\r
+\r
+\r
+import java.security.Principal;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.X509Certificate;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+import java.util.TreeMap;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.xml.datatype.XMLGregorianCalendar;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.principal.X509Principal;\r
+import com.att.cadi.taf.cert.CertIdentity;\r
+import com.att.cadi.taf.cert.X509Taf;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.inno.env.util.Split;\r
+\r
+import aaf.v2_0.Certs;\r
+import aaf.v2_0.Certs.Cert;\r
+import aaf.v2_0.Users;\r
+import aaf.v2_0.Users.User;\r
+\r
+public class AAFListedCertIdentity implements CertIdentity {\r
+       //TODO should 8 hours be configurable? \r
+       private static final long EIGHT_HOURS = 1000*60*60*8; \r
+       private static final String AAF_VERSION = "2.0";\r
+                       \r
+       private static Map<ByteArrayHolder,String> certs = null;\r
+       \r
+       // Did this to add other Trust Mechanisms\r
+       // Trust mechanism set by Property: \r
+       private static final String[] authMechanisms = new String[] {"tguard","basicAuth","csp"};\r
+       private static String[] certIDs;\r
+       \r
+       private static Map<String,Set<String>> trusted =null;\r
+\r
+       public AAFListedCertIdentity(Access access, AAFCon<?> aafcon) throws APIException {\r
+               synchronized(AAFListedCertIdentity.class) {\r
+                       if(certIDs==null) {\r
+                               String cip = access.getProperty(Config.AAF_CERT_IDS, null);\r
+                               if(cip!=null) {\r
+                                       certIDs = Split.split(',',cip);\r
+                               }\r
+                       }\r
+                       if(certIDs!=null && certs==null) {\r
+                               TimerTask cu = new CertUpdate(aafcon);\r
+                               cu.run(); // want this to run in this thread first...\r
+                               new Timer("AAF Identity Refresh Timer",true).scheduleAtFixedRate(cu, EIGHT_HOURS,EIGHT_HOURS);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static Set<String> trusted(String authMech) {\r
+               return trusted.get(authMech);\r
+       }\r
+       \r
+       public Principal identity(HttpServletRequest req, X509Certificate cert, byte[] certBytes) throws CertificateException {\r
+               if(cert==null && certBytes==null)return null;\r
+               if(certBytes==null)certBytes = cert.getEncoded();\r
+               byte[] fingerprint = X509Taf.getFingerPrint(certBytes);\r
+               String id = certs.get(new ByteArrayHolder(fingerprint));\r
+               if(id!=null) { // Caller is Validated\r
+                       return new X509Principal(id,cert,certBytes);\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private static class ByteArrayHolder implements Comparable<ByteArrayHolder> {\r
+               private byte[] ba;\r
+               public ByteArrayHolder(byte[] ba) {\r
+                       this.ba = ba;\r
+               }\r
+               public int compareTo(ByteArrayHolder b) {\r
+                       return Hash.compareTo(ba, b.ba);\r
+               }\r
+       }\r
+       \r
+       private class CertUpdate extends TimerTask {\r
+\r
+               private AAFCon<?> aafcon;\r
+               public CertUpdate(AAFCon<?> con) {\r
+                       aafcon = con;\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       try {\r
+                               TreeMap<ByteArrayHolder, String> newCertsMap = new TreeMap<ByteArrayHolder,String>();\r
+                               Map<String,Set<String>> newTrustMap = new TreeMap<String,Set<String>>();\r
+                               Set<String> userLookup = new HashSet<String>();\r
+                               for(String s : certIDs) {\r
+                                       userLookup.add(s);\r
+                               }\r
+                               for(String authMech : authMechanisms) {\r
+                                       Future<Users> fusr = aafcon.client(AAF_VERSION).read("/authz/users/perm/com.att.aaf.trust/"+authMech+"/authenticate", Users.class, aafcon.usersDF);\r
+                                       if(fusr.get(5000)) {\r
+                                               List<User> users = fusr.value.getUser();\r
+                                               if(users.isEmpty()) {\r
+                                                       aafcon.access.log(Level.WARN, "AAF Lookup-No IDs in Role com.att.aaf.trustForID <> "+authMech);\r
+                                               } else {\r
+                                                       aafcon.access.log(Level.INFO,"Loading Trust Authentication Info for",authMech);\r
+                                                       Set<String> hsUser = new HashSet<String>();\r
+                                                       for(User u : users) {\r
+                                                               userLookup.add(u.getId());\r
+                                                               hsUser.add(u.getId());\r
+                                                       }\r
+                                                       newTrustMap.put(authMech,hsUser);\r
+                                               }\r
+                                       } else {\r
+                                               aafcon.access.log(Level.WARN, "Could not get Users in Perm com.att.trust|tguard|authenticate",fusr.code(),fusr.body());\r
+                                       }\r
+                                       \r
+                               }\r
+                               \r
+                               for(String u : userLookup) {\r
+                                       Future<Certs> fc = aafcon.client(AAF_VERSION).read("/authn/cert/id/"+u, Certs.class, aafcon.certsDF);\r
+                                       XMLGregorianCalendar now = Chrono.timeStamp();\r
+                                       if(fc.get(5000)) {\r
+                                               List<Cert> certs = fc.value.getCert();\r
+                                               if(certs.isEmpty()) {\r
+                                                       aafcon.access.log(Level.WARN, "No Cert Associations for",u);\r
+                                               } else {\r
+                                                       for(Cert c : fc.value.getCert()) {\r
+                                                               XMLGregorianCalendar then =c.getExpires();\r
+                                                               if(then !=null && then.compare(now)>0) {\r
+                                                                       newCertsMap.put(new ByteArrayHolder(c.getFingerprint()), c.getId());\r
+                                                                       aafcon.access.log(Level.INIT,"Associating "+ c.getId() + " expiring " + Chrono.dateOnlyStamp(c.getExpires()) + " with " + c.getX500());\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       } else {\r
+                                               aafcon.access.log(Level.WARN, "Could not get Certificates for",u);\r
+                                       }\r
+                               }\r
+\r
+                               certs = newCertsMap;\r
+                               trusted = newTrustMap;\r
+                       } catch(Exception e) {\r
+                               aafcon.access.log(e, "Failure to update Certificate Identities from AAF");\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java b/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
new file mode 100644 (file)
index 0000000..7fc776a
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.client;\r
+\r
+import java.io.PrintStream;\r
+\r
+import aaf.v2_0.Error;\r
+\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.util.Vars;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class ErrMessage {\r
+       private RosettaDF<Error> errDF;\r
+       \r
+       public ErrMessage(RosettaEnv env) throws APIException {\r
+               errDF = env.newDataFactory(Error.class);\r
+       }\r
+\r
+       /**\r
+        * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.\r
+        * \r
+        * This code will create a meaningful string from this format. \r
+        * \r
+        * @param ps\r
+        * @param df\r
+        * @param r\r
+        * @throws APIException\r
+        */\r
+       public void printErr(PrintStream ps,  String attErrJson) throws APIException {\r
+               StringBuilder sb = new StringBuilder();\r
+               Error err = errDF.newData().in(TYPE.JSON).load(attErrJson).asObject();\r
+               ps.println(toMsg(sb,err));\r
+       }\r
+       \r
+       /**\r
+        * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.\r
+        * \r
+        * This code will create a meaningful string from this format. \r
+        * \r
+        * @param sb\r
+        * @param df\r
+        * @param r\r
+        * @throws APIException\r
+        */\r
+       public StringBuilder toMsg(StringBuilder sb,  String attErrJson) throws APIException {\r
+               return toMsg(sb,errDF.newData().in(TYPE.JSON).load(attErrJson).asObject());\r
+       }\r
+       \r
+       public StringBuilder toMsg(Future<?> future) {\r
+               return toMsg(new StringBuilder(),future);\r
+       }\r
+       \r
+       public StringBuilder toMsg(StringBuilder sb, Future<?> future) {\r
+               try {\r
+                       toMsg(sb,errDF.newData().in(TYPE.JSON).load(future.body()).asObject());\r
+               } catch(Exception e) {\r
+                       //just print what we can\r
+                       sb.append(future.code());\r
+                       sb.append(": ");\r
+                       sb.append(future.body());\r
+               }\r
+               return sb;\r
+       }\r
+\r
+       public StringBuilder toMsg(StringBuilder sb, Error err) {\r
+               sb.append(err.getMessageId());\r
+               sb.append(' ');\r
+               String[] vars = new String[err.getVariables().size()];\r
+               err.getVariables().toArray(vars);\r
+               Vars.convert(sb, err.getText(),vars);\r
+               return sb;\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java b/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java
new file mode 100644 (file)
index 0000000..e8a4756
--- /dev/null
@@ -0,0 +1,445 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.client;\r
+\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.GregorianCalendar;\r
+\r
+import aaf.v2_0.Approval;\r
+import aaf.v2_0.Approvals;\r
+import aaf.v2_0.CredRequest;\r
+import aaf.v2_0.Keys;\r
+import aaf.v2_0.NsRequest;\r
+import aaf.v2_0.Nss;\r
+import aaf.v2_0.Nss.Ns;\r
+import aaf.v2_0.Perm;\r
+import aaf.v2_0.PermKey;\r
+import aaf.v2_0.PermRequest;\r
+import aaf.v2_0.Perms;\r
+import aaf.v2_0.Pkey;\r
+import aaf.v2_0.Request;\r
+import aaf.v2_0.Role;\r
+import aaf.v2_0.RoleKey;\r
+import aaf.v2_0.RolePermRequest;\r
+import aaf.v2_0.RoleRequest;\r
+import aaf.v2_0.Roles;\r
+import aaf.v2_0.UserRole;\r
+import aaf.v2_0.UserRoleRequest;\r
+import aaf.v2_0.UserRoles;\r
+import aaf.v2_0.Users;\r
+import aaf.v2_0.Users.User;\r
+\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class Examples {\r
+       public static <C> String print(RosettaEnv env, String nameOrContentType, boolean optional) throws APIException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {\r
+               // Discover ClassName\r
+               String className = null;\r
+               String version = null;\r
+               TYPE type = TYPE.JSON; // default\r
+               if(nameOrContentType.startsWith("application/")) {\r
+                       for(String ct : nameOrContentType.split("\\s*,\\s*")) {\r
+                               for(String elem : ct.split("\\s*;\\s*")) {\r
+                                       if(elem.endsWith("+json")) {\r
+                                               type = TYPE.JSON;\r
+                                               className = elem.substring(elem.indexOf('/')+1, elem.length()-5);\r
+                                       } else if(elem.endsWith("+xml")) {\r
+                                               type = TYPE.XML;\r
+                                               className = elem.substring(elem.indexOf('/')+1, elem.length()-4);\r
+                                       } else if(elem.startsWith("version=")) {\r
+                                               version = elem.substring(8);\r
+                                       }\r
+                               }\r
+                               if(className!=null && version!=null)break;\r
+                       }\r
+                       if(className==null) {\r
+                               throw new APIException(nameOrContentType + " does not contain Class Information");\r
+                       }\r
+               } else {\r
+                       className = nameOrContentType;\r
+               }\r
+               \r
+               // No Void.class in aaf.v2_0 package causing errors when trying to use a newVoidv2_0\r
+               // method similar to others in this class. This makes it work, but is it right?\r
+               if ("Void".equals(className)) return "";\r
+                               \r
+               if("1.1".equals(version)) {\r
+                       version = "v1_0";\r
+               } else if(version!=null) {\r
+                       version = "v" + version.replace('.', '_');\r
+               } else {\r
+                       version = "v2_0";\r
+               }\r
+               \r
+               Class<?> cls;\r
+               try {\r
+                       cls = Examples.class.getClassLoader().loadClass("aaf."+version+'.'+className);\r
+               } catch (ClassNotFoundException e) {\r
+                       throw new APIException(e);\r
+               }\r
+               \r
+               Method meth;\r
+               try {\r
+                       meth = Examples.class.getDeclaredMethod("new"+cls.getSimpleName()+version,boolean.class);\r
+               } catch (Exception e) {\r
+                       throw new APIException("ERROR: " + cls.getName() + " does not have an Example in Code.  Request from AAF Developers");\r
+               }\r
+               \r
+               RosettaDF<C> df = env.newDataFactory(cls);\r
+               df.option(Data.PRETTY);\r
+               \r
+               Object data = meth.invoke(null,optional);\r
+               \r
+               @SuppressWarnings("unchecked")\r
+               String rv = df.newData().load((C)data).out(type).asString();\r
+//             Object obj = df.newData().in(type).load(rv).asObject();\r
+               return rv;\r
+       }\r
+       \r
+       /*\r
+        *  Set Base Class Request (easier than coding over and over)\r
+        */\r
+       private static void setOptional(Request req) {\r
+               GregorianCalendar gc = new GregorianCalendar();\r
+               req.setStart(Chrono.timeStamp(gc));\r
+               gc.add(GregorianCalendar.MONTH, 6);\r
+               req.setEnd(Chrono.timeStamp(gc));\r
+//             req.setForce("false");\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Request newRequestv2_0(boolean optional) {\r
+               Request r = new Request();\r
+               setOptional(r);\r
+               return r;\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private static RolePermRequest newRolePermRequestv2_0(boolean optional) {\r
+               RolePermRequest rpr = new RolePermRequest();\r
+               Pkey pkey = new Pkey();\r
+               pkey.setType("com.att.myns.mytype");\r
+               pkey.setInstance("myInstance");\r
+               pkey.setAction("myAction");\r
+               rpr.setPerm(pkey);\r
+               rpr.setRole("com.att.myns.myrole");\r
+               if(optional)setOptional(rpr);\r
+               return rpr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Roles newRolesv2_0(boolean optional) {\r
+               Role r;\r
+               Pkey p;\r
+               Roles rs = new Roles();\r
+               rs.getRole().add(r = new Role());\r
+               r.setName("com.att.myns.myRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               \r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+               \r
+               rs.getRole().add(r = new Role());\r
+               r.setName("com.att.myns.myOtherRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myOtherType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               \r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myOthertype");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+\r
+               return rs;\r
+       }\r
+       \r
+       \r
+       @SuppressWarnings("unused")\r
+       private static PermRequest newPermRequestv2_0(boolean optional) {\r
+               PermRequest pr = new PermRequest();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               if(optional) {\r
+                       pr.setDescription("Short and meaningful verbiage about the Permission");\r
+                       \r
+                       setOptional(pr);\r
+               }\r
+               return pr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Perm newPermv2_0(boolean optional) {\r
+               Perm pr = new Perm();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               pr.getRoles().add("com.att.myns.myRole");\r
+               pr.getRoles().add("com.att.myns.myRole2");\r
+               pr.setDescription("This is my description, and I'm sticking with it");\r
+               if(optional) {\r
+                       pr.setDescription("Short and meaningful verbiage about the Permission");\r
+               }\r
+               return pr;\r
+       }\r
+\r
+\r
+       @SuppressWarnings("unused")\r
+       private static PermKey newPermKeyv2_0(boolean optional) {\r
+               PermKey pr = new PermKey();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               return pr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Perms newPermsv2_0(boolean optional) {\r
+               Perms perms = new Perms();\r
+               Perm p;\r
+               perms.getPerm().add(p=new Perm());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               p.getRoles().add("com.att.myns.myRole");\r
+               p.getRoles().add("com.att.myns.myRole2");\r
+               \r
+\r
+               perms.getPerm().add(p=new Perm());\r
+               p.setType("com.att.myns.myOtherType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+               p.getRoles().add("com.att.myns.myRole");\r
+               p.getRoles().add("com.att.myns.myRole2");\r
+\r
+               return perms;\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static UserRoleRequest newUserRoleRequestv2_0(boolean optional) {\r
+               UserRoleRequest urr = new UserRoleRequest();\r
+               urr.setRole("com.att.myns.myRole");\r
+               urr.setUser("ab1234@csp.att.com");\r
+               if(optional) setOptional(urr);\r
+               return urr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static NsRequest newNsRequestv2_0(boolean optional) {\r
+               NsRequest nr = new NsRequest();\r
+               nr.setName("com.att.myns");\r
+               nr.getResponsible().add("ab1234@csp.att.com");\r
+               nr.getResponsible().add("cd5678@csp.att.com");\r
+               nr.getAdmin().add("zy9876@csp.att.com");\r
+               nr.getAdmin().add("xw5432@csp.att.com");                \r
+               if(optional) {\r
+                       nr.setDescription("This is my Namespace to set up");\r
+                       nr.setType("APP");\r
+                       setOptional(nr);\r
+               }\r
+               return nr;\r
+       }\r
+       \r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Nss newNssv2_0(boolean optional) {\r
+               Ns ns;\r
+               \r
+               Nss nss = new Nss();\r
+               nss.getNs().add(ns = new Nss.Ns());\r
+               ns.setName("com.att.myns");\r
+               ns.getResponsible().add("ab1234@csp.att.com");\r
+               ns.getResponsible().add("cd5678@csp.att.com");\r
+               ns.getAdmin().add("zy9876@csp.att.com");\r
+               ns.getAdmin().add("xw5432@csp.att.com");\r
+               ns.setDescription("This is my Namespace to set up");\r
+               \r
+               nss.getNs().add(ns = new Nss.Ns());\r
+               ns.setName("com.att.myOtherNs");\r
+               ns.getResponsible().add("ab1234@csp.att.com");\r
+               ns.getResponsible().add("cd5678@csp.att.com");\r
+               ns.getAdmin().add("zy9876@csp.att.com");\r
+               ns.getAdmin().add("xw5432@csp.att.com");                \r
+                       \r
+               return nss;\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private static RoleRequest newRoleRequestv2_0(boolean optional) {\r
+               RoleRequest rr = new RoleRequest();\r
+               rr.setName("com.att.myns.myRole");\r
+               if(optional) {\r
+                       rr.setDescription("This is my Role");\r
+                       setOptional(rr);\r
+               }\r
+               return rr;\r
+       }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static CredRequest newCredRequestv2_0(boolean optional) {\r
+               CredRequest cr = new CredRequest();\r
+               cr.setId("myID@fully.qualified.domain");\r
+               if(optional) {\r
+                       cr.setType(2);\r
+                       cr.setEntry("0x125AB256344CE");\r
+               } else {\r
+                       cr.setPassword("This is my provisioned password");\r
+               }\r
+\r
+               return cr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Users newUsersv2_0(boolean optional) {\r
+               User user;\r
+       \r
+               Users users = new Users();\r
+               users.getUser().add(user = new Users.User());\r
+               user.setId("ab1234@csp.att.com");       \r
+               GregorianCalendar gc = new GregorianCalendar();\r
+               user.setExpires(Chrono.timeStamp(gc));\r
+               \r
+               users.getUser().add(user = new Users.User());\r
+               user.setId("zy9876@csp.att.com");       \r
+               user.setExpires(Chrono.timeStamp(gc));  \r
+                       \r
+               return users;\r
+       }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Role newRolev2_0(boolean optional) {\r
+               Role r = new Role();\r
+               Pkey p;\r
+               r.setName("com.att.myns.myRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+\r
+        return r;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static RoleKey newRoleKeyv2_0(boolean optional) {\r
+               RoleKey r = new RoleKey();\r
+               Pkey p;\r
+               r.setName("com.att.myns.myRole");\r
+        return r;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Keys newKeysv2_0(boolean optional) {\r
+               Keys ks = new Keys();\r
+               ks.getKey().add("Reponse 1");\r
+               ks.getKey().add("Response 2");\r
+        return ks;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static UserRoles newUserRolesv2_0(boolean optional) {\r
+               UserRoles urs = new UserRoles();\r
+               UserRole ur = new UserRole();\r
+               ur.setUser("xy1234");\r
+               ur.setRole("com.test.myapp.myRole");\r
+               ur.setExpires(Chrono.timeStamp());\r
+               urs.getUserRole().add(ur);\r
+               \r
+               ur = new UserRole();\r
+               ur.setUser("yx4321");\r
+               ur.setRole("com.test.yourapp.yourRole");\r
+               ur.setExpires(Chrono.timeStamp());\r
+               urs.getUserRole().add(ur);\r
+        return urs;\r
+    }\r
+\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Approvals newApprovalsv2_0(boolean optional) {\r
+               Approvals as = new Approvals();\r
+               Approval a = new Approval();\r
+               a.setApprover("MyApprover");\r
+               a.setId("MyID");\r
+               a.setMemo("My memo (and then some)");\r
+               a.setOperation("MyOperation");\r
+               a.setStatus("MyStatus");\r
+               a.setTicket("MyTicket");\r
+               a.setType("MyType");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser");\r
+               as.getApprovals().add(a);\r
+               a = new Approval();\r
+               a.setApprover("MyApprover2");\r
+               a.setId("MyID2");\r
+               a.setMemo("My memo (and then some)2");\r
+               a.setOperation("MyOperation2");\r
+               a.setStatus("MyStatus2");\r
+               a.setTicket("MyTicket2");\r
+               a.setType("MyType2");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser2");\r
+               as.getApprovals().add(a);\r
+        return as;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Approval newApprovalv2_0(boolean optional) {\r
+               Approval a = new Approval();\r
+               a.setApprover("MyApprover");\r
+               a.setId("MyID");\r
+               a.setMemo("My memo (and then some)");\r
+               a.setOperation("MyOperation");\r
+               a.setStatus("MyStatus");\r
+               a.setTicket("MyTicket");\r
+               a.setType("MyType");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser");\r
+        return a;\r
+    }\r
+\r
+       \r
+\r
+       @SuppressWarnings("unused")\r
+       private static aaf.v2_0.Error newErrorv2_0(boolean optional) {\r
+               aaf.v2_0.Error err = new aaf.v2_0.Error();\r
+               err.setMessageId("SVC1403");\r
+               err.setText("MyText %s, %s: The last three digits are usually the HTTP Code");\r
+               err.getVariables().add("Variable 1");\r
+               err.getVariables().add("Variable 2");\r
+               return err;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
new file mode 100644 (file)
index 0000000..4193d43
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.marshal;\r
+\r
+import javax.xml.datatype.XMLGregorianCalendar;\r
+\r
+import aaf.v2_0.Certs.Cert;\r
+\r
+import com.att.rosetta.marshal.FieldDateTime;\r
+import com.att.rosetta.marshal.FieldHexBinary;\r
+import com.att.rosetta.marshal.FieldString;\r
+import com.att.rosetta.marshal.ObjMarshal;\r
+\r
+public class CertMarshal extends ObjMarshal<Cert> {\r
+       public CertMarshal() {\r
+               add(new FieldHexBinary<Cert>("fingerprint") {\r
+                       @Override\r
+                       protected byte[] data(Cert t) {\r
+                               return t.getFingerprint();\r
+                       }\r
+               });\r
+\r
+               add(new FieldString<Cert>("id") {\r
+                       @Override\r
+                       protected String data(Cert t) {\r
+                               return t.getId();\r
+                       }\r
+               });\r
+\r
+               add(new FieldString<Cert>("x500") {\r
+                       @Override\r
+                       protected String data(Cert t) {\r
+                               return t.getX500();\r
+                       }\r
+               });\r
+               \r
+               add(new FieldDateTime<Cert>("expires") {\r
+                       @Override\r
+                       protected XMLGregorianCalendar data(Cert t) {\r
+                               return t.getExpires();\r
+                       }\r
+               });\r
+\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java
new file mode 100644 (file)
index 0000000..16fc580
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.marshal;\r
+\r
+import java.util.List;\r
+\r
+import aaf.v2_0.Certs;\r
+import aaf.v2_0.Certs.Cert;\r
+\r
+import com.att.rosetta.marshal.ObjArray;\r
+import com.att.rosetta.marshal.ObjMarshal;\r
+\r
+public class CertsMarshal extends ObjMarshal<Certs> {\r
+\r
+       public CertsMarshal() {\r
+               add(new ObjArray<Certs,Cert>("cert",new CertMarshal()) {\r
+                       @Override\r
+                       protected List<Cert> data(Certs t) {\r
+                               return t.getCert();\r
+                       }\r
+               });     \r
+       }\r
+\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
new file mode 100644 (file)
index 0000000..db60495
--- /dev/null
@@ -0,0 +1,207 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.lur.ConfigPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {\r
+       private AAFCon<CLIENT> con;\r
+       private String realm;\r
+       \r
+       /**\r
+        * Configure with Standard AAF properties, Stand alone\r
+        * @param con\r
+        * @throws Exception \r
+        */\r
+       // Package on purpose\r
+       AAFAuthn(AAFCon<CLIENT> con) throws Exception {\r
+               super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);\r
+               this.con = con;\r
+\r
+               try {\r
+                       setRealm();\r
+               } catch (APIException e) {\r
+                       if(e.getCause() instanceof DME2Exception) {\r
+                               // Can't contact AAF, assume default\r
+                               realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
+                       }\r
+               }\r
+               }\r
+\r
+       /**\r
+        * Configure with Standard AAF properties, but share the Cache (with AAF Lur)\r
+        * @param con\r
+        * @throws Exception \r
+        */\r
+       // Package on purpose\r
+       AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {\r
+               super(cache);\r
+               this.con = con;\r
+               try {\r
+                       setRealm();\r
+               } catch (Exception e) {\r
+                       if(e.getCause() instanceof DME2Exception) {\r
+                               access.log(e);\r
+                               // Can't contact AAF, assume default            \r
+                               realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void setRealm() throws Exception {\r
+               // Make a call without security set to get the 401 response, which\r
+               // includes the Realm of the server\r
+               // This also checks on Connectivity early on.\r
+               Future<String> fp = con.client(AAFCon.AAF_LATEST_VERSION).read("/authn/basicAuth", "text/plain");\r
+               if(fp.get(con.timeout)) {\r
+                       throw new Exception("Do not preset Basic Auth Information for AAFAuthn");\r
+               } else {\r
+                       if(fp.code()==401) {\r
+                               realm = fp.header("WWW-Authenticate");\r
+                               if(realm!=null && realm.startsWith("Basic realm=\"")) {\r
+                                       realm = realm.substring(13, realm.length()-1);\r
+                               } else {\r
+                                       realm = "unknown.com";\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Return Native Realm of AAF Instance.\r
+        * \r
+        * @return\r
+        */\r
+       public String getRealm() {\r
+               return realm;\r
+       }\r
+\r
+       /**\r
+        * Returns null if ok, or an Error String;\r
+        * \r
+        * @param user\r
+        * @param password\r
+        * @return\r
+        * @throws IOException \r
+        * @throws CadiException \r
+        * @throws Exception\r
+        */\r
+       public String validate(String user, String password) throws IOException, CadiException {\r
+               User<AAFPermission> usr = getUser(user);\r
+               if(password.startsWith("enc:???")) {\r
+                       password = access.decrypt(password, true);\r
+               }\r
+\r
+               byte[] bytes = password.getBytes();\r
+               if(usr != null && usr.principal != null && usr.principal.getName().equals(user) \r
+                               && usr.principal instanceof GetCred) {\r
+                       \r
+                       if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {\r
+                               return null;\r
+                       } else {\r
+                               remove(usr);\r
+                               usr = null;\r
+                       }\r
+               }\r
+               \r
+               AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);\r
+               // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch\r
+               // Statement\r
+               switch(cp.revalidate()) {\r
+                       case REVALIDATED:\r
+                               if(usr!=null) {\r
+                                       usr.principal = cp;\r
+                               } else {\r
+                                       addUser(new User<AAFPermission>(cp,con.timeout));\r
+                               }\r
+                               return null;\r
+                       case INACCESSIBLE:\r
+                               return "AAF Inaccessible";\r
+                       case UNVALIDATED:\r
+                               return "User/Pass combo invalid for " + user;\r
+                       case DENIED:\r
+                               return "AAF denies API for " + user;\r
+                       default: \r
+                               return "AAFAuthn doesn't handle Principal " + user;\r
+               }\r
+       }\r
+       \r
+       private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {\r
+               private long expires,timeToLive;\r
+\r
+               public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {\r
+                       super(name,pass);\r
+                       this.timeToLive = timeToLive;\r
+                       expires = timeToLive + System.currentTimeMillis();\r
+               }\r
+\r
+               public Resp revalidate() {\r
+                       if(con.isDisabled()) {\r
+                               return Resp.DENIED;\r
+                       }\r
+                       try {\r
+                               Miss missed = missed(getName());\r
+                               if(missed==null || missed.mayContinue(getCred())) {\r
+                                       Rcli<CLIENT> client = con.client(AAFCon.AAF_LATEST_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));\r
+                                       Future<String> fp = client.read(\r
+                                                       "/authn/basicAuth",\r
+                                                       "text/plain"\r
+                                                       );\r
+                                       if(fp.get(con.timeout)) {\r
+                                               expires = System.currentTimeMillis() + timeToLive;\r
+                                               addUser(new User<AAFPermission>(this, expires));\r
+                                               return Resp.REVALIDATED;\r
+                                       } else {\r
+                                               addMiss(getName(), getCred());\r
+                                               return Resp.UNVALIDATED;\r
+                                       }\r
+                               } else {\r
+                                       return Resp.UNVALIDATED;\r
+                               }\r
+                       } catch (Exception e) {\r
+                               con.access.log(e);\r
+                               return Resp.INACCESSIBLE;\r
+                       }\r
+               }\r
+\r
+               public long expires() {\r
+                       return expires;\r
+               }\r
+       };\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
new file mode 100644 (file)
index 0000000..573c85e
--- /dev/null
@@ -0,0 +1,396 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.URI;\r
+import java.security.Principal;\r
+import java.util.Map;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.http.HttpServletRequest;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CadiWrap;\r
+import com.att.cadi.Connector;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.marshal.CertsMarshal;\r
+import com.att.cadi.client.AbsBasicAuth;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.util.Vars;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.util.Split;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+import aaf.v2_0.Certs;\r
+import aaf.v2_0.Error;\r
+import aaf.v2_0.Perms;\r
+import aaf.v2_0.Users;\r
+\r
+public abstract class AAFCon<CLIENT> implements Connector {\r
+       public static final String AAF_LATEST_VERSION = "2.0";\r
+\r
+       final public PropAccess access;\r
+       // Package access\r
+       final public int timeout, cleanInterval, connTimeout;\r
+       final public int highCount, userExpires, usageRefreshTriggerCount;\r
+       private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();\r
+       final public RosettaDF<Perms> permsDF;\r
+       final public RosettaDF<Certs> certsDF;\r
+       final public RosettaDF<Users> usersDF;\r
+       final public RosettaDF<Error> errDF;\r
+       private String realm;\r
+       public final String app;\r
+       protected SecuritySetter<CLIENT> ss;\r
+       protected SecurityInfoC<CLIENT> si;\r
+\r
+       private DisableCheck disableCheck;\r
+\r
+       private AAFLurPerm lur;\r
+\r
+       private RosettaEnv env;\r
+       protected abstract URI initURI();\r
+       protected abstract void setInitURI(String uriString) throws CadiException;\r
+\r
+       /**\r
+        * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)\r
+        * \r
+        * @param apiVersion\r
+        * @return\r
+        * @throws CadiException\r
+        */\r
+       public Rcli<CLIENT> client(String apiVersion) throws CadiException {\r
+               Rcli<CLIENT> client = clients.get(apiVersion);\r
+               if(client==null) {\r
+                       client = rclient(initURI(),ss);\r
+                       client.apiVersion(apiVersion)\r
+                                 .readTimeout(connTimeout);\r
+                       clients.put(apiVersion, client);\r
+               } \r
+               return client;\r
+       }\r
+       \r
+       /**\r
+        * Use this API when you have permission to have your call act as the end client's ID.\r
+        * \r
+        *  Your calls will get 403 errors if you do not have this permission.  it is a special setup, rarely given.\r
+        * \r
+        * @param apiVersion\r
+        * @param req\r
+        * @return\r
+        * @throws CadiException\r
+        */\r
+       public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {\r
+               Rcli<CLIENT> cl = client(apiVersion);\r
+               return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));\r
+       }\r
+       \r
+       protected AAFCon(AAFCon<CLIENT> copy) {\r
+               access = copy.access;\r
+               timeout = copy.timeout;\r
+               cleanInterval = copy.cleanInterval;\r
+               connTimeout = copy.connTimeout;\r
+               highCount = copy.highCount;\r
+               userExpires = copy.userExpires;\r
+               usageRefreshTriggerCount = copy.usageRefreshTriggerCount;\r
+               permsDF = copy.permsDF;\r
+               certsDF = copy.certsDF;\r
+               usersDF = copy.usersDF;\r
+               errDF = copy.errDF;\r
+               app = copy.app;\r
+               ss = copy.ss;\r
+               si = copy.si;\r
+               env = copy.env;\r
+               disableCheck = copy.disableCheck;\r
+               realm = copy.realm;\r
+       }\r
+       \r
+       protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{\r
+               if(tag==null) {\r
+                       throw new CadiException("AAFCon cannot be constructed with a tag=null");\r
+               }\r
+               try {\r
+                       this.access = access;\r
+                       this.si = si;\r
+                       this.ss = si.defSS;\r
+                       if(ss==null) {\r
+                               String mechid = access.getProperty(Config.AAF_MECHID, null);\r
+                               String encpass = access.getProperty(Config.AAF_MECHPASS, null);\r
+                               if(encpass==null) {\r
+                                       String alias = access.getProperty(Config.CADI_ALIAS, mechid);\r
+                                       if(alias==null) {\r
+                                               throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");\r
+                                       }\r
+                                       set(si.defSS=x509Alias(alias));\r
+                               } else {\r
+                                       if(mechid!=null && encpass !=null) {\r
+                                               set(si.defSS=basicAuth(mechid, encpass));\r
+                                       } else {\r
+                                               set(si.defSS=new SecuritySetter<CLIENT>() {\r
+                                                       \r
+                                                       @Override\r
+                                                       public String getID() {\r
+                                                               return "";\r
+                                                       }\r
+                       \r
+                                                       @Override\r
+                                                       public void setSecurity(CLIENT client) throws CadiException {\r
+                                                               throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");\r
+                                                       }\r
+\r
+                                                       @Override\r
+                                                       public int setLastResponse(int respCode) {\r
+                                                               return 0;\r
+                                                       }\r
+                                               });\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));\r
+                       cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));\r
+                       highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());\r
+                       connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());\r
+                       userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());\r
+                       usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based\r
+       \r
+                       String str = access.getProperty(tag,null);\r
+                       if(str==null) {\r
+                               throw new CadiException(tag + " property is required.");\r
+                       }\r
+                       setInitURI(str);\r
+       \r
+                       app=reverseDomain(ss.getID());\r
+                       realm="openecomp.org";\r
+       \r
+                       env = new RosettaEnv();\r
+                       permsDF = env.newDataFactory(Perms.class);\r
+                       usersDF = env.newDataFactory(Users.class);\r
+                       certsDF = env.newDataFactory(Certs.class);\r
+                       certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling\r
+                       errDF = env.newDataFactory(Error.class);\r
+               } catch (APIException e) {\r
+                       throw new CadiException("AAFCon cannot be configured",e);\r
+               }\r
+       }\r
+       \r
+       public RosettaEnv env() {\r
+               return env;\r
+       }\r
+       \r
+       /**\r
+        * Return the backing AAFCon, if there is a Lur Setup that is AAF.\r
+        * \r
+        * If there is no AAFLur setup, it will return "null"\r
+        * @param servletRequest\r
+        * @return\r
+        */\r
+       public static final AAFCon<?> obtain(Object servletRequest) {\r
+               if(servletRequest instanceof CadiWrap) {\r
+                       Lur lur = ((CadiWrap)servletRequest).getLur();\r
+                       if(lur != null) {\r
+                               if(lur instanceof EpiLur) {\r
+                                       AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);\r
+                                       if(aal!=null) {\r
+                                               return aal.aaf;\r
+                                       }\r
+                               } else {\r
+                                       if(lur instanceof AbsAAFLur) {\r
+                                               return ((AbsAAFLur<?>)lur).aaf;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       public abstract AAFCon<CLIENT> clone(String url) throws CadiException;\r
+       \r
+       public AAFAuthn<CLIENT> newAuthn() throws APIException {\r
+               try {\r
+                       return new AAFAuthn<CLIENT>(this);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {\r
+               try {\r
+                       return new AAFAuthn<CLIENT>(this,c);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       public AAFLurPerm newLur() throws CadiException {\r
+               try {\r
+                       if(lur==null) {\r
+                               return new AAFLurPerm(this);\r
+                       } else {\r
+                               return new AAFLurPerm(this,lur);\r
+                       }\r
+               } catch (CadiException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+       \r
+       public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {\r
+               try {\r
+                       return new AAFLurPerm(this,c);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Take a Fully Qualified User, and get a Namespace from it.\r
+        * @param user\r
+        * @return\r
+        */\r
+       public static String reverseDomain(String user) {\r
+               StringBuilder sb = null;\r
+               String[] split = Split.split('.',user);\r
+               int at;\r
+               for(int i=split.length-1;i>=0;--i) {\r
+                       if(sb == null) {\r
+                               sb = new StringBuilder();\r
+                       } else {\r
+                               sb.append('.');\r
+                       }\r
+\r
+                       if((at = split[i].indexOf('@'))>0) {\r
+                               sb.append(split[i].subSequence(at+1, split[i].length()));\r
+                       } else {\r
+                               sb.append(split[i]);\r
+                       }\r
+               }\r
+               \r
+               return sb==null?"":sb.toString();\r
+       }\r
+\r
+       protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;\r
+       \r
+       public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;\r
+\r
+\r
+       public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;\r
+\r
+\r
+       public String getRealm() {\r
+               return realm;\r
+\r
+       }\r
+\r
+       public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {\r
+               this.ss = ss;\r
+               if(ss instanceof AbsBasicAuth) {\r
+                       disableCheck = (ss instanceof AbsBasicAuth)?\r
+                       new DisableCheck() {\r
+                               AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;\r
+                               @Override\r
+                               public boolean isDisabled() {\r
+                                       return aba.isDenied();\r
+                               }\r
+                       }:\r
+                       new DisableCheck() {\r
+                               @Override\r
+                               public boolean isDisabled() {\r
+                                       return this.isDisabled();\r
+                               }\r
+                       };\r
+               }\r
+               for(Rcli<CLIENT> client : clients.values()) {\r
+                       client.setSecuritySetter(ss);\r
+               }\r
+               return ss;\r
+       }\r
+       \r
+       public SecurityInfoC<CLIENT> securityInfo() {\r
+               return si;\r
+       }\r
+\r
+       public String defID() {\r
+               if(ss!=null) {\r
+                       return ss.getID();\r
+               }\r
+               return "unknown";\r
+       }\r
+       \r
+       public void invalidate() throws CadiException {\r
+               for(Rcli<CLIENT> client : clients.values()) {\r
+                       client.invalidate();\r
+                       clients.remove(client);\r
+               }\r
+       }\r
+\r
+       public String readableErrMsg(Future<?> f) {\r
+               String text = f.body();\r
+               if(text==null || text.length()==0) {\r
+                       text = f.code() + ": **No Message**";\r
+               } else if(text.contains("%")) {\r
+                       try {\r
+                               Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();\r
+                               return Vars.convert(err.getText(),err.getVariables());\r
+                       } catch (APIException e){\r
+                               // just return the body below\r
+                       }\r
+               }\r
+               return text;\r
+       }\r
+       \r
+       private interface DisableCheck {\r
+               public boolean isDisabled();\r
+       };\r
+       \r
+       public boolean isDisabled() {\r
+               return disableCheck.isDisabled();\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
new file mode 100644 (file)
index 0000000..7092613
--- /dev/null
@@ -0,0 +1,224 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.net.ConnectException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.security.GeneralSecurityException;\r
+import java.security.Principal;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.dme2.DME2BasicAuth;\r
+import com.att.cadi.dme2.DME2TransferSS;\r
+import com.att.cadi.dme2.DME2x509SS;\r
+import com.att.cadi.dme2.DRcli;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFConDME2 extends AAFCon<DME2Client>{\r
+       private DME2Manager manager;\r
+       private boolean isProxy;\r
+       private URI initURI;\r
+\r
+       public AAFConDME2(PropAccess access) throws CadiException, GeneralSecurityException, IOException{\r
+               super(access,Config.AAF_URL,new SecurityInfoC<DME2Client> (access));\r
+               manager = newManager(access);\r
+               setIsProxy();\r
+       }\r
+       \r
+       public AAFConDME2(PropAccess access, String url) throws CadiException, GeneralSecurityException, IOException{\r
+               super(access,url,new SecurityInfoC<DME2Client> (access));\r
+               manager = newManager(access);\r
+               setIsProxy();\r
+       }\r
+\r
+       public AAFConDME2(PropAccess access, SecurityInfoC<DME2Client> si) throws CadiException {\r
+               super(access,Config.AAF_URL,si);\r
+               manager = newManager(access);\r
+               setIsProxy();\r
+       }\r
+\r
+       public AAFConDME2(PropAccess access, String url, SecurityInfoC<DME2Client> si) throws CadiException {\r
+               super(access,url,si);\r
+               manager = newManager(access);\r
+               setIsProxy();\r
+       }\r
+\r
+       /**\r
+       *  Construct a Connector based on the AAF one.  This is for remote access to OTHER than AAF,\r
+       *  but using Credentials, etc\r
+       */ \r
+       private AAFConDME2(AAFCon<DME2Client> aafcon, String url) throws CadiException {\r
+               super(aafcon);\r
+               try {\r
+                       initURI = new URI(url);\r
+               } catch (URISyntaxException e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               manager = newManager(access);\r
+       }\r
+       \r
+       /**\r
+       *  Create a Connector based on the AAF one.  This is for remote access to OTHER than AAF,\r
+       *  but using Credentials, etc\r
+       */ \r
+       public AAFCon<DME2Client> clone(String url) throws CadiException {\r
+               return new AAFConDME2(this,url);\r
+       }\r
+       \r
+       private void setIsProxy() {\r
+               String str;\r
+               if((str=access.getProperty(Config.AAF_URL, null))!=null) {\r
+                       isProxy = str.contains("service=com.att.authz.authz-gw/version=");\r
+               }\r
+       }\r
+\r
+       private DME2Manager newManager(PropAccess access) throws CadiException {\r
+               Properties props = access.getDME2Properties();\r
+               // Critical that TLS Settings not ignored\r
+               try {\r
+                       return new DME2Manager("AAFCon",props);\r
+               } catch (DME2Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)\r
+        */\r
+       @Override\r
+       public SecuritySetter<DME2Client> basicAuth(String user, String password) throws CadiException {\r
+               if(password.startsWith("enc:???")) {\r
+                       try {\r
+                               password = access.decrypt(password, true);\r
+                       } catch (IOException e) {\r
+                               throw new CadiException("Error Decrypting Password",e);\r
+                       }\r
+               }\r
+\r
+               try {\r
+                       return set(new DME2BasicAuth(user,password,si));\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error setting up DME2BasicAuth",e);\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)\r
+        */\r
+       @Override\r
+       protected Rcli<DME2Client> rclient(URI uri, SecuritySetter<DME2Client> ss) {\r
+               DRcli dc = new DRcli(uri, ss);\r
+               dc.setProxy(isProxy);\r
+               dc.setManager(manager);\r
+               return dc;\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> transferSS(Principal principal) throws CadiException {\r
+               try {\r
+                       return principal==null?ss:new DME2TransferSS(principal, app, si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating DME2TransferSS",e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> basicAuthSS(BasicPrincipal principal) throws CadiException {\r
+               try {\r
+                       return new DME2BasicAuth(principal,si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating DME2BasicAuth",e);\r
+               }\r
+\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> x509Alias(String alias) throws CadiException {\r
+               try {\r
+                       presetProps(access, alias);\r
+                       return new DME2x509SS(alias,si);\r
+               } catch (Exception e) {\r
+                       throw new CadiException("Error creating DME2x509SS",e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               // NOTE: DME2 had Retry Logic embedded lower.  \r
+               try {\r
+                       return (retryable.code(rclient(initURI,ss)));\r
+               } catch (ConnectException e) {\r
+                       // DME2 should catch\r
+                       try {\r
+                               manager.refresh();\r
+                       } catch (Exception e1) {\r
+                               throw new CadiException(e1);\r
+                       }\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+       \r
+       public static void presetProps(PropAccess access, String alias) throws IOException {\r
+               System.setProperty(Config.AFT_DME2_CLIENT_SSL_CERT_ALIAS, alias);\r
+               if(System.getProperty(Config.AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {\r
+                       access.getDME2Properties();\r
+               }\r
+\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()\r
+        */\r
+       @Override\r
+       protected URI initURI() {\r
+               return initURI;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)\r
+        */\r
+       @Override\r
+       protected void setInitURI(String uriString) throws CadiException {\r
+               try {\r
+                       initURI = new URI(uriString);\r
+               } catch (URISyntaxException e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
new file mode 100644 (file)
index 0000000..5454773
--- /dev/null
@@ -0,0 +1,187 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.security.GeneralSecurityException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.AbsTransferSS;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.http.HMangr;\r
+import com.att.cadi.http.HRcli;\r
+import com.att.cadi.http.HTransferSS;\r
+import com.att.cadi.http.HX509SS;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFConHttp extends AAFCon<HttpURLConnection> {\r
+       private final HMangr hman;\r
+\r
+       public AAFConHttp(PropAccess access) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(Config.AAF_URL,null)));\r
+       }\r
+\r
+       public AAFConHttp(PropAccess access, String tag) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,tag,new SecurityInfoC<HttpURLConnection>(access));\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(tag,null)));\r
+       }\r
+\r
+       public AAFConHttp(PropAccess access, String urlTag, SecurityInfoC<HttpURLConnection> si) throws CadiException {\r
+               super(access,urlTag,si);\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(urlTag,null)));\r
+       }\r
+\r
+       public AAFConHttp(PropAccess access, Locator<URI> locator) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));\r
+               hman = new HMangr(access,locator);\r
+       }\r
+\r
+       public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si) throws CadiException {\r
+               super(access,Config.AAF_URL,si);\r
+               hman = new HMangr(access,locator);\r
+       }\r
+\r
+       public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si, String tag) throws CadiException {\r
+               super(access,tag,si);\r
+               hman = new HMangr(access, locator);\r
+       }\r
+       \r
+       private AAFConHttp(AAFCon<HttpURLConnection> aafcon, String url) {\r
+               super(aafcon);\r
+               hman = new HMangr(aafcon.access,Config.loadLocator(access, url));\r
+       }\r
+\r
+       @Override\r
+       public AAFCon<HttpURLConnection> clone(String url) {\r
+               return new AAFConHttp(this,url);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)\r
+        */\r
+       @Override\r
+       public SecuritySetter<HttpURLConnection> basicAuth(String user, String password) throws CadiException {\r
+               if(password.startsWith("enc:???")) {\r
+                       try {\r
+                               password = access.decrypt(password, true);\r
+                       } catch (IOException e) {\r
+                               throw new CadiException("Error decrypting password",e);\r
+                       }\r
+               }\r
+               try {\r
+                       return new HBasicAuthSS(user,password,si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating HBasicAuthSS",e);\r
+               }\r
+       }\r
+\r
+       public SecuritySetter<HttpURLConnection> x509Alias(String alias) throws APIException, CadiException {\r
+               try {\r
+                       return set(new HX509SS(alias,si));\r
+               } catch (Exception e) {\r
+                       throw new CadiException("Error creating X509SS",e);\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)\r
+        */\r
+       @Override\r
+       protected Rcli<HttpURLConnection> rclient(URI ignoredURI, SecuritySetter<HttpURLConnection> ss) throws CadiException {\r
+               if(hman.loc==null) {\r
+                       throw new CadiException("No Locator set in AAFConHttp"); \r
+               }\r
+               try {\r
+                       return new HRcli(hman, hman.loc.best() ,ss);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public AbsTransferSS<HttpURLConnection> transferSS(Principal principal) throws CadiException {\r
+               return new HTransferSS(principal, app,si);\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuthSS(java.security.Principal)\r
+        */\r
+       @Override\r
+       public SecuritySetter<HttpURLConnection> basicAuthSS(BasicPrincipal principal) throws CadiException {\r
+               try {\r
+                       return new HBasicAuthSS(principal,si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating HBasicAuthSS",e);\r
+               }\r
+       }\r
+\r
+       public HMangr hman() {\r
+               return hman;\r
+       }\r
+\r
+       @Override\r
+       public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               return hman.best(ss, (Retryable<RET>)retryable);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()\r
+        */\r
+       @Override\r
+       protected URI initURI() {\r
+               try {\r
+                       Item item = hman.loc.best();\r
+                       if(item!=null) {\r
+                               return hman.loc.get(item);\r
+                       }\r
+               } catch (LocatorException e) {\r
+                       access.log(e, "Error in AAFConHttp obtaining initial URI");\r
+               }\r
+               return null;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)\r
+        */\r
+       @Override\r
+       protected void setInitURI(String uriString) throws CadiException {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+       \r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
new file mode 100644 (file)
index 0000000..db03347
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.ConnectException;\r
+import java.net.URISyntaxException;\r
+import java.security.Principal;\r
+import java.util.Map;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.lur.LocalPermission;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Split;\r
+\r
+import aaf.v2_0.Perm;\r
+import aaf.v2_0.Perms;\r
+\r
+/**\r
+ * Use AAF Service as Permission Service.\r
+ * \r
+ * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.\r
+ * \r
+ * If you want a simple Role Lur, use AAFRoleLur\r
+ * \r
+ *\r
+ */\r
+public class AAFLurPerm extends AbsAAFLur<AAFPermission> {\r
+       /**\r
+        *  Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this\r
+        *  point by AAF.  There is no "domain", aka, no "@att.com" in "ab1234@att.com".  \r
+        *  \r
+        *  The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.\r
+        *  Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely\r
+        * @throws APIException \r
+        * @throws URISyntaxException \r
+        * @throws DME2Exception \r
+        */\r
+       // Package on purpose\r
+       AAFLurPerm(AAFCon<?> con) throws CadiException, DME2Exception, URISyntaxException, APIException {\r
+               super(con);\r
+       }\r
+\r
+       // Package on purpose\r
+       AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws DME2Exception, URISyntaxException, APIException {\r
+               super(con,auc);\r
+       }\r
+\r
+       protected User<AAFPermission> loadUser(Principal p)  {\r
+               // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't \r
+               // have domains.  We are going to make the Transitive Class (see this.transmutative) to convert\r
+               Principal principal = transmutate.mutate(p);\r
+               if(principal==null)return null; // if not a valid Transmutated credential, don't bother calling...\r
+               return loadUser(p, p.getName());\r
+       }\r
+       \r
+       protected User<AAFPermission> loadUser(String name) {\r
+               return loadUser((Principal)null, name);\r
+       }\r
+       \r
+       private User<AAFPermission> loadUser(final Principal prin, final String name) {\r
+               \r
+               //TODO Create a dynamic way to declare domains supported.\r
+               final long start = System.nanoTime();\r
+               final boolean[] success = new boolean[]{false};\r
+               \r
+//             new Exception("loadUser").printStackTrace();\r
+               try {\r
+                       return aaf.best(new Retryable<User<AAFPermission>>() {\r
+                               @Override\r
+                               public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {\r
+                                       Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);\r
+                                       \r
+                                       // In the meantime, lookup User, create if necessary\r
+                                       User<AAFPermission> user = getUser(name);\r
+                                       Principal p;\r
+                                       if(prin == null) {\r
+                                               p = new Principal() {// Create a holder for lookups\r
+                                                       private String n = name;\r
+                                                       public String getName() {\r
+                                                               return n;\r
+                                                       }\r
+                                               };\r
+                                       } else {\r
+                                               p = prin;\r
+                                       }\r
+                                       \r
+                                       if(user==null) {\r
+                                               addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password\r
+                                       }\r
+                                       \r
+                                       // OK, done all we can, now get content\r
+                                       if(fp.get(aaf.timeout)) {\r
+                                               success[0]=true;\r
+                                               Map<String, Permission> newMap = user.newMap();\r
+                                               boolean willLog = aaf.access.willLog(Level.DEBUG);\r
+                                               for(Perm perm : fp.value.getPerm()) {\r
+                                                       user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));\r
+                                                       if(willLog) {\r
+                                                               aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');\r
+                                                       }\r
+                                               }\r
+                                               user.setMap(newMap);\r
+                                               user.renewPerm();\r
+                                       } else {\r
+                                               int code;\r
+                                               switch(code=fp.code()) {\r
+                                                       case 401:\r
+                                                               aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");\r
+                                                               break;\r
+                                                       default:\r
+                                                               aaf.access.log(Access.Level.ERROR, code, fp.body());\r
+                                               }\r
+                                       }\r
+\r
+                                       return user;\r
+                               }\r
+                       });\r
+               } catch (Exception e) {\r
+                       aaf.access.log(e,"Calling","/authz/perms/user/"+name);\r
+                       success[0]=false;\r
+                       return null;\r
+               } finally {\r
+                       float time = (System.nanoTime()-start)/1000000f;\r
+                       aaf.access.log(Level.INFO, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");\r
+               }\r
+       }\r
+\r
+       public Resp reload(User<AAFPermission> user) {\r
+               final String name = user.principal.getName();\r
+               long start = System.nanoTime();\r
+               boolean success = false;\r
+               try {\r
+                       Future<Perms> fp = aaf.client(AAFCon.AAF_LATEST_VERSION).read(\r
+                                       "/authz/perms/user/"+name,\r
+                                       aaf.permsDF\r
+                                       );\r
+                       \r
+                       // OK, done all we can, now get content\r
+                       if(fp.get(aaf.timeout)) {\r
+                               success = true;\r
+                               Map<String,Permission> newMap = user.newMap(); \r
+                               boolean willLog = aaf.access.willLog(Level.DEBUG);\r
+                               for(Perm perm : fp.value.getPerm()) {\r
+                                       user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));\r
+                                       if(willLog) {\r
+                                               aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());\r
+                                       }\r
+                               }\r
+                               user.renewPerm();\r
+                               return Resp.REVALIDATED;\r
+                       } else {\r
+                               int code;\r
+                               switch(code=fp.code()) {\r
+                                       case 401:\r
+                                               aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");\r
+                                               break;\r
+                                       default:\r
+                                               aaf.access.log(Access.Level.ERROR, code, fp.body());\r
+                               }\r
+                               return Resp.UNVALIDATED;\r
+                       }\r
+               } catch (Exception e) {\r
+                       aaf.access.log(e,"Calling","/authz/perms/user/"+name);\r
+                       return Resp.INACCESSIBLE;\r
+               } finally {\r
+                       float time = (System.nanoTime()-start)/1000000f;\r
+                       aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected boolean isCorrectPermType(Permission pond) {\r
+               return pond instanceof AAFPermission;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Lur#createPerm(java.lang.String)\r
+        */\r
+       @Override\r
+       public Permission createPerm(String p) {\r
+               String[] params = Split.split('|', p);\r
+               if(params.length==3) {\r
+                       return new AAFPermission(params[0],params[1],params[2]);\r
+               } else {\r
+                       return new LocalPermission(p);\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
new file mode 100644 (file)
index 0000000..35df38f
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.CachedBasicPrincipal;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+import com.att.cadi.taf.basic.BasicHttpTafResp;\r
+\r
+public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {\r
+//     private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";\r
+//     private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";\r
+       private AAFCon<CLIENT> aaf;\r
+       private boolean warn;\r
+\r
+       public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {\r
+               super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);\r
+               aaf = con;\r
+               warn = turnOnWarning;\r
+       }\r
+\r
+       public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {\r
+               super(other);\r
+               aaf = con;\r
+               warn = turnOnWarning;\r
+       }\r
+\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               //TODO Do we allow just anybody to validate?\r
+\r
+               // Note: Either Carbon or Silicon based LifeForms ok\r
+               String authz = req.getHeader("Authorization");\r
+               if(authz != null && authz.startsWith("Basic ")) {\r
+                       if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");\r
+                       try {\r
+                               CachedBasicPrincipal bp;\r
+                               if(req.getUserPrincipal() instanceof CachedBasicPrincipal) {\r
+                                       bp = (CachedBasicPrincipal)req.getUserPrincipal();\r
+                               } else {\r
+                                       bp = new CachedBasicPrincipal(this,authz,aaf.getRealm(),aaf.userExpires);\r
+                               }\r
+                               // First try Cache\r
+                               User<AAFPermission> usr = getUser(bp);\r
+                               if(usr != null && usr.principal != null) {\r
+                                       if(usr.principal instanceof GetCred) {\r
+                                               if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {\r
+                                                       return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               Miss miss = missed(bp.getName());\r
+                               if(miss!=null && !miss.mayContinue(bp.getCred())) {\r
+                                       return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                       "User/Pass Retry limit exceeded"), \r
+                                                       RESP.FAIL,resp,aaf.getRealm(),true);\r
+                               }\r
+                               \r
+                               Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.basicAuthSS(bp));\r
+                               Future<String> fp = userAAF.read("/authn/basicAuth", "text/plain");\r
+                               if(fp.get(aaf.timeout)) {\r
+                                       if(usr!=null) {\r
+                                               usr.principal = bp;\r
+                                       } else {\r
+                                               addUser(new User<AAFPermission>(bp,aaf.userExpires));\r
+                                       }\r
+                                       return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);\r
+                               } else {\r
+                                       // Note: AddMiss checks for miss==null, and is part of logic\r
+                                       boolean rv= addMiss(bp.getName(),bp.getCred());\r
+                                       if(rv) {\r
+                                               return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                               "User/Pass combo invalid via AAF"), \r
+                                                               RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);\r
+                                       } else {\r
+                                               return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                               "User/Pass combo invalid via AAF - Retry limit exceeded"), \r
+                                                               RESP.FAIL,resp,aaf.getRealm(),true);\r
+                                       }\r
+                               }\r
+                       } catch (IOException e) {\r
+                               String msg = buildMsg(null,req,"Invalid Auth Token");\r
+                               aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');\r
+                               return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);\r
+                       } catch (Exception e) {\r
+                               String msg = buildMsg(null,req,"Authenticating Service unavailable");\r
+                               aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');\r
+                               return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);\r
+                       }\r
+               }\r
+               return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);\r
+       }\r
+       \r
+       private String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {\r
+               StringBuilder sb = new StringBuilder();\r
+               for(Object s : msg) {\r
+                       sb.append(s.toString());\r
+               }\r
+               if(pr!=null) {\r
+                       sb.append(" for ");\r
+                       sb.append(pr.getName());\r
+               }\r
+               sb.append(" from ");\r
+               sb.append(req.getRemoteAddr());\r
+               sb.append(':');\r
+               sb.append(req.getRemotePort());\r
+               return sb.toString();\r
+       }\r
+\r
+\r
+       \r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               //  !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal\r
+               if(prin instanceof BasicPrincipal) {\r
+                       Future<String> fp;\r
+                       try {\r
+                               Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.transferSS(prin));\r
+                               fp = userAAF.read("/authn/basicAuth", "text/plain");\r
+                               return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;\r
+                       } catch (Exception e) {\r
+                               aaf.access.log(e, "Cannot Revalidate",prin.getName());\r
+                               return Resp.INACCESSIBLE;\r
+                       }\r
+               }\r
+               return Resp.NOT_MINE;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
new file mode 100644 (file)
index 0000000..3bc4faf
--- /dev/null
@@ -0,0 +1,116 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import javax.servlet.http.HttpServletRequest ;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.principal.TrustPrincipal;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TrustNotTafResp;\r
+import com.att.cadi.taf.TrustTafResp;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.util.Split;\r
+\r
+public class AAFTrustChecker implements TrustChecker {\r
+       private final String tag, id;\r
+       private final AAFPermission perm;\r
+       private Lur lur;\r
+\r
+       /**\r
+        * \r
+        * Instance will be replaced by Identity\r
+        * @param lur \r
+        *    \r
+        * @param tag\r
+        * @param perm\r
+        */\r
+       public AAFTrustChecker(final Env env) {\r
+               tag = env.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);\r
+               id = env.getProperty(Config.CADI_ALIAS,env.getProperty(Config.AAF_MECHID)); // share between components\r
+               String str = env.getProperty(Config.CADI_TRUST_PERM);\r
+               AAFPermission temp=null;\r
+               if(str!=null) {\r
+                       String[] sp = Split.splitTrim('|', str);\r
+                       if(sp.length==3) {\r
+                               temp = new AAFPermission(sp[0],sp[1],sp[2]);\r
+                       }\r
+               }\r
+               perm=temp;\r
+       }\r
+\r
+       public AAFTrustChecker(final Access access) {\r
+               tag = access.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);\r
+               id = access.getProperty(Config.CADI_ALIAS,access.getProperty(Config.AAF_MECHID,null)); // share between components\r
+               String str = access.getProperty(Config.CADI_TRUST_PERM,null);\r
+               AAFPermission temp=null;\r
+               if(str!=null) {\r
+                       String[] sp = Split.splitTrim('|', str);\r
+                       if(sp.length==3) {\r
+                               temp = new AAFPermission(sp[0],sp[1],sp[2]);\r
+                       }\r
+               }\r
+               perm=temp;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.TrustChecker#setLur(com.att.cadi.Lur)\r
+        */\r
+       @Override\r
+       public void setLur(Lur lur) {\r
+               this.lur = lur;\r
+       }\r
+\r
+       @Override\r
+       public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {\r
+               String user_info = req.getHeader(tag);\r
+               if(user_info !=null ) {\r
+                       String[] info = Split.split(',', user_info);\r
+                       if(info.length>0) {\r
+                               String[] flds = Split.splitTrim(':',info[0]);\r
+                               if(flds.length>3 && "AS".equals(flds[3])) { // is it set for "AS"\r
+                                       String pn = tresp.getPrincipal().getName();\r
+                                       if(pn.equals(id)  // We do trust our own App Components: if a trust entry is made with self, always accept\r
+                                          || lur.fish(tresp.getPrincipal(), perm)) { // Have Perm set by Config.CADI_TRUST_PERM\r
+                                               return new TrustTafResp(tresp,\r
+                                                               new TrustPrincipal(tresp.getPrincipal(), flds[0]),\r
+                                                               "  " + flds[0] + " validated using " + flds[2] + " by " + flds[1] + ','\r
+                                                       );\r
+                                       } else if(pn.equals(flds[0])) { // Ignore if same identity \r
+                                               return tresp;\r
+                                       } else {\r
+                                               return new TrustNotTafResp(tresp, tresp.getPrincipal().getName() + " requested trust as "\r
+                                                               + flds[0] + ", but does not have Authorization");\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return tresp;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
new file mode 100644 (file)
index 0000000..8626588
--- /dev/null
@@ -0,0 +1,269 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.URISyntaxException;\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachingLur;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.StrLur;\r
+import com.att.cadi.Transmutate;\r
+import com.att.cadi.User;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.AAFTransmutate;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Split;\r
+\r
+public abstract class AbsAAFLur<PERM extends Permission> extends AbsUserCache<PERM> implements StrLur, CachingLur<PERM> {\r
+       protected static final byte[] BLANK_PASSWORD = new byte[0];\r
+       protected static final Transmutate<Principal> transmutate = new AAFTransmutate();\r
+       private String[] debug = null;\r
+       public AAFCon<?> aaf;\r
+       private String[] supports;\r
+\r
+       public AbsAAFLur(AAFCon<?> con) throws DME2Exception, URISyntaxException, APIException {\r
+               super(con.access, con.cleanInterval, con.highCount, con.usageRefreshTriggerCount);\r
+               aaf = con;\r
+               setLur(this);\r
+               supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");\r
+       }\r
+\r
+       public AbsAAFLur(AAFCon<?> con, AbsUserCache<PERM> auc) throws DME2Exception, URISyntaxException, APIException {\r
+               super(auc);\r
+               aaf = con;\r
+               setLur(this);\r
+               supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");\r
+       }\r
+\r
+       @Override\r
+       public void setDebug(String ids) {\r
+               this.debug = ids==null?null:Split.split(',', ids);\r
+       }\r
+       \r
+       protected abstract User<PERM> loadUser(Principal bait);\r
+       protected abstract User<PERM> loadUser(String name);\r
+       public final boolean supports(String userName) {\r
+               if(userName!=null) {\r
+                       for(String s : supports) {\r
+                               if(userName.endsWith(s))\r
+                                       return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       protected abstract boolean isCorrectPermType(Permission pond);\r
+       \r
+       // This is where you build AAF CLient Code.  Answer the question "Is principal "bait" in the "pond"\r
+       public boolean fish(Principal bait, Permission pond) {\r
+               return fish(bait.getName(), pond);\r
+       }\r
+\r
+       public void fishAll(Principal bait, List<Permission> perms) {\r
+               fishAll(bait.getName(),perms);\r
+       }\r
+\r
+       // This is where you build AAF CLient Code.  Answer the question "Is principal "bait" in the "pond"\r
+       public boolean fish(String bait, Permission pond) {\r
+               if(isDebug(bait)) {\r
+                       boolean rv = false;\r
+                       StringBuilder sb = new StringBuilder("Log for ");\r
+                       sb.append(bait);\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser is not in Cache");\r
+                               } else {\r
+                                       if(user.noPerms())sb.append("\n\tUser has no Perms");\r
+                                       if(user.permExpired()) {\r
+                                               sb.append("\n\tUser's perm expired [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       } else {\r
+                                               sb.append("\n\tUser's perm expires [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       }\r
+                               }\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                                       sb.append("\n\tloadUser called");\r
+                               }\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser was not Loaded");\r
+                               } else if(user.contains(pond)) {\r
+                                       sb.append("\n\tUser contains ");\r
+                                       sb.append(pond.getKey());\r
+                                       rv = true;\r
+                               } else {\r
+                                       sb.append("\n\tUser does not contain ");\r
+                                       sb.append(pond.getKey());\r
+                                       List<Permission> perms = new ArrayList<Permission>();\r
+                                       user.copyPermsTo(perms);\r
+                                       for(Permission p : perms) {\r
+                                               sb.append("\n\t\t");\r
+                                               sb.append(p.getKey());\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               sb.append("AAF Lur does not support [");\r
+                               sb.append(bait);\r
+                               sb.append("]");\r
+                       }\r
+                       aaf.access.log(Level.INFO, sb);\r
+                       return rv;\r
+               } else {\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                               }\r
+                               return user==null?false:user.contains(pond);\r
+                       }\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       public void fishAll(String bait, List<Permission> perms) {\r
+               if(isDebug(bait)) {\r
+                       StringBuilder sb = new StringBuilder("Log for ");\r
+                       sb.append(bait);\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser is not in Cache");\r
+                               } else {\r
+                                       if(user.noPerms())sb.append("\n\tUser has no Perms");\r
+                                       if(user.permExpired()) {\r
+                                               sb.append("\n\tUser's perm expired [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       } else {\r
+                                               sb.append("\n\tUser's perm expires [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       }\r
+                               }\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                                       sb.append("\n\tloadUser called");\r
+                               }\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser was not Loaded");\r
+                               } else {\r
+                                       sb.append("\n\tCopying Perms ");\r
+                                       user.copyPermsTo(perms);\r
+                                       for(Permission p : perms) {\r
+                                               sb.append("\n\t\t");\r
+                                               sb.append(p.getKey());\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               sb.append("AAF Lur does not support [");\r
+                               sb.append(bait);\r
+                               sb.append("]");\r
+                       }\r
+                       aaf.access.log(Level.INFO, sb);\r
+               } else {\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null || (user.noPerms() && user.permExpired())) user = loadUser(bait);\r
+                               if(user!=null) {\r
+                                       user.copyPermsTo(perms);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void remove(String user) {\r
+               super.remove(user);\r
+       }\r
+\r
+       private boolean isDebug(String bait) {\r
+               if(debug!=null) {\r
+                       if(debug.length==1 && "all".equals(debug[0]))return true;\r
+                       for(String s : debug) {\r
+                               if(s.equals(bait))return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       /**\r
+        * This special case minimizes loops, avoids multiple Set hits, and calls all the appropriate Actions found.\r
+        * \r
+        * @param bait\r
+        * @param obj\r
+        * @param type\r
+        * @param instance\r
+        * @param actions\r
+        */\r
+       public<A> void fishOneOf(String bait, A obj, String type, String instance, List<Action<A>> actions) {\r
+               User<PERM> user = getUser(bait);\r
+               if(user==null || (user.noPerms() && user.permExpired()))user = loadUser(bait);\r
+//             return user==null?false:user.contains(pond);\r
+               if(user!=null) {\r
+                       ReuseAAFPermission perm = new ReuseAAFPermission(type,instance);\r
+                       for(Action<A> action : actions) {\r
+                               perm.setAction(action.getName());\r
+                               if(user.contains(perm)) {\r
+                                       if(action.exec(obj))return;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public static interface Action<A> {\r
+               public String getName();\r
+               /**\r
+                *  Return false to continue, True to end now\r
+                * @return\r
+                */\r
+               public boolean exec(A a);\r
+       }\r
+       \r
+       private class ReuseAAFPermission extends AAFPermission {\r
+               public ReuseAAFPermission(String type, String instance) {\r
+                       super(type,instance,null);\r
+               }\r
+\r
+               public void setAction(String s) {\r
+                       action = s;\r
+               }\r
+               \r
+               /**\r
+                * This function understands that AAF Keys are hierarchical, :A:B:C, \r
+                *  Cassandra follows a similar method, so we'll short circuit and do it more efficiently when there isn't a first hit\r
+                * @return\r
+                */\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java b/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java
new file mode 100644 (file)
index 0000000..39854d6
--- /dev/null
@@ -0,0 +1,288 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.io.PrintWriter;\r
+import java.security.KeyStore;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public abstract class ArtifactDir implements PlaceArtifact {\r
+\r
+       protected static final String C_R = "\n";\r
+       protected File dir;\r
+       private List<String> encodeds = new ArrayList<String>();\r
+       \r
+       private Symm symm;\r
+       // This checks for multiple passes of Dir on the same objects.  Run clear after done.\r
+       protected static Map<String,Object> processed = new HashMap<String,Object>();\r
+\r
+\r
+       /**\r
+        * Note:  Derived Classes should ALWAYS call "super.place(cert,arti)" first, and \r
+        * then "placeProperties(arti)" just after they implement\r
+        */\r
+       @Override\r
+       public final boolean place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               validate(arti);\r
+               \r
+               try {\r
+                       // Obtain/setup directory as required\r
+                       dir = new File(arti.getDir());\r
+                       if(processed.get("dir")==null) {\r
+                               if(!dir.exists()) {\r
+                                       Chmod.to755.chmod(dir);\r
+                                       if(!dir.mkdirs()) {\r
+                                               throw new CadiException("Could not create " + dir);\r
+                                       }\r
+                               }\r
+                               \r
+                               // Also place cm_url and Host Name\r
+                               addProperty(Config.CM_URL,trans.getProperty(Config.CM_URL));\r
+                               addProperty(Config.HOSTNAME,arti.getMachine());\r
+                               //addProperty(Config.AAF_ENV,certInfo.getEnv());\r
+                               // Obtain Issuers\r
+                               boolean first = true;\r
+                               StringBuilder issuers = new StringBuilder();\r
+//                             for(String dn : certInfo.getCaIssuerDNs()) {\r
+//                                     if(first) {\r
+//                                             first=false;\r
+//                                     } else {\r
+//                                             issuers.append(':');\r
+//                                     }\r
+//                                     issuers.append(dn);\r
+//                             }\r
+                               addProperty(Config.CADI_X509_ISSUERS,issuers.toString());\r
+                       }\r
+                       symm = (Symm)processed.get("symm");\r
+                       if(symm==null) {\r
+                               // CADI Key Gen\r
+                               File f = new File(dir,arti.getAppName() + ".keyfile");\r
+                               if(!f.exists()) {\r
+                                       write(f,Chmod.to400,Symm.baseCrypt().keygen());\r
+                               }\r
+                               symm = Symm.obtain(f); \r
+\r
+                               addEncProperty("ChallengePassword", certInfo.getChallenge());\r
+                               \r
+                               processed.put("symm",symm);\r
+                       }\r
+\r
+                       _place(trans, certInfo,arti);\r
+                       \r
+                       placeProperties(arti);\r
+                       \r
+                       processed.put("dir",dir);\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Derived Classes implement this instead, so Dir can process first, and write any Properties last\r
+        * @param cert\r
+        * @param arti\r
+        * @return\r
+        * @throws CadiException\r
+        */\r
+       protected abstract boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException;\r
+\r
+       protected void addProperty(String tag, String value) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append(tag);\r
+               sb.append('=');\r
+               sb.append(value);\r
+               encodeds.add(sb.toString());\r
+       }\r
+\r
+       protected void addEncProperty(String tag, String value) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append(tag);\r
+               sb.append('=');\r
+               sb.append("enc:???");\r
+               sb.append(symm.enpass(value));\r
+               encodeds.add(sb.toString());\r
+       }\r
+\r
+       protected void write(File f, Chmod c, String ... data) throws IOException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               PrintStream ps = new PrintStream(fos);\r
+               try {\r
+                       for(String s : data) {\r
+                               ps.print(s);\r
+                       }\r
+               } finally {\r
+                       ps.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+\r
+       protected void write(File f, Chmod c, byte[] bytes) throws IOException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               try {\r
+                       fos.write(bytes);\r
+               } finally {\r
+                       fos.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+       \r
+       protected void write(File f, Chmod c, KeyStore ks, char[] pass ) throws IOException, CadiException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               try {\r
+                       ks.store(fos, pass);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               } finally {\r
+                       fos.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+\r
+\r
+       private void validate(Artifact a) throws CadiException {\r
+               StringBuilder sb = new StringBuilder();\r
+               if(a.getDir()==null) {\r
+                       sb.append("File Artifacts require a path");\r
+               }\r
+\r
+               if(a.getAppName()==null) {\r
+                       if(sb.length()>0) {\r
+                               sb.append('\n');\r
+                       }\r
+                       sb.append("File Artifacts require an AAF Namespace");\r
+               }\r
+               \r
+               if(sb.length()>0) {\r
+                       throw new CadiException(sb.toString());\r
+               }\r
+       }\r
+\r
+       private boolean placeProperties(Artifact arti) throws CadiException {\r
+               if(encodeds.size()==0) {\r
+                       return true;\r
+               }\r
+               boolean first=processed.get("dir")==null;\r
+               try {\r
+                       File f = new File(dir,arti.getAppName()+".props");\r
+                       if(f.exists()) {\r
+                               if(first) {\r
+                                       f.delete();\r
+                               } else {\r
+                                       f.setWritable(true);\r
+                               }\r
+                       }\r
+                       // Append if not first\r
+                       PrintWriter pw = new PrintWriter(new FileWriter(f,!first));\r
+                       \r
+                       // Write a Header\r
+                       if(first) {\r
+                               for(int i=0;i<60;++i) {\r
+                                       pw.print('#');\r
+                               }\r
+                               pw.println();\r
+                               pw.println("# Properties Generated by AT&T Certificate Manager");\r
+                               pw.print("#   by ");\r
+                               pw.println(System.getProperty("user.name"));\r
+                               pw.print("#   on ");\r
+                               pw.println(Chrono.dateStamp());\r
+                               pw.println("# @copyright 2016, AT&T");\r
+                               for(int i=0;i<60;++i) {\r
+                                       pw.print('#');\r
+                               }\r
+                               pw.println();\r
+                               for(String prop : encodeds) {\r
+                                       if(    prop.startsWith("cm_") \r
+                                               || prop.startsWith(Config.HOSTNAME)\r
+                                               || prop.startsWith(Config.AAF_ENV)) {\r
+                                               pw.println(prop);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       try {\r
+                               for(String prop : encodeds) {\r
+                                       if(prop.startsWith("cadi")) {\r
+                                               pw.println(prop);\r
+                                       }\r
+                               }\r
+                       } finally {\r
+                               pw.close();\r
+                       }\r
+                       Chmod.to644.chmod(f);\r
+                       \r
+                       if(first) {\r
+                               // Challenge\r
+                               f = new File(dir,arti.getAppName()+".chal");\r
+                               if(f.exists()) {\r
+                                       f.delete();\r
+                               }\r
+                               pw = new PrintWriter(new FileWriter(f));\r
+                               try {\r
+                                       for(String prop : encodeds) {\r
+                                               if(prop.startsWith("Challenge")) {\r
+                                                       pw.println(prop);\r
+                                               }\r
+                                       }\r
+                               } finally {\r
+                                       pw.close();\r
+                               }\r
+                               Chmod.to400.chmod(f);\r
+                       }\r
+               } catch(Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       public static void clear() {\r
+               processed.clear();\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/CertException.java b/aaf/src/main/java/com/att/cadi/cm/CertException.java
new file mode 100644 (file)
index 0000000..a2694ce
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+public class CertException extends Exception {\r
+\r
+       /**\r
+        * \r
+        */\r
+       private static final long serialVersionUID = 1373028409048516401L;\r
+\r
+       public CertException() {\r
+       }\r
+\r
+       public CertException(String message) {\r
+               super(message);\r
+       }\r
+\r
+       public CertException(Throwable cause) {\r
+               super(cause);\r
+       }\r
+\r
+       public CertException(String message, Throwable cause) {\r
+               super(message, cause);\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/CmAgent.java b/aaf/src/main/java/com/att/cadi/cm/CmAgent.java
new file mode 100644 (file)
index 0000000..424ef83
--- /dev/null
@@ -0,0 +1,711 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.security.KeyStore;\r
+import java.security.cert.X509Certificate;\r
+import java.util.ArrayDeque;\r
+import java.util.Deque;\r
+import java.util.GregorianCalendar;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.aaf.client.ErrMessage;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.sso.AAFSSO;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.TimeTaken;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.inno.env.util.Split;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+import certman.v1_0.Artifacts;\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+import certman.v1_0.CertificateRequest;\r
+\r
+public class CmAgent {\r
+       private static final String PRINT = "print";\r
+       private static final String FILE = "file";\r
+       private static final String PKCS12 = "pkcs12";\r
+       private static final String JKS = "jks";\r
+       private static final String SCRIPT="script";\r
+       \r
+       private static final String CM_VER = "1.0";\r
+       public static final int PASS_SIZE = 24;\r
+       private static int TIMEOUT;\r
+       \r
+       private static RosettaDF<CertificateRequest> reqDF;\r
+       private static RosettaDF<CertInfo> certDF;\r
+       private static RosettaDF<Artifacts> artifactsDF;\r
+       private static ErrMessage errMsg;\r
+       private static Map<String,PlaceArtifact> placeArtifact;\r
+       private static RosettaEnv env;\r
+\r
+       public static void main(String[] args) {\r
+               int exitCode = 0;\r
+               try {\r
+                       AAFSSO aafsso = new AAFSSO(args);\r
+                       if(aafsso.loginOnly()) {\r
+                               aafsso.setLogDefault();\r
+                               aafsso.writeFiles();\r
+                               System.out.println("AAF SSO information created in ~/.aaf");\r
+                       } else {\r
+                               PropAccess access = aafsso.access();\r
+                               env = new RosettaEnv(access.getProperties());\r
+                               Deque<String> cmds = new ArrayDeque<String>();\r
+                               for(String p : args) {\r
+                                       if(p.indexOf('=')<0) {\r
+                                               cmds.add(p);\r
+                                       }\r
+                               }\r
+                               \r
+                               if(cmds.size()==0) {\r
+                                       aafsso.setLogDefault();\r
+                                       System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");\r
+                                       System.out.println("   create   <mechID> [<machine>]");\r
+                                       System.out.println("   read     <mechID> [<machine>]");\r
+                                       System.out.println("   update   <mechID> [<machine>]");\r
+                                       System.out.println("   delete   <mechID> [<machine>]");\r
+                                       System.out.println("   copy     <mechID> <machine> <newmachine>[,<newmachine>]*");\r
+                                       System.out.println("   place    <mechID> [<machine>]");\r
+                                       System.out.println("   showpass <mechID> [<machine>]");\r
+                                       System.out.println("   check    <mechID> [<machine>]");\r
+                                       System.exit(1);\r
+                               }\r
+                               \r
+                               TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));\r
+                       \r
+                               reqDF = env.newDataFactory(CertificateRequest.class);\r
+                               artifactsDF = env.newDataFactory(Artifacts.class);\r
+                               certDF = env.newDataFactory(CertInfo.class);\r
+                               errMsg = new ErrMessage(env);\r
+       \r
+                               placeArtifact = new HashMap<String,PlaceArtifact>();\r
+                               placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));\r
+                               placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));\r
+                               placeArtifact.put(FILE, new PlaceArtifactInFiles());\r
+                               placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));\r
+                               placeArtifact.put(SCRIPT, new PlaceArtifactScripts());\r
+                               \r
+                               Trans trans = env.newTrans();\r
+                               try {\r
+                                       // show Std out again\r
+                                       aafsso.setLogDefault();\r
+                                       aafsso.setStdErrDefault();\r
+                                       \r
+                                       // if CM_URL can be obtained, add to sso.props, if written\r
+                                       String cm_url = getProperty(access,env,false, Config.CM_URL,Config.CM_URL+": ");\r
+                                       if(cm_url!=null) {\r
+                                               aafsso.addProp(Config.CM_URL, cm_url);\r
+                                       }\r
+                                       aafsso.writeFiles();\r
+\r
+                                       AAFCon<?> aafcon = new AAFConHttp(access,Config.CM_URL);\r
+\r
+                                       String cmd = cmds.removeFirst();\r
+                                       if("place".equals(cmd)) {\r
+                                               placeCerts(trans,aafcon,cmds);\r
+                                       } else if("create".equals(cmd)) {\r
+                                               createArtifact(trans, aafcon,cmds);\r
+                                       } else if("read".equals(cmd)) {\r
+                                               readArtifact(trans, aafcon, cmds);\r
+                                       } else if("copy".equals(cmd)) {\r
+                                               copyArtifact(trans, aafcon, cmds);\r
+                                       } else if("update".equals(cmd)) {\r
+                                               updateArtifact(trans, aafcon, cmds);\r
+                                       } else if("delete".equals(cmd)) {\r
+                                               deleteArtifact(trans, aafcon, cmds);\r
+                                       } else if("showpass".equals(cmd)) {\r
+                                               showPass(trans,aafcon,cmds);\r
+                                       } else if("check".equals(cmd)) {\r
+                                               try {\r
+                                                       exitCode = check(trans,aafcon,cmds);\r
+                                               } catch (Exception e) {\r
+                                                       exitCode = 1;\r
+                                                       throw e;\r
+                                               }\r
+                                       } else {\r
+                                               AAFSSO.cons.printf("Unknown command \"%s\"\n", cmd);\r
+                                       }\r
+                               } finally {\r
+                                       StringBuilder sb = new StringBuilder();\r
+                       trans.auditTrail(4, sb, Trans.REMOTE);\r
+                       if(sb.length()>0) {\r
+                               trans.info().log("Trans Info\n",sb);\r
+                       }\r
+                               }\r
+                               aafsso.close();\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+               if(exitCode!=0) {\r
+                       System.exit(exitCode);\r
+               }\r
+       }\r
+\r
+       private static String getProperty(PropAccess pa, Env env, boolean secure, String tag, String prompt, Object ... def) {\r
+               String value;\r
+               if((value=pa.getProperty(tag))==null) {\r
+                       if(secure) {\r
+                               value = new String(AAFSSO.cons.readPassword(prompt, def));\r
+                       } else {\r
+                               value = AAFSSO.cons.readLine(prompt,def).trim();\r
+                       }\r
+                       if(value!=null) {\r
+                               if(value.length()>0) {\r
+                                       pa.setProperty(tag,value);\r
+                                       env.setProperty(tag,value);\r
+                               } else if(def.length==1) {\r
+                                       value=def[0].toString();\r
+                                       pa.setProperty(tag,value);\r
+                                       env.setProperty(tag,value);\r
+                               }\r
+                       }\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private static String mechID(Deque<String> cmds) {\r
+               if(cmds.size()<1) {\r
+                       String alias = env.getProperty(Config.CADI_ALIAS);\r
+                       return alias!=null?alias:AAFSSO.cons.readLine("MechID: ");\r
+               }\r
+               return cmds.removeFirst();      \r
+       }\r
+\r
+       private static String machine(Deque<String> cmds) throws UnknownHostException {\r
+               if(cmds.size()>0) {\r
+                       return cmds.removeFirst();\r
+               } else {\r
+                       String mach = env.getProperty(Config.HOSTNAME);\r
+                       return mach!=null?mach:InetAddress.getLocalHost().getHostName();\r
+               }\r
+       }\r
+\r
+       private static String[] machines(Deque<String> cmds)  {\r
+               String machines;\r
+               if(cmds.size()>0) {\r
+                       machines = cmds.removeFirst();\r
+               } else {\r
+                       machines = AAFSSO.cons.readLine("Machines (sep by ','): ");\r
+               }\r
+               return Split.split(',', machines);\r
+       }\r
+\r
+       private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               Artifacts artifacts = new Artifacts();\r
+               Artifact arti = new Artifact();\r
+               artifacts.getArtifact().add(arti);\r
+               arti.setMechid(mechID!=null?mechID:AAFSSO.cons.readLine("MechID: "));\r
+               arti.setMachine(machine!=null?machine:AAFSSO.cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));\r
+               arti.setCa(AAFSSO.cons.readLine("CA: (%s): ","aaf"));\r
+               \r
+               String resp = AAFSSO.cons.readLine("Types [file,jks,script] (%s): ", "jks");\r
+               for(String s : Split.splitTrim(',', resp)) {\r
+                       arti.getType().add(s);\r
+               }\r
+               // Always do Script\r
+               if(!resp.contains(SCRIPT)) {\r
+                       arti.getType().add(SCRIPT);\r
+               }\r
+\r
+               // Note: Sponsor is set on Creation by CM\r
+               String configRootName = AAFCon.reverseDomain(arti.getMechid());\r
+               arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",configRootName));\r
+               arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", System.getProperty("user.dir")));\r
+               arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", System.getProperty("user.name")));\r
+               arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renewal Days (%s):", "30")));\r
+               arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (mailto owner):", "")));\r
+               \r
+               TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);\r
+                       if(future.get(TIMEOUT)) {\r
+                               trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                       errMsg.toMsg(future));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       private static String toNotification(String notification) {\r
+               if(notification==null) {\r
+                       notification="";\r
+               } else if(notification.length()>0) {\r
+                       if(notification.indexOf(':')<0) {\r
+                               notification = "mailto:" + notification;\r
+                       }\r
+               }\r
+               return notification;\r
+       }\r
+       \r
+\r
+       private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Read Artifact", Env.SUB);\r
+               try {\r
+                       Future<Artifacts> future = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+       \r
+                       if(future.get(TIMEOUT)) {\r
+                               boolean printed = false;\r
+                               for(Artifact a : future.value.getArtifact()) {\r
+                                       AAFSSO.cons.printf("MechID:          %s\n",a.getMechid()); \r
+                                       AAFSSO.cons.printf("  Sponsor:       %s\n",a.getSponsor()); \r
+                                       AAFSSO.cons.printf("Machine:         %s\n",a.getMachine()); \r
+                                       AAFSSO.cons.printf("CA:              %s\n",a.getCa()); \r
+                                       StringBuilder sb = new StringBuilder();\r
+                                       boolean first = true;\r
+                                       for(String t : a.getType()) {\r
+                                               if(first) {first=false;}\r
+                                               else{sb.append(',');}\r
+                                               sb.append(t);\r
+                                       }\r
+                                       AAFSSO.cons.printf("Types:           %s\n",sb);\r
+                                       AAFSSO.cons.printf("Namespace:       %s\n",a.getAppName()); \r
+                                       AAFSSO.cons.printf("Directory:       %s\n",a.getDir());\r
+                                       AAFSSO.cons.printf("O/S User:        %s\n",a.getOsUser());\r
+                                       AAFSSO.cons.printf("Renew Days:      %d\n",a.getRenewDays());\r
+                                       AAFSSO.cons.printf("Notification     %s\n",a.getNotification());\r
+                                       printed = true;\r
+                               }\r
+                               if(!printed) {\r
+                                       AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(future));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               String[] newmachs = machines(cmds);\r
+               if(newmachs==null || newmachs == null) {\r
+                       trans.error().log("No machines listed to copy to");\r
+               } else {\r
+                       TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);\r
+                       try {\r
+                               Future<Artifacts> future = aafcon.client(CM_VER)\r
+                                               .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       \r
+                               if(future.get(TIMEOUT)) {\r
+                                       boolean printed = false;\r
+                                       for(Artifact a : future.value.getArtifact()) {\r
+                                               for(String m : newmachs) {\r
+                                                       a.setMachine(m);\r
+                                                       Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);\r
+                                                       if(fup.get(TIMEOUT)) {\r
+                                                               trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);\r
+                                                       } else {\r
+                                                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                                                       errMsg.toMsg(fup));\r
+                                                       }\r
+       \r
+                                                       printed = true;\r
+                                               }\r
+                                       }\r
+                                       if(!printed) {\r
+                                               AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                                       }\r
+                               } else {\r
+                                       trans.error().log(errMsg.toMsg(future));\r
+                               }\r
+                       } finally {\r
+                               tt.done();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> fread = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+       \r
+                       if(fread.get(TIMEOUT)) {\r
+                               Artifacts artifacts = new Artifacts();\r
+                               for(Artifact a : fread.value.getArtifact()) {\r
+                                       Artifact arti = new Artifact();\r
+                                       artifacts.getArtifact().add(arti);\r
+                                       \r
+                                       AAFSSO.cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());\r
+                                       arti.setMechid(a.getMechid());\r
+                                       arti.setMachine(a.getMachine());\r
+                                       arti.setCa(AAFSSO.cons.readLine("CA: (%s): ",a.getCa()));\r
+                                       StringBuilder sb = new StringBuilder();\r
+                                       boolean first = true;\r
+                                       for(String t : a.getType()) {\r
+                                               if(first) {first=false;}\r
+                                               else{sb.append(',');}\r
+                                               sb.append(t);\r
+                                       }\r
+       \r
+                                       String resp = AAFSSO.cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);\r
+                                       for(String s : Split.splitTrim(',', resp)) {\r
+                                               arti.getType().add(s);\r
+                                       }\r
+                                       // Always do Script\r
+                                       if(!resp.contains(SCRIPT)) {\r
+                                               arti.getType().add(SCRIPT);\r
+                                       }\r
+\r
+                                       // Note: Sponsor is set on Creation by CM\r
+                                       arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",a.getAppName()));\r
+                                       arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", a.getDir()));\r
+                                       arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", a.getOsUser()));\r
+                                       arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renew Days (%s):", a.getRenewDays())));\r
+                                       arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (%s):", a.getNotification())));\r
+       \r
+                               }\r
+                               if(artifacts.getArtifact().size()==0) {\r
+                                       AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                               } else {\r
+                                       Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);\r
+                                       if(fup.get(TIMEOUT)) {\r
+                                               trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);\r
+                                       } else {\r
+                                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                                       errMsg.toMsg(fup));\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s %s, %s",\r
+                                               errMsg.toMsg(fread),mechID,machine);\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechid = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Void> future = aafcon.client(CM_VER)\r
+                                       .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );\r
+       \r
+                       if(future.get(TIMEOUT)) {\r
+                               trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s %s, %s",\r
+                                       errMsg.toMsg(future),mechid,machine);\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       \r
+\r
+       private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               boolean rv = false;\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       AAFSSO.cons.printf("===> There are no artifacts for %s %s", mechID, machine);\r
+                               } else {\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               String osID = System.getProperty("user.name");\r
+                                               if(a.getOsUser().equals(osID)) {\r
+                                                       CertificateRequest cr = new CertificateRequest();\r
+                                                       cr.setMechid(a.getMechid());\r
+                                                       cr.setSponsor(a.getSponsor());\r
+                                                       cr.getFqdns().add(a.getMachine());\r
+                                                       Future<String> f = aafcon.client(CM_VER)\r
+                                                                       .setQueryParams("withTrust")\r
+                                                                       .updateRespondString("/cert/" + a.getCa(),reqDF, cr);\r
+                                                       if(f.get(TIMEOUT)) {\r
+                                                               CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();\r
+                                                               for(String type : a.getType()) {\r
+                                                                       PlaceArtifact pa = placeArtifact.get(type);\r
+                                                                       if(pa!=null) {\r
+                                                                               if(rv = pa.place(trans, capi, a)) {\r
+                                                                                       notifyPlaced(a,rv);\r
+                                                                               }\r
+                                                                       }\r
+                                                               }\r
+                                                               // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact\r
+                                                       } else {\r
+                                                               trans.error().log(errMsg.toMsg(f));\r
+                                                       }\r
+                                               } else {\r
+                                                       trans.error().log("You must be OS User \"" + a.getOsUser() +"\" to place Certificates on this box");\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+               return rv;\r
+       }\r
+       \r
+       private static void notifyPlaced(Artifact a, boolean rv) {\r
+               \r
+               \r
+       }\r
+\r
+       private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Show Password", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);\r
+                               } else {\r
+                                       String id = aafcon.defID();\r
+                                       boolean allowed;\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               allowed = id!=null && (id.equals(a.getSponsor()) ||\r
+                                                               (id.equals(a.getMechid()) \r
+                                                                               && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));\r
+                                               if(!allowed) {\r
+                                                       Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" + \r
+                                                                       a.getAppName() + ".certman|"+a.getCa()+"|showpass","*/*");\r
+                                                       if(pf.get(TIMEOUT)) {\r
+                                                               allowed = true;\r
+                                                       } else {\r
+                                                               trans.error().log(errMsg.toMsg(pf));\r
+                                                       }\r
+                                               }\r
+                                               if(allowed) {\r
+                                                       File dir = new File(a.getDir());\r
+                                                       Properties props = new Properties();\r
+                                                       FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));\r
+                                                       try {\r
+                                                               props.load(fis);\r
+                                                               fis.close();\r
+                                                               fis = new FileInputStream(new File(dir,a.getAppName()+".chal"));\r
+                                                               props.load(fis);\r
+                                                       } finally {\r
+                                                               fis.close();\r
+                                                       }\r
+                                                       \r
+                                                       File f = new File(dir,a.getAppName()+".keyfile");\r
+                                                       if(f.exists()) {\r
+                                                               Symm symm = Symm.obtain(f);\r
+                                                               \r
+                                                               for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {\r
+                                                                       Entry<Object,Object> en = iter.next();\r
+                                                                       if(en.getValue().toString().startsWith("enc:???")) {\r
+                                                                               System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));\r
+                                                                       }\r
+                                                               }\r
+                                                       } else {\r
+                                                               trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",\r
+                                                                               f.getAbsolutePath(),a.getMechid(), a.getMachine());\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+\r
+       }\r
+       \r
+\r
+       /**\r
+        * Check returns Error Codes, so that Scripts can know what to do\r
+        * \r
+        *   0 - Check Complete, nothing to do\r
+        *   1 - General Error\r
+        *   2 - Error for specific Artifact - read check.msg\r
+        *   10 - Certificate Updated - check.msg is email content\r
+        *   \r
+        * @param trans\r
+        * @param aafcon\r
+        * @param cmds\r
+        * @return\r
+        * @throws Exception\r
+        */\r
+       private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               int exitCode=1;\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);\r
+               try {\r
+               \r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);\r
+                               } else {\r
+                                       String id = aafcon.defID();\r
+                                       GregorianCalendar now = new GregorianCalendar();\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               if(id.equals(a.getMechid())) {\r
+                                                       File dir = new File(a.getDir());\r
+                                                       Properties props = new Properties();\r
+                                                       FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));\r
+                                                       try {\r
+                                                               props.load(fis);\r
+                                                       } finally {\r
+                                                               fis.close();\r
+                                                       }\r
+                                                       \r
+                                                       String prop;                                            \r
+                                                       File f;\r
+       \r
+                                                       if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||\r
+                                                               !(f=new File(prop)).exists()) {\r
+                                                                       trans.error().printf("Keyfile must exist to check Certificates for %s on %s",\r
+                                                                               a.getMechid(), a.getMachine());\r
+                                                       } else {\r
+                                                               String ksf = props.getProperty(Config.CADI_KEYSTORE);\r
+                                                               String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);\r
+                                                               if(ksf==null || ksps == null) {\r
+                                                                       trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",\r
+                                                                                       Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());\r
+                                                               } else {\r
+                                                                       KeyStore ks = KeyStore.getInstance("JKS");\r
+                                                                       Symm symm = Symm.obtain(f);\r
+                                                                       \r
+                                                                       fis = new FileInputStream(ksf);\r
+                                                                       try {\r
+                                                                               ks.load(fis,symm.depass(ksps).toCharArray());\r
+                                                                       } finally {\r
+                                                                               fis.close();\r
+                                                                       }\r
+                                                                       X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);\r
+                                                                       String msg = null;\r
+\r
+                                                                       if(cert==null) {\r
+                                                                               msg = String.format("X509Certificate does not exist for %s on %s in %s",\r
+                                                                                               a.getMechid(), a.getMachine(), ksf);\r
+                                                                               trans.error().log(msg);\r
+                                                                               exitCode = 2;\r
+                                                                       } else {\r
+                                                                               GregorianCalendar renew = new GregorianCalendar();\r
+                                                                               renew.setTime(cert.getNotAfter());\r
+                                                                               renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());\r
+                                                                               if(renew.after(now)) {\r
+                                                                                       msg = String.format("X509Certificate for %s on %s has been checked on %s. It expires on %s; it will not be renewed until %s.\n", \r
+                                                                                                       a.getMechid(), a.getMachine(),Chrono.dateOnlyStamp(now),cert.getNotAfter(),Chrono.dateOnlyStamp(renew));\r
+                                                                                       trans.info().log(msg);\r
+                                                                                       exitCode = 0; // OK\r
+                                                                               } else {\r
+                                                                                       trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n", \r
+                                                                                                       a.getMechid(), a.getMachine(),cert.getNotAfter());\r
+                                                                                       cmds.offerLast(mechID);\r
+                                                                                       cmds.offerLast(machine);\r
+                                                                                       if(placeCerts(trans,aafcon,cmds)) {\r
+                                                                                               msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n", \r
+                                                                                                               a.getMechid(), a.getMachine());\r
+                                                                                               exitCode = 10; // Refreshed\r
+                                                                                       } else {\r
+                                                                                               msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n", \r
+                                                                                                               a.getMechid(), a.getMachine());\r
+                                                                                               exitCode = 1; // Error Renewing\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       }\r
+                                                                       if(msg!=null) {\r
+                                                                               FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getAppName()+".msg");\r
+                                                                               try {\r
+                                                                                       fos.write(msg.getBytes());\r
+                                                                               } finally {\r
+                                                                                       fos.close();\r
+                                                                               }\r
+                                                                       }\r
+                                                               }\r
+                                                               \r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                               exitCode=1;\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+               return exitCode;\r
+       }\r
+\r
+}\r
+                       \r
+               \r
+\r
+\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/Factory.java b/aaf/src/main/java/com/att/cadi/cm/Factory.java
new file mode 100644 (file)
index 0000000..178cc81
--- /dev/null
@@ -0,0 +1,449 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.DataInputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.Reader;\r
+import java.io.StringReader;\r
+import java.security.InvalidKeyException;\r
+import java.security.Key;\r
+import java.security.KeyFactory;\r
+import java.security.KeyPair;\r
+import java.security.KeyPairGenerator;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.security.PrivateKey;\r
+import java.security.PublicKey;\r
+import java.security.SecureRandom;\r
+import java.security.Signature;\r
+import java.security.SignatureException;\r
+import java.security.cert.Certificate;\r
+import java.security.cert.CertificateEncodingException;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.CertificateFactory;\r
+import java.security.cert.X509Certificate;\r
+import java.security.spec.InvalidKeySpecException;\r
+import java.security.spec.PKCS8EncodedKeySpec;\r
+import java.security.spec.X509EncodedKeySpec;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.crypto.Cipher;\r
+import javax.crypto.NoSuchPaddingException;\r
+\r
+import com.att.cadi.Symm;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.TimeTaken;\r
+import com.att.inno.env.Trans;\r
+\r
+public class Factory {\r
+       private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";\r
+       public static final String KEY_ALGO = "RSA";\r
+       public static final String SIG_ALGO = "SHA256withRSA";\r
+\r
+       public  static final int KEY_LENGTH = 2048;\r
+       private static final KeyPairGenerator keygen;\r
+       private static final KeyFactory keyFactory;\r
+       private static final CertificateFactory certificateFactory;\r
+       private static final SecureRandom random;\r
+       \r
+       \r
+       private static final Symm base64 = Symm.base64.copy(64);\r
+\r
+       static {\r
+                       random = new SecureRandom();\r
+                       KeyPairGenerator tempKeygen;\r
+                       try {\r
+                               tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");\r
+                               tempKeygen.initialize(KEY_LENGTH, random);\r
+                       } catch (NoSuchAlgorithmException e) {\r
+                               tempKeygen = null;\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+                       keygen = tempKeygen;\r
+\r
+                       KeyFactory tempKeyFactory;\r
+                       try {\r
+                               tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"\r
+                       } catch (NoSuchAlgorithmException e) {\r
+                               tempKeyFactory = null;\r
+                               e.printStackTrace(System.err);\r
+                       };\r
+                       keyFactory = tempKeyFactory;\r
+                        \r
+                       CertificateFactory tempCertificateFactory;\r
+                       try {\r
+                               tempCertificateFactory = CertificateFactory.getInstance("X.509");\r
+                       } catch (CertificateException e) {\r
+                               tempCertificateFactory = null;\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+                       certificateFactory = tempCertificateFactory;\r
+\r
+                \r
+       }\r
+\r
+\r
+       public static KeyPair generateKeyPair(Trans trans) {\r
+               TimeTaken tt;\r
+               if(trans!=null) {\r
+                       tt = trans.start("Generate KeyPair", Env.SUB);\r
+               } else {\r
+                       tt = null;\r
+               }\r
+               try {\r
+                       return keygen.generateKeyPair();\r
+               } finally {\r
+                       if(tt!=null) {\r
+                               tt.done();\r
+                       }\r
+               }\r
+       }  \r
+\r
+       private static final String LINE_END = "-----\n";\r
+\r
+       protected static String textBuilder(String kind, byte[] bytes) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append("-----BEGIN ");\r
+               sb.append(kind);\r
+               sb.append(LINE_END);\r
+\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               base64.encode(bais, baos);\r
+               sb.append(new String(baos.toByteArray()));\r
+               \r
+               if(sb.charAt(sb.length()-1)!='\n') {\r
+                       sb.append('\n');\r
+               }\r
+               sb.append("-----END ");\r
+               sb.append(kind);\r
+               sb.append(LINE_END);\r
+               return sb.toString();\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {\r
+               byte[] bytes = decode(new StringReader(pk));\r
+               return toPrivateKey(trans, bytes);\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {\r
+               TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);\r
+               try {\r
+                       return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));\r
+               } catch (InvalidKeySpecException e) {\r
+                       throw new CertException("Translating Private Key from PKCS8 KeySpec",e);\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {\r
+               TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);\r
+               try {\r
+                       return toPrivateKey(trans,decode(file));\r
+               }finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       public static String toString(Trans trans, PrivateKey pk) throws IOException {\r
+//             PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());\r
+               trans.debug().log("Private Key to String");\r
+               return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());\r
+       }\r
+\r
+       public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {\r
+               TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);\r
+               try {\r
+                       ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());\r
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+                       Symm.base64noSplit.decode(bais, baos);\r
+\r
+                       return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));\r
+               } catch (InvalidKeySpecException e) {\r
+                       trans.error().log(e,"Translating Public Key from X509 KeySpec");\r
+                       return null;\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       public static String toString(Trans trans, PublicKey pk) throws IOException {\r
+               trans.debug().log("Public Key to String");\r
+               return textBuilder("PUBLIC KEY",pk.getEncoded());\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(String x509) throws CertificateException {\r
+               return toX509Certificate(x509.getBytes());\r
+       }\r
+       \r
+       public static Collection<? extends Certificate> toX509Certificate(List<String> x509s) throws CertificateException {\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               try {\r
+                       for(String x509 : x509s) {\r
+                               baos.write(x509.getBytes());\r
+                       }\r
+               } catch (IOException e) {\r
+                       throw new CertificateException(e);\r
+               }\r
+               return toX509Certificate(new ByteArrayInputStream(baos.toByteArray()));\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(byte[] x509) throws CertificateException {\r
+               return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {\r
+               FileInputStream fis = new FileInputStream(file);\r
+               try {\r
+                       return toX509Certificate(fis);\r
+               } finally {\r
+                       try {\r
+                               fis.close();\r
+                       } catch (IOException e) {\r
+                               throw new CertificateException(e);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(InputStream is) throws CertificateException {\r
+               return certificateFactory.generateCertificates(is);\r
+       }\r
+\r
+       public static String toString(Trans trans, Certificate cert) throws IOException, CertException {\r
+               if(trans.debug().isLoggable()) {\r
+                       StringBuilder sb = new StringBuilder("Certificate to String");\r
+                       if(cert instanceof X509Certificate) {\r
+                               sb.append(" - ");\r
+                               sb.append(((X509Certificate)cert).getSubjectDN());\r
+                       }\r
+                       trans.debug().log(sb);\r
+               }\r
+               try {\r
+                       if(cert==null) {\r
+                               throw new CertException("Certificate not built");\r
+                       }\r
+                       return textBuilder("CERTIFICATE",cert.getEncoded());\r
+               } catch (CertificateEncodingException e) {\r
+                       throw new CertException(e);\r
+               }\r
+       }\r
+\r
+       public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {\r
+               return Cipher.getInstance(KEY_ALGO); \r
+       }\r
+\r
+       public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {\r
+               Cipher cipher = Cipher.getInstance(KEY_ALGO);\r
+               cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);\r
+               return cipher;\r
+       }\r
+\r
+       public static byte[] strip(Reader rdr) throws IOException {\r
+               BufferedReader br = new BufferedReader(rdr);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               String line;\r
+               while((line=br.readLine())!=null) {\r
+                       if(line.length()>0 &&\r
+                          !line.startsWith("-----") &&\r
+                          line.indexOf(':')<0) {  // Header elements\r
+                               baos.write(line.getBytes());\r
+                       }\r
+               }\r
+               return baos.toByteArray();\r
+       }\r
+       \r
+       public static class StripperInputStream extends InputStream {\r
+               private Reader created;\r
+               private BufferedReader br;\r
+               private int idx;\r
+               private String line;\r
+\r
+               public StripperInputStream(Reader rdr) {\r
+                       if(rdr instanceof BufferedReader) {\r
+                               br = (BufferedReader)rdr;\r
+                       } else {\r
+                               br = new BufferedReader(rdr);\r
+                       }\r
+                       created = null;\r
+               }\r
+               \r
+               public StripperInputStream(File file) throws FileNotFoundException {\r
+                       this(new FileReader(file));\r
+                       created = br;\r
+               }\r
+\r
+               public StripperInputStream(InputStream is) throws FileNotFoundException {\r
+                       this(new InputStreamReader(is));\r
+                       created = br;\r
+               }\r
+\r
+               @Override\r
+               public int read() throws IOException {\r
+                       if(line==null || idx>=line.length()) {\r
+                               while((line=br.readLine())!=null) {\r
+                                       if(line.length()>0 &&\r
+                                          !line.startsWith("-----") &&\r
+                                          line.indexOf(':')<0) {  // Header elements\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if(line==null) {\r
+                                       return -1;\r
+                               }\r
+                               idx = 0;\r
+                       }\r
+                       return line.charAt(idx++);\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see java.io.InputStream#close()\r
+                */\r
+               @Override\r
+               public void close() throws IOException {\r
+                       if(created!=null) {\r
+                               created.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static class Base64InputStream extends InputStream {\r
+               private InputStream created;\r
+               private InputStream is;\r
+               private byte trio[];\r
+               private byte duo[];\r
+               private int idx;\r
+\r
+               \r
+               public Base64InputStream(File file) throws FileNotFoundException {\r
+                       this(new FileInputStream(file));\r
+                       created = is;\r
+               }\r
+\r
+               public Base64InputStream(InputStream is) throws FileNotFoundException {\r
+                       this.is = is;\r
+                       trio = new byte[3];\r
+                       idx = 4;\r
+               }\r
+\r
+               @Override\r
+               public int read() throws IOException {\r
+                       if(duo==null || idx>=duo.length) {\r
+                               int read = is.read(trio);\r
+                               if(read==-1) {\r
+                                       return -1;\r
+                               }\r
+                               duo = Symm.base64.decode(trio);\r
+                               if(duo==null || duo.length==0) {\r
+                                       return -1;\r
+                               }\r
+                               idx=0;\r
+                       }\r
+                       \r
+                       return duo[idx++];\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see java.io.InputStream#close()\r
+                */\r
+               @Override\r
+               public void close() throws IOException {\r
+                       if(created!=null) {\r
+                               created.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static byte[] decode(byte[] bytes) throws IOException {\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               Symm.base64.decode(bais, baos);\r
+               return baos.toByteArray();\r
+       }\r
+       \r
+       public static byte[] decode(File f) throws IOException {\r
+               FileReader fr = new FileReader(f);\r
+               try {\r
+                       return Factory.decode(fr);\r
+               } finally {\r
+                       fr.close();\r
+               }\r
+\r
+       }\r
+       public static byte[] decode(Reader rdr) throws IOException {\r
+               return decode(strip(rdr));\r
+       }\r
+\r
+\r
+       public static byte[] binary(File file) throws IOException {\r
+               DataInputStream dis = new DataInputStream(new FileInputStream(file));\r
+               try {\r
+                       byte[] bytes = new byte[(int)file.length()];\r
+                       dis.readFully(bytes);\r
+                       return bytes;\r
+               } finally {\r
+                       dis.close();\r
+               }\r
+       }\r
+\r
+\r
+       public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {\r
+               TimeTaken tt = trans.start("Sign Data", Env.SUB);\r
+               try {\r
+                       Signature sig = Signature.getInstance(SIG_ALGO);\r
+                       sig.initSign(pk, random);\r
+                       sig.update(bytes);\r
+                       return sig.sign();\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       public static String toSignatureString(byte[] signed) throws IOException {\r
+               return textBuilder("SIGNATURE", signed);\r
+       }\r
+\r
+       public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {\r
+               TimeTaken tt = trans.start("Verify Data", Env.SUB);\r
+               try {\r
+                       Signature sig = Signature.getInstance(SIG_ALGO);\r
+                       sig.initVerify(pk);\r
+                       sig.update(bytes);\r
+                       return sig.verify(signature);\r
+               } finally {\r
+                       tt.done();\r
+               }       \r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java
new file mode 100644 (file)
index 0000000..b5a3fb0
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.inno.env.Trans;\r
+\r
+public interface PlaceArtifact {\r
+       public boolean place(Trans trans, CertInfo cert, Artifact arti) throws CadiException;\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
new file mode 100644 (file)
index 0000000..219eb4a
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+\r
+public class PlaceArtifactInFiles extends ArtifactDir {\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               try {\r
+                       // Setup Public Cert\r
+                       File f = new File(dir,arti.getAppName()+".crt");\r
+                       write(f,Chmod.to644,certInfo.getCerts().get(0),C_R);\r
+                       \r
+                       // Setup Private Key\r
+                       f = new File(dir,arti.getAppName()+".key");\r
+                       write(f,Chmod.to400,certInfo.getPrivatekey(),C_R);\r
+                       \r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+}\r
+\r
+\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java
new file mode 100644 (file)
index 0000000..6859ba5
--- /dev/null
@@ -0,0 +1,130 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+import java.security.KeyStore;\r
+import java.security.PrivateKey;\r
+import java.security.cert.Certificate;\r
+import java.security.cert.X509Certificate;\r
+import java.util.Collection;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public class PlaceArtifactInKeystore extends ArtifactDir {\r
+       private String kst;\r
+       //TODO get ROOT DNs or Trusted DNs from Certificate Manager.\r
+//     private static String[] rootDNs = new String[]{                 \r
+//                     "CN=ATT CADI Root CA - Test, O=ATT, OU=CSO, C=US", // Lab.  delete eventually\r
+//                     "CN=ATT AAF CADI TEST CA, OU=CSO, O=ATT, C=US",\r
+//                     "CN=ATT AAF CADI CA, OU=CSO, O=ATT, C=US"\r
+//     };\r
+\r
+       public PlaceArtifactInKeystore(String kst) {\r
+               this.kst = kst;\r
+       }\r
+\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               File fks = new File(dir,arti.getAppName()+'.'+kst);\r
+               try {\r
+                       KeyStore jks = KeyStore.getInstance(kst);\r
+                       if(fks.exists()) {\r
+                               fks.delete();\r
+                       }       \r
+\r
+                       // Get the Cert(s)... Might include Trust store\r
+                       Collection<? extends Certificate> certColl = Factory.toX509Certificate(certInfo.getCerts());\r
+                       X509Certificate[] certs = new X509Certificate[certColl.size()];\r
+                       certColl.toArray(certs);\r
+                       \r
+\r
+                       // Add CADI Keyfile Entry to Properties\r
+                       addProperty(Config.CADI_KEYFILE,arti.getDir()+'/'+arti.getAppName() + ".keyfile");\r
+                       // Set Keystore Password\r
+                       addProperty(Config.CADI_KEYSTORE,fks.getAbsolutePath());\r
+                       String keystorePass = Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       addEncProperty(Config.CADI_KEYSTORE_PASSWORD,keystorePass);\r
+                       char[] keystorePassArray = keystorePass.toCharArray();\r
+                       jks.load(null,keystorePassArray); // load in\r
+                       \r
+                       // Add Private Key/Cert Entry for App\r
+                       // Note: Java SSL security classes, while having a separate key from keystore,\r
+                       // is documented to not actually work. \r
+                       // java.security.UnrecoverableKeyException: Cannot recover key\r
+                       // You can create a custom Key Manager to make it work, but Practicality  \r
+                       // dictates that you live with the default, meaning, they are the same\r
+                       String keyPass = keystorePass; //Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       PrivateKey pk = Factory.toPrivateKey(trans, certInfo.getPrivatekey());\r
+                       addEncProperty(Config.CADI_KEY_PASSWORD, keyPass);\r
+                       addProperty(Config.CADI_ALIAS, arti.getMechid());\r
+//                     Set<Attribute> attribs = new HashSet<Attribute>();\r
+//                     if(kst.equals("pkcs12")) {\r
+//                             // Friendly Name\r
+//                             attribs.add(new PKCS12Attribute("1.2.840.113549.1.9.20", arti.getAppName()));\r
+//                     } \r
+//                     \r
+                       KeyStore.ProtectionParameter protParam = \r
+                                       new KeyStore.PasswordProtection(keyPass.toCharArray());\r
+                       \r
+                       KeyStore.PrivateKeyEntry pkEntry = \r
+                               new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]});\r
+                       jks.setEntry(arti.getMechid(), \r
+                                       pkEntry, protParam);\r
+               \r
+                       // Write out\r
+                       write(fks,Chmod.to400,jks,keystorePassArray);\r
+                       \r
+                       // Change out to TrustStore\r
+                       fks = new File(dir,arti.getAppName()+".trust."+kst);\r
+                       jks = KeyStore.getInstance(kst);\r
+                       \r
+                       // Set Truststore Password\r
+                       addProperty(Config.CADI_TRUSTSTORE,fks.getAbsolutePath());\r
+                       String trustStorePass = Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       addEncProperty(Config.CADI_TRUSTSTORE_PASSWORD,trustStorePass);\r
+                       char[] truststorePassArray = trustStorePass.toCharArray();\r
+                       jks.load(null,truststorePassArray); // load in\r
+                       \r
+                       // Add Trusted Certificates\r
+                       for(int i=1; i<certs.length;++i) {\r
+                               jks.setCertificateEntry("cadi_root_" + arti.getCa() + '_' + i, certs[i]);\r
+                       }\r
+                       // Write out\r
+                       write(fks,Chmod.to644,jks,truststorePassArray);\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java
new file mode 100644 (file)
index 0000000..7815a8e
--- /dev/null
@@ -0,0 +1,53 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.PrintStream;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.inno.env.Trans;\r
+\r
+public class PlaceArtifactOnStream implements PlaceArtifact {\r
+       private PrintStream out;\r
+\r
+       public PlaceArtifactOnStream(PrintStream printStream) {\r
+               out = printStream;\r
+       }\r
+\r
+       @Override\r
+       public boolean place(Trans trans, CertInfo capi, Artifact a) {\r
+               if(capi.getNotes()!=null && capi.getNotes().length()>0) {\r
+                       trans.info().printf("Warning:    %s\n",capi.getNotes());\r
+               }\r
+               out.printf("Challenge:  %s\n",capi.getChallenge());\r
+               out.printf("PrivateKey:\n%s\n",capi.getPrivatekey());\r
+               out.println("Certificate Chain:");\r
+               for(String c : capi.getCerts()) {\r
+                       out.println(c);\r
+               }\r
+               return true;\r
+       }\r
+}\r
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
new file mode 100644 (file)
index 0000000..ab77ca2
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.inno.env.util.Split;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public class PlaceArtifactScripts extends ArtifactDir {\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               try {\r
+                       // Setup check.sh script\r
+                       String filename = arti.getAppName()+".check.sh";\r
+                       File f1 = new File(dir,filename);\r
+                       String email = arti.getNotification() + '\n';\r
+                       if(email.startsWith("mailto:")) {\r
+                               email=email.substring(7);\r
+                       }  else {\r
+                               email=arti.getOsUser() + '\n';\r
+                       }\r
+                       \r
+                       StringBuilder classpath = new StringBuilder();\r
+                       boolean first = true;\r
+                       for(String pth : Split.split(File.pathSeparatorChar, System.getProperty("java.class.path"))) {\r
+                               if(first) {\r
+                                       first=false;\r
+                               } else {\r
+                                       classpath.append(File.pathSeparatorChar);\r
+                               }\r
+                               File f = new File(pth);\r
+                               classpath.append(f.getCanonicalPath().replaceAll("[0-9]+\\.[0-9]+\\.[0-9]+","*"));\r
+                       }\r
+                       \r
+                       write(f1,Chmod.to644,\r
+                                       "#!/bin/bash " + f1.getCanonicalPath()+'\n',\r
+                                       "# Certificate Manager Check Script\n",\r
+                                       "# Check on Certificate, and renew if needed.\n",\r
+                                       "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',\r
+                                       "DIR="+arti.getDir()+'\n',\r
+                                       "APP="+arti.getAppName()+'\n',\r
+                                       "EMAIL="+email,\r
+                                       "CP=\""+classpath.toString()+"\"\n",\r
+                                       checkScript\r
+                                       );\r
+                       \r
+                       // Setup check.sh script\r
+                       File f2 = new File(dir,arti.getAppName()+".crontab.sh");\r
+                       write(f2,Chmod.to644,\r
+                                       "#!/bin/bash " + f1.getCanonicalPath()+'\n',\r
+                                       "# Certificate Manager Crontab Loading Script\n",\r
+                                       "# Add/Update a Crontab entry, that adds a check on Certificate Manager generated Certificate nightly.\n",\r
+                                       "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',\r
+                                       "TFILE=\"/tmp/cmcron$$.temp\"\n",\r
+                                       "DIR=\""+arti.getDir()+"\"\n",\r
+                                       "CF=\""+arti.getAppName()+" Certificate Check Script\"\n",\r
+                                       "SCRIPT=\""+f1.getCanonicalPath()+"\"\n",\r
+                                       cronScript\r
+                                       );\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       private final static String checkScript = \r
+                       "> $DIR/$APP.msg\n\n" +\r
+                       "function mailit {\n" +\r
+                       "  printf \"$*\" | /bin/mail -s \"AAF Certman Notification for `uname -n`\" $EMAIL\n"+\r
+                       "}\n\n" +\r
+                       System.getProperty("java.home") + "/bin/" +"java -cp $CP " +\r
+                               CmAgent.class.getName() + \r
+                               " cadi_prop_files=$DIR/$APP.props check 2>  $DIR/$APP.STDERR > $DIR/$APP.STDOUT\n" +\r
+                       "case \"$?\" in\n" +\r
+                       "  0)\n" +\r
+                       "    # Note: Validation will be mailed only the first day after any modification\n" +\r
+                       "    if [ \"`find $DIR -mtime 0 -name $APP.check.sh`\" != \"\" ] ; then\n" +\r
+                       "       mailit `echo \"Certficate Validated:\\n\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    else\n" +\r
+                       "       cat $DIR/$APP.msg\n" +\r
+                       "    fi\n" +\r
+                       "    ;;\n" +\r
+                       "  1) mailit \"Error with Certificate Check:\\\\n\\\\nCheck logs $DIR/$APP.STDOUT and $DIR/$APP.STDERR on `uname -n`\"\n" +\r
+                       "    ;;\n" +\r
+                       "  2) mailit `echo \"Certificate Check Error\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    ;;\n" +\r
+                       "  10) mailit `echo \"Certificate Replaced\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "      if [ -e $DIR/$APP.restart.sh ]; then\n" +\r
+                       "        # Note: it is THIS SCRIPT'S RESPONSIBILITY to notify upon success or failure as necessary!!\n" +\r
+                       "        /bin/sh $DIR/$APP.restart.sh\n" +\r
+                       "      fi\n" +\r
+                       "    ;;\n" +\r
+                       "  *) mailit `echo \"Unknown Error code for CM Agent\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    ;;\n" +\r
+                       " esac\n\n" +\r
+                       " # Note: make sure to cover this sripts' exit Code\n";\r
+       \r
+       private final static String cronScript = \r
+                       "crontab -l | sed -n \"/#### BEGIN $CF/,/END $CF ####/!p\" > $TFILE\n" +\r
+                       "# Note: Randomize Minutes (0-60) and hours (1-4)\n" +\r
+                       "echo \"#### BEGIN $CF ####\" >> $TFILE\n" +\r
+                       "echo \"$(( $RANDOM % 60)) $(( $(( $RANDOM % 3 )) + 1 )) * * * /bin/bash $SCRIPT " +\r
+                               ">> $DIR/cronlog 2>&1 \" >> $TFILE\n" +\r
+                       "echo \"#### END $CF ####\" >> $TFILE\n" +\r
+                       "crontab $TFILE\n" +\r
+                       "rm $TFILE\n";\r
+}\r
+\r
+\r
+\r
diff --git a/aaf/src/main/java/com/att/cadi/sso/AAFSSO.java b/aaf/src/main/java/com/att/cadi/sso/AAFSSO.java
new file mode 100644 (file)
index 0000000..5d0d342
--- /dev/null
@@ -0,0 +1,286 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.sso;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Properties;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.util.MyConsole;\r
+import com.att.cadi.util.SubStandardConsole;\r
+import com.att.cadi.util.TheConsole;\r
+\r
+\r
+public class AAFSSO {\r
+       public static final MyConsole  cons = TheConsole.implemented()?new TheConsole():new SubStandardConsole();\r
+       \r
+       private Properties diskprops = null; // use for temp storing User/Password on disk\r
+       private File dot_aaf = null, sso=null; // instantiated, if ever, with diskprops\r
+       \r
+       boolean removeSSO=false;\r
+       boolean loginOnly = false;\r
+       private PropAccess access;\r
+       private StringBuilder err;\r
+       private String user,encrypted_pass;\r
+       private boolean use_X509;\r
+\r
+       private PrintStream os, stdout=null,stderr=null;\r
+\r
+       private Method close;\r
+\r
+       public AAFSSO(String[] args) throws IOException, CadiException {\r
+               List<String> larg = new ArrayList<String>(args.length);\r
+\r
+               // Cover for bash's need to escape *... (\\*)\r
+               // also, remove SSO if required\r
+               for (int i = 0; i < args.length; ++i) {\r
+                       if ("\\*".equals(args[i])) {\r
+                               args[i] = "*";\r
+                       }\r
+                       \r
+                       if("-logout".equalsIgnoreCase(args[i])) {\r
+                               removeSSO=true;\r
+                       } else if("-login".equalsIgnoreCase(args[i])) {\r
+                               loginOnly = true;\r
+                       } else {\r
+                               larg.add(args[i]);\r
+                       }\r
+               }\r
+               \r
+               String[] nargs = new String[larg.size()];\r
+               larg.toArray(nargs);\r
+\r
+               dot_aaf = new File(System.getProperty("user.home")+"/.aaf");\r
+               if(!dot_aaf.exists()) {\r
+                       dot_aaf.mkdirs();\r
+               }\r
+               File f = new File(dot_aaf,"sso.out");\r
+               os = new PrintStream(new FileOutputStream(f,true));\r
+               stdout = System.out;\r
+               stderr = System.err;\r
+               System.setOut(os);\r
+               System.setErr(os);\r
+\r
+               access = new PropAccess(os,nargs);\r
+               Config.setDefaultRealm(access);\r
+\r
+               user = access.getProperty(Config.AAF_MECHID);\r
+               encrypted_pass = access.getProperty(Config.AAF_MECHPASS);\r
+               \r
+               File dot_aaf_kf = new File(dot_aaf,"keyfile");\r
+               \r
+               sso = new File(dot_aaf,"sso.props");\r
+               if(removeSSO) {\r
+                       if(dot_aaf_kf.exists()) {\r
+                               dot_aaf_kf.setWritable(true,true);\r
+                               dot_aaf_kf.delete();\r
+                       }\r
+                       if(sso.exists()) {\r
+                               sso.delete();\r
+                       }\r
+                       System.out.println("AAF SSO information removed");\r
+                       System.exit(0);\r
+               }\r
+               \r
+               if(!dot_aaf_kf.exists()) {\r
+                       FileOutputStream fos = new FileOutputStream(dot_aaf_kf);\r
+                       try {\r
+                               fos.write(Symm.encrypt.keygen());\r
+                               dot_aaf_kf.setExecutable(false,false);\r
+                               dot_aaf_kf.setWritable(false,false);\r
+                               dot_aaf_kf.setReadable(false,false);\r
+                               dot_aaf_kf.setReadable(true, true);\r
+                       } finally {\r
+                               fos.close();\r
+                       }\r
+               }\r
+\r
+               String keyfile = access.getProperty(Config.CADI_KEYFILE); // in case it's CertificateMan props\r
+               if(keyfile==null) {\r
+                       access.setProperty(Config.CADI_KEYFILE, dot_aaf_kf.getAbsolutePath());\r
+               }\r
+               \r
+               String alias = access.getProperty(Config.CADI_ALIAS);\r
+               if(user==null && alias!=null && access.getProperty(Config.CADI_KEYSTORE_PASSWORD)!=null) {\r
+                       user = alias;\r
+                       access.setProperty(Config.AAF_MECHID, user);\r
+                       use_X509 = true;\r
+               } else {\r
+                       use_X509 = false;\r
+                       Symm decryptor = Symm.obtain(dot_aaf_kf);\r
+                       if (user==null) {\r
+                               if(sso.exists() && sso.lastModified()>System.currentTimeMillis()-(8*60*60*1000 /* 8 hours */)) {\r
+                                       String cm_url = access.getProperty(Config.CM_URL); // SSO might overwrite...\r
+                                       FileInputStream fos = new FileInputStream(sso);\r
+                                       try {\r
+                                               access.load(fos);\r
+                                               user = access.getProperty(Config.AAF_MECHID);\r
+                                               encrypted_pass = access.getProperty(Config.AAF_MECHPASS);\r
+                                               // decrypt with .aaf, and re-encrypt with regular Keyfile\r
+                                               access.setProperty(Config.AAF_MECHPASS, \r
+                                                               access.encrypt(decryptor.depass(encrypted_pass)));\r
+                                               if(cm_url!=null) { //Command line CM_URL Overwrites ssofile.\r
+                                                       access.setProperty(Config.CM_URL, cm_url);\r
+                                               }\r
+                                       } finally {\r
+                                               fos.close();\r
+                                       }\r
+                               } else {\r
+                                       diskprops = new Properties();\r
+                                       String realm = Config.getDefaultRealm();\r
+                                       // Turn on Console Sysout\r
+                                       System.setOut(stdout);\r
+                                       user=cons.readLine("aaf_id(%s@%s): ",System.getProperty("user.name"),realm);\r
+                                       if(user==null) {\r
+                                               user = System.getProperty("user.name")+'@'+realm;\r
+                                       } else if(user.length()==0) { // \r
+                                               user = System.getProperty("user.name")+'@' + realm;\r
+                                       } else if(user.indexOf('@')<0 && realm!=null) {\r
+                                               user = user+'@'+realm;\r
+                                       }\r
+                                       access.setProperty(Config.AAF_MECHID,user);\r
+                                       diskprops.setProperty(Config.AAF_MECHID,user);\r
+                                       encrypted_pass = new String(cons.readPassword("aaf_password: "));\r
+                                       System.setOut(os);\r
+                                       encrypted_pass = Symm.ENC+decryptor.enpass(encrypted_pass);\r
+                                       access.setProperty(Config.AAF_MECHPASS,encrypted_pass);\r
+                                       diskprops.setProperty(Config.AAF_MECHPASS,encrypted_pass);\r
+                                       diskprops.setProperty(Config.CADI_KEYFILE, access.getProperty(Config.CADI_KEYFILE));\r
+                               }\r
+                       }\r
+               }\r
+               if (user == null) {\r
+                       err = new StringBuilder("Add -D" + Config.AAF_MECHID + "=<id> ");\r
+               }\r
+       \r
+               if (encrypted_pass == null && alias==null) {\r
+                       if (err == null) {\r
+                               err = new StringBuilder();\r
+                       } else {\r
+                               err.append("and ");\r
+                       }\r
+                       err.append("-D" + Config.AAF_MECHPASS + "=<passwd> ");\r
+               }\r
+       }\r
+       \r
+       public void setLogDefault() {\r
+               access.setLogLevel(PropAccess.DEFAULT);\r
+               if(stdout!=null) {\r
+                       System.setOut(stdout);\r
+               }\r
+       }\r
+\r
+       public void setStdErrDefault() {\r
+               access.setLogLevel(PropAccess.DEFAULT);\r
+               if(stderr!=null) {\r
+                       System.setErr(stderr);\r
+               }\r
+       }\r
+\r
+       public void setLogDefault(Level level) {\r
+               access.setLogLevel(level);\r
+               if(stdout!=null) {\r
+                       System.setOut(stdout);\r
+               }\r
+       }\r
+       \r
+       public boolean loginOnly() {\r
+               return loginOnly;\r
+       }\r
+\r
+       public void addProp(String key, String value) {\r
+               if(diskprops!=null) {\r
+                       diskprops.setProperty(key, value);\r
+               }\r
+       }\r
+       \r
+       public void writeFiles() throws IOException {\r
+               // Store Creds, if they work \r
+               if(diskprops!=null) {\r
+                       if(!dot_aaf.exists()) {\r
+                               dot_aaf.mkdirs();\r
+                       }\r
+                       FileOutputStream fos = new FileOutputStream(sso);\r
+                       try {\r
+                               diskprops.store(fos, "AAF Single Signon");\r
+                       } finally {\r
+                               fos.close();\r
+                               sso.setWritable(false,false);\r
+                               sso.setExecutable(false,false);\r
+                               sso.setReadable(false,false);\r
+                               sso.setReadable(true,true);\r
+                       }\r
+               }\r
+               if(sso!=null) {\r
+                       sso.setReadable(false,false);\r
+                       sso.setWritable(false,false);\r
+                       sso.setExecutable(false,false);\r
+                       sso.setReadable(true,true);\r
+                       sso.setWritable(true,true);\r
+               }\r
+       }\r
+\r
+       public PropAccess access() {\r
+               return access;\r
+       }\r
+\r
+       public StringBuilder err() {\r
+               return err;\r
+       }\r
+       \r
+       public String user() {\r
+               return user;\r
+       }\r
+       \r
+       public String enc_pass() {\r
+               return encrypted_pass;\r
+       }\r
+       \r
+       public boolean useX509() {\r
+               return use_X509;\r
+       }\r
+       \r
+       public void close() {\r
+               if(close!=null) {\r
+                       try {\r
+                               close.invoke(null);\r
+                       } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {\r
+                               // nothing to do here.\r
+                       }\r
+                       close = null;\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/src/assemble/cadi-aaf-test.xml b/aaf/src/src/assemble/cadi-aaf-test.xml
new file mode 100644 (file)
index 0000000..a6671ba
--- /dev/null
@@ -0,0 +1,110 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">\r
+  \r
+  <id>test</id>\r
+  <formats>\r
+    <format>zip</format>\r
+  </formats>\r
+\r
+  <includeBaseDirectory>true</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.cadi:cadi-core</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.cadi:cadi-aaf</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>org.eclipse.jetty.aggregate:jetty-all</include>\r
+      </includes>\r
+    </dependencySet>\r
+\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>org.eclipse.jetty.orbit:javax.servlet</include>\r
+      </includes>\r
+    </dependencySet>\r
+\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>javax:servlet</include>\r
+      </includes>\r
+    </dependencySet>\r
+    \r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.aft:dme2</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>test</scope>\r
+      <includes>\r
+       <include>com.att.aft.discovery:discovery-clt</include>\r
+      </includes>\r
+    </dependencySet>\r
+    <dependencySet>\r
+      <unpack>false</unpack>\r
+      <scope>compile</scope>\r
+      <includes>\r
+       <include>com.att.cssa:rosetta</include>\r
+      </includes>\r
+    </dependencySet>\r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>run</directory>\r
+      <includes>\r
+       <include>cadi.properties</include>\r
+       <include>keyfile</include>\r
+       <include>start.sh</include>\r
+      </includes>\r
+    </fileSet>\r
+      <fileSet>\r
+      <includes>\r
+       <include>../cadi/target/cadi-core*tests.jar</include>\r
+      </includes>\r
+    </fileSet>\r
+   </fileSets>\r
+  \r
+</assembly>\r
diff --git a/aaf/src/src/assemble/cadi-aaf.xml b/aaf/src/src/assemble/cadi-aaf.xml
new file mode 100644 (file)
index 0000000..578037b
--- /dev/null
@@ -0,0 +1,53 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">\r
+  \r
+  <id>full</id>\r
+  <formats>\r
+    <format>jar</format>\r
+  </formats>\r
+\r
+  <includeBaseDirectory>false</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <unpack>true</unpack>\r
+      <scope>compile</scope>\r
+      <includes>\r
+       <include>com.att.authz:authz-client</include>\r
+       <include>com.att.cadi:cadi-aaf</include>\r
+       <include>com.att.cadi:cadi-core</include>\r
+       <include>com.att.cadi:cadi-client</include>\r
+       <include>com.att.inno:env</include>\r
+       <include>com.att.inno:rosetta</include>\r
+      </includes>\r
+    </dependencySet>\r
+    \r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>src/main/xsd</directory>\r
+    </fileSet>\r
+   </fileSets>\r
+</assembly>\r
diff --git a/aaf/src/src/main/java/Examples.java b/aaf/src/src/main/java/Examples.java
new file mode 100644 (file)
index 0000000..91f313f
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class Examples {\r
+       public static void main(String[] args) {\r
+               if(args.length<1) {\r
+                       System.out.println("Usage: Examples <name> [\"optional\" - will show optional fields]");\r
+               } else {\r
+                       boolean options = args.length>1&&"optional".equals(args[1]);\r
+                       try {\r
+                               RosettaEnv env = new RosettaEnv();\r
+                               System.out.println(com.att.cadi.aaf.client.Examples.print(env, args[0], options));\r
+                       } catch (Exception e) {\r
+                               System.out.println(e.getMessage());\r
+                       }\r
+               }\r
+       }\r
+       \r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/AAFPermission.java b/aaf/src/src/main/java/com/att/cadi/aaf/AAFPermission.java
new file mode 100644 (file)
index 0000000..c436db4
--- /dev/null
@@ -0,0 +1,107 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import com.att.cadi.Permission;\r
+\r
+/**\r
+ * A Class that understands the AAF format of Permission (name/type/action)\r
+ *  or String "name|type|action"\r
+ * \r
+ *\r
+ */\r
+public class AAFPermission implements Permission {\r
+       protected String type,instance,action,key;\r
+\r
+       protected AAFPermission() {}\r
+\r
+       public AAFPermission(String type, String instance, String action) {\r
+               this.type = type;\r
+               this.instance = instance;\r
+               this.action = action;\r
+               key = type + '|' + instance + '|' + action;\r
+       }\r
+       \r
+       /**\r
+        * Match a Permission\r
+        * if Permission is Fielded type "Permission", we use the fields\r
+        * otherwise, we split the Permission with '|'\r
+        * \r
+        * when the type or action starts with REGEX indicator character ( ! ),\r
+        * then it is evaluated as a regular expression.\r
+        * \r
+        * If you want a simple field comparison, it is faster without REGEX\r
+        */\r
+       public boolean match(Permission p) {\r
+               if(p instanceof AAFPermission) {\r
+                       AAFPermission ap = (AAFPermission)p;\r
+                       // Note: In AAF > 1.0, Accepting "*" from name would violate multi-tenancy\r
+                       // Current solution is only allow direct match on Type.\r
+                       // 8/28/2014 - added REGEX ability\r
+                       if(type.equals(ap.getName()))  \r
+                               if(PermEval.evalInstance(instance,ap.getInstance()))\r
+                                       if(PermEval.evalAction(action,ap.getAction()))\r
+                                               return true;\r
+               } else {\r
+                       // Permission is concatenated together: separated by |\r
+                       String[] aaf = p.getKey().split("[\\s]*\\|[\\s]*",3);\r
+                       if(aaf.length>0 && type.equals(aaf[0]))\r
+                               if(PermEval.evalInstance(instance,aaf.length>1?aaf[1]:"*"))\r
+                                       if(PermEval.evalAction(action,aaf.length>2?aaf[2]:"*"))\r
+                                               return true;\r
+               }                               \r
+               return false;\r
+       }\r
+\r
+        \r
+       public String getName() {\r
+               return type;\r
+       }\r
+       \r
+       public String getInstance() {\r
+               return instance;\r
+       }\r
+       \r
+       public String getAction() {\r
+               return action;\r
+       }\r
+       \r
+       public String getKey() {\r
+               return key;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Permission#permType()\r
+        */\r
+       public String permType() {\r
+               return "AAF";\r
+       }\r
+\r
+       public String toString() {\r
+               return "AAFPermission:\n\tType: " + type + \r
+                               "\n\tInstance: " + instance +\r
+                               "\n\tAction: " + action +\r
+                               "\n\tKey: " + key;\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/AAFTransmutate.java b/aaf/src/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
new file mode 100644 (file)
index 0000000..fca8e8f
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import java.security.Principal;\r
+import java.util.regex.Pattern;\r
+\r
+import com.att.cadi.Transmutate;\r
+import com.att.cadi.lur.ConfigPrincipal;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.CSPPrincipal_T;\r
+\r
+/**\r
+ * AAFTransmutate\r
+ * \r
+ * Each System determines the mechanisms for which one Principal is transmutated to another, such as whether it is created\r
+ * independently, etc.\r
+ * \r
+ * For AAF, the only important thing is that these are valid ATTUID/mechIDs, to avoid unnecessary user hits\r
+ * \r
+ * attUIDs look like ab1234 or AB1234 or AZ123a\r
+ * mechids look like m12345\r
+ * \r
+ *\r
+ */\r
+public final class AAFTransmutate implements Transmutate<Principal> {\r
+       private Pattern pattern = Pattern.compile("[a-zA-Z]\\w\\d\\d\\d\\w");\r
+\r
+       public Principal mutate(Principal p) {\r
+               // Accept these three internal kinds of Principals\r
+               if(p instanceof CSPPrincipal_T \r
+                       || p instanceof BasicPrincipal\r
+                       || p instanceof ConfigPrincipal) { \r
+                       return p;\r
+               } else { \r
+                       String name = p.getName();\r
+                       final int idx = name.indexOf('@');\r
+                       if(idx>0) { // strip off any domain\r
+                               name = name.substring(0,idx); \r
+                       }\r
+\r
+                       // Check for ATTUID specs before creating CSP_T\r
+                       return pattern.matcher(name).matches()?\r
+                               new CSP_T(name):\r
+                               null;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Essential Principal reflecting CSP Principal\r
+        * \r
+        *\r
+        */\r
+       private final class CSP_T implements CSPPrincipal_T {\r
+               private String name;\r
+               public CSP_T(String name) {\r
+                       this.name = name;\r
+               }\r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/PermEval.java b/aaf/src/src/main/java/com/att/cadi/aaf/PermEval.java
new file mode 100644 (file)
index 0000000..b721968
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf;\r
+\r
+import com.att.inno.env.util.Split;\r
+\r
+\r
+public class PermEval {\r
+       public static final char START_REGEX_CHAR = '!';\r
+       public static final char START_INST_KEY_CHAR=':';\r
+       public static final char ALT_START_INST_KEY_CHAR='/';\r
+       \r
+       public static final char LIST_SEP = ',';\r
+       public static final String INST_KEY_REGEX = new StringBuilder().append(START_INST_KEY_CHAR).toString();\r
+       public static final String ASTERIX = "*";\r
+       \r
+       /**\r
+        * Evaluate Instance\r
+        * \r
+        * Instance can be more complex.  It can be a string, a Regular Expression, or a ":" separated Key \r
+        * who's parts can also be a String, Regular Expression.\r
+        * \r
+        * sInst = Server's Instance\r
+        * In order to prevent false matches, keys must be the same length to count as equal\r
+        * Changing this will break existing users, like Cassandra.  9-4-2015\r
+        */\r
+        public static boolean evalInstance(String sInst, String pInst) {\r
+                 if(ASTERIX.equals(sInst)) return true;                        // If Server's String is "*", then it accepts every Instance\r
+                 char firstChar = pInst.charAt(0);\r
+                 char startChar = firstChar==ALT_START_INST_KEY_CHAR?ALT_START_INST_KEY_CHAR:START_INST_KEY_CHAR;\r
+                 switch(pInst.charAt(0)) {                                             // First char\r
+                       case START_REGEX_CHAR:                                                  // Evaluate as Regular Expression\r
+                               String pItem = pInst.substring(1);\r
+                           for(String sItem : Split.split(LIST_SEP,sInst)) {           // allow for "," definition in Action\r
+                               return sItem.matches(pItem);\r
+                           }\r
+                        \r
+                       case START_INST_KEY_CHAR:                                               // Evaluate a special Key field, i.e.:xyz:*:!df.*\r
+                       case ALT_START_INST_KEY_CHAR:                                   // Also allow '/' as special Key Field, i.e. /xyz/*/!.*\r
+                               if(sInst.charAt(0)==startChar) {  // To compare key-to-key, both strings must be keys\r
+                                       String[] skeys=Split.split(startChar,sInst);\r
+                                       String[] pkeys=Split.split(startChar,pInst);\r
+                                       if(skeys.length!=pkeys.length) return false;\r
+                                       \r
+                                       boolean pass = true;\r
+                                       for(int i=1;pass && i<skeys.length;++i) {                               // We start at 1, because the first one, being ":" is always ""\r
+                                               if(ASTERIX.equals(skeys[i]))continue;                           // Server data accepts all for this key spot\r
+                                               pass = false;\r
+                                           for(String sItem : Split.split(LIST_SEP,skeys[i])) {                // allow for "," definition in Action\r
+                                                       if(pkeys[i].length()==0) {\r
+                                                               if(pass=sItem.length()==0) {\r
+                                                                       break;                                                                  // Both Empty, keep checking\r
+                                                               }\r
+//                                                     } else if(pkeys[i].charAt(0)==START_REGEX_CHAR) { \r
+//                                                             if(pass=sItem.matches(pkeys[i].substring(1))) {\r
+//                                                                     break;                                                                  // Matches, keep checking\r
+//                                                             }\r
+                                                       } else if(sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like *\r
+                                                               if(pass=pkeys[i].matches(sItem.substring(1))) {\r
+                                                                       break;                                                                  // Matches, keep checking\r
+                                                               }\r
+                                                       } else if(skeys[i].endsWith(ASTERIX)) {\r
+                                                               if(pass=endAsterixCompare(skeys[i],pkeys[i])) {\r
+                                                                       break;\r
+                                                               }\r
+                                                       } else {\r
+                                                               if(pass=sItem.equals(pkeys[i]))\r
+                                                                       break;                                                                  // Equal, keep checking\r
+                                                       }\r
+                                           }\r
+                                       }\r
+                                       return pass;                                                                                    // return whether passed all key checks\r
+                               }\r
+                               return false;                                                           // if first chars aren't the same, further String compare not necessary\r
+                       default:                                                                                // Evaluate as String Compare\r
+                           for(String sItem : Split.split(LIST_SEP,sInst)) {   // allow for "," separator //TODO is this only for actions?\r
+                               if(sItem.endsWith(ASTERIX)) {\r
+                                       if(endAsterixCompare(sInst, pInst));\r
+                               } else if(sItem.equals(pInst)) {\r
+                                       return true;\r
+                               }\r
+                           }\r
+                           return false;\r
+                 }\r
+        }\r
+        \r
+        private static boolean endAsterixCompare(String sInst, String pInst) {\r
+                       final int len = sInst.length()-1;\r
+                       if(pInst.length()<len) {\r
+                               return false;\r
+                       }\r
+                       for(int j=0;j<len;++j) {\r
+                               if(pInst.charAt(j)!=sInst.charAt(j)) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       return true;\r
+       }\r
+\r
+       /**\r
+         * Evaluate Action\r
+         * \r
+         * sAction = Stored Action...\r
+         * pAction = Present Action... the Permission to validate against.\r
+         * Action is not quite as complex.  But we write it in this function so it can be consistent\r
+         */\r
+         public static boolean evalAction(String sAction,String pAction) {\r
+                 if(ASTERIX.equals(sAction))return true;                    // If Server's String is "*", then it accepts every Action\r
+                 for(String sItem : Split.split(LIST_SEP,sAction)) {            // allow for "," definition in Action\r
+                         if (pAction.charAt(0)==START_REGEX_CHAR?       // First char\r
+                                     sItem.matches(pAction.substring(1)):   // Evaluate as Regular Expression\r
+                                     sItem.equals(pAction))                 // Evaluate as String Compare\r
+                                               return true;\r
+                 }             \r
+                 return false;\r
+         }\r
+        \r
+         /**\r
+          * Split.split by Char\r
+          * \r
+          * Note: I read the String Split.split and Pattern Split.split code, and we can do this more efficiently for a single Character\r
+          */\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/client/ErrMessage.java b/aaf/src/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
new file mode 100644 (file)
index 0000000..7fc776a
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.client;\r
+\r
+import java.io.PrintStream;\r
+\r
+import aaf.v2_0.Error;\r
+\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.util.Vars;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class ErrMessage {\r
+       private RosettaDF<Error> errDF;\r
+       \r
+       public ErrMessage(RosettaEnv env) throws APIException {\r
+               errDF = env.newDataFactory(Error.class);\r
+       }\r
+\r
+       /**\r
+        * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.\r
+        * \r
+        * This code will create a meaningful string from this format. \r
+        * \r
+        * @param ps\r
+        * @param df\r
+        * @param r\r
+        * @throws APIException\r
+        */\r
+       public void printErr(PrintStream ps,  String attErrJson) throws APIException {\r
+               StringBuilder sb = new StringBuilder();\r
+               Error err = errDF.newData().in(TYPE.JSON).load(attErrJson).asObject();\r
+               ps.println(toMsg(sb,err));\r
+       }\r
+       \r
+       /**\r
+        * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.\r
+        * \r
+        * This code will create a meaningful string from this format. \r
+        * \r
+        * @param sb\r
+        * @param df\r
+        * @param r\r
+        * @throws APIException\r
+        */\r
+       public StringBuilder toMsg(StringBuilder sb,  String attErrJson) throws APIException {\r
+               return toMsg(sb,errDF.newData().in(TYPE.JSON).load(attErrJson).asObject());\r
+       }\r
+       \r
+       public StringBuilder toMsg(Future<?> future) {\r
+               return toMsg(new StringBuilder(),future);\r
+       }\r
+       \r
+       public StringBuilder toMsg(StringBuilder sb, Future<?> future) {\r
+               try {\r
+                       toMsg(sb,errDF.newData().in(TYPE.JSON).load(future.body()).asObject());\r
+               } catch(Exception e) {\r
+                       //just print what we can\r
+                       sb.append(future.code());\r
+                       sb.append(": ");\r
+                       sb.append(future.body());\r
+               }\r
+               return sb;\r
+       }\r
+\r
+       public StringBuilder toMsg(StringBuilder sb, Error err) {\r
+               sb.append(err.getMessageId());\r
+               sb.append(' ');\r
+               String[] vars = new String[err.getVariables().size()];\r
+               err.getVariables().toArray(vars);\r
+               Vars.convert(sb, err.getText(),vars);\r
+               return sb;\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/client/Examples.java b/aaf/src/src/main/java/com/att/cadi/aaf/client/Examples.java
new file mode 100644 (file)
index 0000000..e8a4756
--- /dev/null
@@ -0,0 +1,445 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.client;\r
+\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.GregorianCalendar;\r
+\r
+import aaf.v2_0.Approval;\r
+import aaf.v2_0.Approvals;\r
+import aaf.v2_0.CredRequest;\r
+import aaf.v2_0.Keys;\r
+import aaf.v2_0.NsRequest;\r
+import aaf.v2_0.Nss;\r
+import aaf.v2_0.Nss.Ns;\r
+import aaf.v2_0.Perm;\r
+import aaf.v2_0.PermKey;\r
+import aaf.v2_0.PermRequest;\r
+import aaf.v2_0.Perms;\r
+import aaf.v2_0.Pkey;\r
+import aaf.v2_0.Request;\r
+import aaf.v2_0.Role;\r
+import aaf.v2_0.RoleKey;\r
+import aaf.v2_0.RolePermRequest;\r
+import aaf.v2_0.RoleRequest;\r
+import aaf.v2_0.Roles;\r
+import aaf.v2_0.UserRole;\r
+import aaf.v2_0.UserRoleRequest;\r
+import aaf.v2_0.UserRoles;\r
+import aaf.v2_0.Users;\r
+import aaf.v2_0.Users.User;\r
+\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class Examples {\r
+       public static <C> String print(RosettaEnv env, String nameOrContentType, boolean optional) throws APIException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {\r
+               // Discover ClassName\r
+               String className = null;\r
+               String version = null;\r
+               TYPE type = TYPE.JSON; // default\r
+               if(nameOrContentType.startsWith("application/")) {\r
+                       for(String ct : nameOrContentType.split("\\s*,\\s*")) {\r
+                               for(String elem : ct.split("\\s*;\\s*")) {\r
+                                       if(elem.endsWith("+json")) {\r
+                                               type = TYPE.JSON;\r
+                                               className = elem.substring(elem.indexOf('/')+1, elem.length()-5);\r
+                                       } else if(elem.endsWith("+xml")) {\r
+                                               type = TYPE.XML;\r
+                                               className = elem.substring(elem.indexOf('/')+1, elem.length()-4);\r
+                                       } else if(elem.startsWith("version=")) {\r
+                                               version = elem.substring(8);\r
+                                       }\r
+                               }\r
+                               if(className!=null && version!=null)break;\r
+                       }\r
+                       if(className==null) {\r
+                               throw new APIException(nameOrContentType + " does not contain Class Information");\r
+                       }\r
+               } else {\r
+                       className = nameOrContentType;\r
+               }\r
+               \r
+               // No Void.class in aaf.v2_0 package causing errors when trying to use a newVoidv2_0\r
+               // method similar to others in this class. This makes it work, but is it right?\r
+               if ("Void".equals(className)) return "";\r
+                               \r
+               if("1.1".equals(version)) {\r
+                       version = "v1_0";\r
+               } else if(version!=null) {\r
+                       version = "v" + version.replace('.', '_');\r
+               } else {\r
+                       version = "v2_0";\r
+               }\r
+               \r
+               Class<?> cls;\r
+               try {\r
+                       cls = Examples.class.getClassLoader().loadClass("aaf."+version+'.'+className);\r
+               } catch (ClassNotFoundException e) {\r
+                       throw new APIException(e);\r
+               }\r
+               \r
+               Method meth;\r
+               try {\r
+                       meth = Examples.class.getDeclaredMethod("new"+cls.getSimpleName()+version,boolean.class);\r
+               } catch (Exception e) {\r
+                       throw new APIException("ERROR: " + cls.getName() + " does not have an Example in Code.  Request from AAF Developers");\r
+               }\r
+               \r
+               RosettaDF<C> df = env.newDataFactory(cls);\r
+               df.option(Data.PRETTY);\r
+               \r
+               Object data = meth.invoke(null,optional);\r
+               \r
+               @SuppressWarnings("unchecked")\r
+               String rv = df.newData().load((C)data).out(type).asString();\r
+//             Object obj = df.newData().in(type).load(rv).asObject();\r
+               return rv;\r
+       }\r
+       \r
+       /*\r
+        *  Set Base Class Request (easier than coding over and over)\r
+        */\r
+       private static void setOptional(Request req) {\r
+               GregorianCalendar gc = new GregorianCalendar();\r
+               req.setStart(Chrono.timeStamp(gc));\r
+               gc.add(GregorianCalendar.MONTH, 6);\r
+               req.setEnd(Chrono.timeStamp(gc));\r
+//             req.setForce("false");\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Request newRequestv2_0(boolean optional) {\r
+               Request r = new Request();\r
+               setOptional(r);\r
+               return r;\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private static RolePermRequest newRolePermRequestv2_0(boolean optional) {\r
+               RolePermRequest rpr = new RolePermRequest();\r
+               Pkey pkey = new Pkey();\r
+               pkey.setType("com.att.myns.mytype");\r
+               pkey.setInstance("myInstance");\r
+               pkey.setAction("myAction");\r
+               rpr.setPerm(pkey);\r
+               rpr.setRole("com.att.myns.myrole");\r
+               if(optional)setOptional(rpr);\r
+               return rpr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Roles newRolesv2_0(boolean optional) {\r
+               Role r;\r
+               Pkey p;\r
+               Roles rs = new Roles();\r
+               rs.getRole().add(r = new Role());\r
+               r.setName("com.att.myns.myRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               \r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+               \r
+               rs.getRole().add(r = new Role());\r
+               r.setName("com.att.myns.myOtherRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myOtherType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               \r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myOthertype");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+\r
+               return rs;\r
+       }\r
+       \r
+       \r
+       @SuppressWarnings("unused")\r
+       private static PermRequest newPermRequestv2_0(boolean optional) {\r
+               PermRequest pr = new PermRequest();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               if(optional) {\r
+                       pr.setDescription("Short and meaningful verbiage about the Permission");\r
+                       \r
+                       setOptional(pr);\r
+               }\r
+               return pr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Perm newPermv2_0(boolean optional) {\r
+               Perm pr = new Perm();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               pr.getRoles().add("com.att.myns.myRole");\r
+               pr.getRoles().add("com.att.myns.myRole2");\r
+               pr.setDescription("This is my description, and I'm sticking with it");\r
+               if(optional) {\r
+                       pr.setDescription("Short and meaningful verbiage about the Permission");\r
+               }\r
+               return pr;\r
+       }\r
+\r
+\r
+       @SuppressWarnings("unused")\r
+       private static PermKey newPermKeyv2_0(boolean optional) {\r
+               PermKey pr = new PermKey();\r
+               pr.setType("com.att.myns.myType");\r
+               pr.setInstance("myInstance");\r
+               pr.setAction("myAction");\r
+               return pr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Perms newPermsv2_0(boolean optional) {\r
+               Perms perms = new Perms();\r
+               Perm p;\r
+               perms.getPerm().add(p=new Perm());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+               p.getRoles().add("com.att.myns.myRole");\r
+               p.getRoles().add("com.att.myns.myRole2");\r
+               \r
+\r
+               perms.getPerm().add(p=new Perm());\r
+               p.setType("com.att.myns.myOtherType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myOtherAction");\r
+               p.getRoles().add("com.att.myns.myRole");\r
+               p.getRoles().add("com.att.myns.myRole2");\r
+\r
+               return perms;\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static UserRoleRequest newUserRoleRequestv2_0(boolean optional) {\r
+               UserRoleRequest urr = new UserRoleRequest();\r
+               urr.setRole("com.att.myns.myRole");\r
+               urr.setUser("ab1234@csp.att.com");\r
+               if(optional) setOptional(urr);\r
+               return urr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static NsRequest newNsRequestv2_0(boolean optional) {\r
+               NsRequest nr = new NsRequest();\r
+               nr.setName("com.att.myns");\r
+               nr.getResponsible().add("ab1234@csp.att.com");\r
+               nr.getResponsible().add("cd5678@csp.att.com");\r
+               nr.getAdmin().add("zy9876@csp.att.com");\r
+               nr.getAdmin().add("xw5432@csp.att.com");                \r
+               if(optional) {\r
+                       nr.setDescription("This is my Namespace to set up");\r
+                       nr.setType("APP");\r
+                       setOptional(nr);\r
+               }\r
+               return nr;\r
+       }\r
+       \r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Nss newNssv2_0(boolean optional) {\r
+               Ns ns;\r
+               \r
+               Nss nss = new Nss();\r
+               nss.getNs().add(ns = new Nss.Ns());\r
+               ns.setName("com.att.myns");\r
+               ns.getResponsible().add("ab1234@csp.att.com");\r
+               ns.getResponsible().add("cd5678@csp.att.com");\r
+               ns.getAdmin().add("zy9876@csp.att.com");\r
+               ns.getAdmin().add("xw5432@csp.att.com");\r
+               ns.setDescription("This is my Namespace to set up");\r
+               \r
+               nss.getNs().add(ns = new Nss.Ns());\r
+               ns.setName("com.att.myOtherNs");\r
+               ns.getResponsible().add("ab1234@csp.att.com");\r
+               ns.getResponsible().add("cd5678@csp.att.com");\r
+               ns.getAdmin().add("zy9876@csp.att.com");\r
+               ns.getAdmin().add("xw5432@csp.att.com");                \r
+                       \r
+               return nss;\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private static RoleRequest newRoleRequestv2_0(boolean optional) {\r
+               RoleRequest rr = new RoleRequest();\r
+               rr.setName("com.att.myns.myRole");\r
+               if(optional) {\r
+                       rr.setDescription("This is my Role");\r
+                       setOptional(rr);\r
+               }\r
+               return rr;\r
+       }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static CredRequest newCredRequestv2_0(boolean optional) {\r
+               CredRequest cr = new CredRequest();\r
+               cr.setId("myID@fully.qualified.domain");\r
+               if(optional) {\r
+                       cr.setType(2);\r
+                       cr.setEntry("0x125AB256344CE");\r
+               } else {\r
+                       cr.setPassword("This is my provisioned password");\r
+               }\r
+\r
+               return cr;\r
+       }\r
+       \r
+       @SuppressWarnings("unused")\r
+       private static Users newUsersv2_0(boolean optional) {\r
+               User user;\r
+       \r
+               Users users = new Users();\r
+               users.getUser().add(user = new Users.User());\r
+               user.setId("ab1234@csp.att.com");       \r
+               GregorianCalendar gc = new GregorianCalendar();\r
+               user.setExpires(Chrono.timeStamp(gc));\r
+               \r
+               users.getUser().add(user = new Users.User());\r
+               user.setId("zy9876@csp.att.com");       \r
+               user.setExpires(Chrono.timeStamp(gc));  \r
+                       \r
+               return users;\r
+       }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Role newRolev2_0(boolean optional) {\r
+               Role r = new Role();\r
+               Pkey p;\r
+               r.setName("com.att.myns.myRole");\r
+               r.getPerms().add(p = new Pkey());\r
+               p.setType("com.att.myns.myType");\r
+               p.setInstance("myInstance");\r
+               p.setAction("myAction");\r
+\r
+        return r;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static RoleKey newRoleKeyv2_0(boolean optional) {\r
+               RoleKey r = new RoleKey();\r
+               Pkey p;\r
+               r.setName("com.att.myns.myRole");\r
+        return r;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Keys newKeysv2_0(boolean optional) {\r
+               Keys ks = new Keys();\r
+               ks.getKey().add("Reponse 1");\r
+               ks.getKey().add("Response 2");\r
+        return ks;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static UserRoles newUserRolesv2_0(boolean optional) {\r
+               UserRoles urs = new UserRoles();\r
+               UserRole ur = new UserRole();\r
+               ur.setUser("xy1234");\r
+               ur.setRole("com.test.myapp.myRole");\r
+               ur.setExpires(Chrono.timeStamp());\r
+               urs.getUserRole().add(ur);\r
+               \r
+               ur = new UserRole();\r
+               ur.setUser("yx4321");\r
+               ur.setRole("com.test.yourapp.yourRole");\r
+               ur.setExpires(Chrono.timeStamp());\r
+               urs.getUserRole().add(ur);\r
+        return urs;\r
+    }\r
+\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Approvals newApprovalsv2_0(boolean optional) {\r
+               Approvals as = new Approvals();\r
+               Approval a = new Approval();\r
+               a.setApprover("MyApprover");\r
+               a.setId("MyID");\r
+               a.setMemo("My memo (and then some)");\r
+               a.setOperation("MyOperation");\r
+               a.setStatus("MyStatus");\r
+               a.setTicket("MyTicket");\r
+               a.setType("MyType");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser");\r
+               as.getApprovals().add(a);\r
+               a = new Approval();\r
+               a.setApprover("MyApprover2");\r
+               a.setId("MyID2");\r
+               a.setMemo("My memo (and then some)2");\r
+               a.setOperation("MyOperation2");\r
+               a.setStatus("MyStatus2");\r
+               a.setTicket("MyTicket2");\r
+               a.setType("MyType2");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser2");\r
+               as.getApprovals().add(a);\r
+        return as;\r
+    }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static Approval newApprovalv2_0(boolean optional) {\r
+               Approval a = new Approval();\r
+               a.setApprover("MyApprover");\r
+               a.setId("MyID");\r
+               a.setMemo("My memo (and then some)");\r
+               a.setOperation("MyOperation");\r
+               a.setStatus("MyStatus");\r
+               a.setTicket("MyTicket");\r
+               a.setType("MyType");\r
+               a.setUpdated(Chrono.timeStamp());\r
+               a.setUser("MyUser");\r
+        return a;\r
+    }\r
+\r
+       \r
+\r
+       @SuppressWarnings("unused")\r
+       private static aaf.v2_0.Error newErrorv2_0(boolean optional) {\r
+               aaf.v2_0.Error err = new aaf.v2_0.Error();\r
+               err.setMessageId("SVC1403");\r
+               err.setText("MyText %s, %s: The last three digits are usually the HTTP Code");\r
+               err.getVariables().add("Variable 1");\r
+               err.getVariables().add("Variable 2");\r
+               return err;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java b/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
new file mode 100644 (file)
index 0000000..4193d43
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.marshal;\r
+\r
+import javax.xml.datatype.XMLGregorianCalendar;\r
+\r
+import aaf.v2_0.Certs.Cert;\r
+\r
+import com.att.rosetta.marshal.FieldDateTime;\r
+import com.att.rosetta.marshal.FieldHexBinary;\r
+import com.att.rosetta.marshal.FieldString;\r
+import com.att.rosetta.marshal.ObjMarshal;\r
+\r
+public class CertMarshal extends ObjMarshal<Cert> {\r
+       public CertMarshal() {\r
+               add(new FieldHexBinary<Cert>("fingerprint") {\r
+                       @Override\r
+                       protected byte[] data(Cert t) {\r
+                               return t.getFingerprint();\r
+                       }\r
+               });\r
+\r
+               add(new FieldString<Cert>("id") {\r
+                       @Override\r
+                       protected String data(Cert t) {\r
+                               return t.getId();\r
+                       }\r
+               });\r
+\r
+               add(new FieldString<Cert>("x500") {\r
+                       @Override\r
+                       protected String data(Cert t) {\r
+                               return t.getX500();\r
+                       }\r
+               });\r
+               \r
+               add(new FieldDateTime<Cert>("expires") {\r
+                       @Override\r
+                       protected XMLGregorianCalendar data(Cert t) {\r
+                               return t.getExpires();\r
+                       }\r
+               });\r
+\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java b/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java
new file mode 100644 (file)
index 0000000..16fc580
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.marshal;\r
+\r
+import java.util.List;\r
+\r
+import aaf.v2_0.Certs;\r
+import aaf.v2_0.Certs.Cert;\r
+\r
+import com.att.rosetta.marshal.ObjArray;\r
+import com.att.rosetta.marshal.ObjMarshal;\r
+\r
+public class CertsMarshal extends ObjMarshal<Certs> {\r
+\r
+       public CertsMarshal() {\r
+               add(new ObjArray<Certs,Cert>("cert",new CertMarshal()) {\r
+                       @Override\r
+                       protected List<Cert> data(Certs t) {\r
+                               return t.getCert();\r
+                       }\r
+               });     \r
+       }\r
+\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
new file mode 100644 (file)
index 0000000..0c72dcd
--- /dev/null
@@ -0,0 +1,197 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.lur.ConfigPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {\r
+       private AAFCon<CLIENT> con;\r
+       private String realm;\r
+       \r
+       /**\r
+        * Configure with Standard AAF properties, Stand alone\r
+        * @param con\r
+        * @throws Exception \r
+        */\r
+       // Package on purpose\r
+       AAFAuthn(AAFCon<CLIENT> con) throws Exception {\r
+               super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);\r
+               this.con = con;\r
+\r
+               try {\r
+                       setRealm();\r
+               } catch (APIException e) {\r
+                       if(e.getCause() instanceof DME2Exception) {\r
+                               // Can't contact AAF, assume default\r
+                               realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
+                       }\r
+               }\r
+               }\r
+\r
+       /**\r
+        * Configure with Standard AAF properties, but share the Cache (with AAF Lur)\r
+        * @param con\r
+        * @throws Exception \r
+        */\r
+       // Package on purpose\r
+       AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {\r
+               super(cache);\r
+               this.con = con;\r
+               try {\r
+                       setRealm();\r
+               } catch (Exception e) {\r
+                       if(e.getCause() instanceof DME2Exception) {\r
+                               access.log(e);\r
+                               // Can't contact AAF, assume default            \r
+                               realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void setRealm() throws Exception {\r
+               // Make a call without security set to get the 401 response, which\r
+               // includes the Realm of the server\r
+               // This also checks on Connectivity early on.\r
+               Future<String> fp = con.client(AAFCon.AAF_VERSION).read("/authn/basicAuth", "text/plain");\r
+               if(fp.get(con.timeout)) {\r
+                       throw new Exception("Do not preset Basic Auth Information for AAFAuthn");\r
+               } else {\r
+                       if(fp.code()==401) {\r
+                               realm = fp.header("WWW-Authenticate");\r
+                               if(realm!=null && realm.startsWith("Basic realm=\"")) {\r
+                                       realm = realm.substring(13, realm.length()-1);\r
+                               } else {\r
+                                       realm = "unknown.com";\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Return Native Realm of AAF Instance.\r
+        * \r
+        * @return\r
+        */\r
+       public String getRealm() {\r
+               return realm;\r
+       }\r
+\r
+       /**\r
+        * Returns null if ok, or an Error String;\r
+        * \r
+        * @param user\r
+        * @param password\r
+        * @return\r
+        * @throws Exception\r
+        */\r
+       public String validate(String user, String password) throws Exception {\r
+               User<AAFPermission> usr = getUser(user);\r
+               if(password.startsWith("enc:???")) {\r
+                       password = access.decrypt(password, true);\r
+               }\r
+\r
+               byte[] bytes = password.getBytes();\r
+               if(usr != null && usr.principal != null && usr.principal.getName().equals(user) \r
+                               && usr.principal instanceof GetCred) {\r
+                       \r
+                       if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {\r
+                               return null;\r
+                       } else {\r
+                               remove(usr);\r
+                               usr = null;\r
+                       }\r
+               }\r
+               \r
+               AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);\r
+               // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch\r
+               // Statement\r
+               switch(cp.revalidate()) {\r
+                       case REVALIDATED:\r
+                               if(usr!=null) {\r
+                                       usr.principal = cp;\r
+                               } else {\r
+                                       addUser(new User<AAFPermission>(cp,con.timeout));\r
+                               }\r
+                               return null;\r
+                       case INACCESSIBLE:\r
+                               return "AAF Inaccessible";\r
+                       case UNVALIDATED:\r
+                               return "User/Pass combo invalid";\r
+                       default: \r
+                               return "AAFAuthn doesn't handle this Principal";\r
+               }\r
+       }\r
+       \r
+       private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {\r
+               private long expires,timeToLive;\r
+\r
+               public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {\r
+                       super(name,pass);\r
+                       this.timeToLive = timeToLive;\r
+                       expires = timeToLive + System.currentTimeMillis();\r
+               }\r
+\r
+               public Resp revalidate() {\r
+                       try {\r
+                               Miss missed = missed(getName());\r
+                               if(missed==null || missed.mayContinue(getCred())) {\r
+                                       Rcli<CLIENT> client = con.client(AAFCon.AAF_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));\r
+                                       Future<String> fp = client.read(\r
+                                                       "/authn/basicAuth",\r
+                                                       "text/plain"\r
+                                                       );\r
+                                       if(fp.get(con.timeout)) {\r
+                                               expires = System.currentTimeMillis() + timeToLive;\r
+                                               addUser(new User<AAFPermission>(this, expires));\r
+                                               return Resp.REVALIDATED;\r
+                                       } else {\r
+                                               addMiss(getName(), getCred());\r
+                                               return Resp.UNVALIDATED;\r
+                                       }\r
+                               } else {\r
+                                       return Resp.UNVALIDATED;\r
+                               }\r
+                       } catch (Exception e) {\r
+                               con.access.log(e);\r
+                               return Resp.INACCESSIBLE;\r
+                       }\r
+               }\r
+\r
+               public long expires() {\r
+                       return expires;\r
+               }\r
+       };\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
new file mode 100644 (file)
index 0000000..c58dd9a
--- /dev/null
@@ -0,0 +1,279 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CadiWrap;\r
+import com.att.cadi.Connector;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.marshal.CertsMarshal;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfo;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Split;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+import aaf.v2_0.Certs;\r
+import aaf.v2_0.Perms;\r
+import aaf.v2_0.Users;\r
+\r
+public abstract class AAFCon<CLIENT> implements Connector {\r
+       public static final String AAF_VERSION = "2.0";\r
+\r
+       final public Access access;\r
+       // Package access\r
+       final public int timeout, cleanInterval, connTimeout;\r
+       final public int highCount, userExpires, usageRefreshTriggerCount;\r
+       private Rcli<CLIENT> client = null;\r
+       final public RosettaDF<Perms> permsDF;\r
+       final public RosettaDF<Certs> certsDF;\r
+       final public RosettaDF<Users> usersDF;\r
+       private String realm;\r
+       public final String app;\r
+       protected SecuritySetter<CLIENT> ss;\r
+       protected SecurityInfo<CLIENT> si;\r
+       protected final URI initURI;\r
+\r
+       public Rcli<CLIENT> client(String apiVersion) throws CadiException {\r
+               if(client==null) {\r
+                       client = rclient(initURI,ss);\r
+                       client.apiVersion(apiVersion)\r
+                                 .readTimeout(connTimeout);\r
+               }\r
+               return client;\r
+       }\r
+       \r
+       protected AAFCon(Access access, String tag, SecurityInfo<CLIENT> si) throws CadiException{\r
+               try {\r
+                       this.access = access;\r
+                       this.si = si;\r
+                       this.ss = si.defSS;\r
+                       if(ss==null) {\r
+                               String mechid = access.getProperty(Config.AAF_MECHID, null);\r
+                               String encpass = access.getProperty(Config.AAF_MECHPASS, null);\r
+                               if(encpass==null) {\r
+                                       String alias = access.getProperty(Config.CADI_ALIAS, mechid);\r
+                                       if(alias==null) {\r
+                                               throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");\r
+                                       }\r
+                                       si.defSS=ss = x509Alias(alias);\r
+                               } else {\r
+                                       if(mechid!=null && encpass !=null) {\r
+                                               si.defSS=ss=basicAuth(mechid, encpass);\r
+                                       } else {\r
+                                               si.defSS=ss=new SecuritySetter<CLIENT>() {\r
+                                                       \r
+                                                       @Override\r
+                                                       public String getID() {\r
+                                                               return "";\r
+                                                       }\r
+                       \r
+                                                       @Override\r
+                                                       public void setSecurity(CLIENT client) throws CadiException {\r
+                                                               throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");\r
+                                                       }\r
+                                               };\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));\r
+                       cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));\r
+                       highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());\r
+                       connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());\r
+                       userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());\r
+                       usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based\r
+       \r
+                       \r
+                       initURI = new URI(access.getProperty(tag,null));\r
+                       if(initURI==null) {\r
+                               throw new CadiException(tag + " property is required.");\r
+                       }\r
+       \r
+                       app=reverseDomain(ss.getID());\r
+                       realm="openecomp.org";\r
+       \r
+                       RosettaEnv env = new RosettaEnv();\r
+                       permsDF = env.newDataFactory(Perms.class);\r
+                       usersDF = env.newDataFactory(Users.class);\r
+                       certsDF = env.newDataFactory(Certs.class);\r
+                       certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling\r
+               } catch (APIException|URISyntaxException e) {\r
+                       throw new CadiException("AAFCon cannot be configured",e);\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Return the backing AAFCon, if there is a Lur Setup that is AAF.\r
+        * \r
+        * If there is no AAFLur setup, it will return "null"\r
+        * @param servletRequest\r
+        * @return\r
+        */\r
+       public static final AAFCon<?> obtain(Object servletRequest) {\r
+               if(servletRequest instanceof CadiWrap) {\r
+                       Lur lur = ((CadiWrap)servletRequest).getLur();\r
+                       if(lur != null) {\r
+                               if(lur instanceof EpiLur) {\r
+                                       AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);\r
+                                       if(aal!=null) {\r
+                                               return aal.aaf;\r
+                                       }\r
+                               } else {\r
+                                       if(lur instanceof AbsAAFLur) {\r
+                                               return ((AbsAAFLur<?>)lur).aaf;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       public AAFAuthn<CLIENT> newAuthn() throws APIException {\r
+               try {\r
+                       return new AAFAuthn<CLIENT>(this);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {\r
+               try {\r
+                       return new AAFAuthn<CLIENT>(this,c);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       public AAFLurPerm newLur() throws CadiException {\r
+               try {\r
+                       return new AAFLurPerm(this);\r
+               } catch (CadiException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+       \r
+       public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {\r
+               try {\r
+                       return new AAFLurPerm(this,c);\r
+               } catch (APIException e) {\r
+                       throw e;\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Take a Fully Qualified User, and get a Namespace from it.\r
+        * @param user\r
+        * @return\r
+        */\r
+       public static String reverseDomain(String user) {\r
+               StringBuilder sb = null;\r
+               String[] split = Split.split('.',user);\r
+               int at;\r
+               for(int i=split.length-1;i>=0;--i) {\r
+                       if(sb == null) {\r
+                               sb = new StringBuilder();\r
+                       } else {\r
+                               sb.append('.');\r
+                       }\r
+\r
+                       if((at = split[i].indexOf('@'))>0) {\r
+                               sb.append(split[i].subSequence(at+1, split[i].length()));\r
+                       } else {\r
+                               sb.append(split[i]);\r
+                       }\r
+               }\r
+               \r
+               return sb==null?"":sb.toString();\r
+       }\r
+\r
+       protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;\r
+       \r
+       public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;\r
+\r
+\r
+       public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;\r
+       \r
+       public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;\r
+\r
+\r
+       public String getRealm() {\r
+               return realm;\r
+\r
+       }\r
+\r
+       public SecuritySetter<CLIENT> set(SecuritySetter<CLIENT> ss) {\r
+               this.ss = ss;\r
+               if(client!=null) {\r
+                       client.setSecuritySetter(ss);\r
+               }\r
+               return ss;\r
+       }\r
+       \r
+       public SecurityInfo<CLIENT> securityInfo() {\r
+               return si;\r
+       }\r
+\r
+       public String defID() {\r
+               if(ss!=null) {\r
+                       return ss.getID();\r
+               }\r
+               return "unknown";\r
+       }\r
+       \r
+       public void invalidate() throws CadiException {\r
+               if(client!=null) {\r
+                       client.invalidate();\r
+               }\r
+               client = null;\r
+       }\r
+\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
new file mode 100644 (file)
index 0000000..07bc390
--- /dev/null
@@ -0,0 +1,158 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.net.ConnectException;\r
+import java.net.URI;\r
+import java.security.GeneralSecurityException;\r
+import java.security.Principal;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfo;\r
+import com.att.cadi.dme2.DME2BasicAuth;\r
+import com.att.cadi.dme2.DME2TransferSS;\r
+import com.att.cadi.dme2.DME2x509SS;\r
+import com.att.cadi.dme2.DRcli;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFConDME2 extends AAFCon<DME2Client>{\r
+       private DME2Manager manager;\r
+\r
+       public AAFConDME2(Access access) throws CadiException, GeneralSecurityException, IOException{\r
+               super(access,Config.AAF_URL,new SecurityInfo<DME2Client> (access));\r
+               manager = newManager(access);\r
+       }\r
+       \r
+       public AAFConDME2(Access access, String url) throws CadiException, GeneralSecurityException, IOException{\r
+               super(access,url,new SecurityInfo<DME2Client> (access));\r
+               manager = newManager(access);\r
+       }\r
+\r
+       public AAFConDME2(Access access, SecurityInfo<DME2Client> si) throws CadiException {\r
+               super(access,Config.AAF_URL,si);\r
+               manager = newManager(access);\r
+       }\r
+\r
+       public AAFConDME2(Access access, String url, SecurityInfo<DME2Client> si) throws CadiException {\r
+               super(access,url,si);\r
+               manager = newManager(access);\r
+       }\r
+\r
+       private DME2Manager newManager(Access access) throws CadiException {\r
+               Properties props = new Properties();\r
+               Config.cadiToDME2(access, props);\r
+               try {\r
+                       return new DME2Manager("AAFCon",props);\r
+               } catch (DME2Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)\r
+        */\r
+       @Override\r
+       public SecuritySetter<DME2Client> basicAuth(String user, String password) throws CadiException {\r
+               if(password.startsWith("enc:???")) {\r
+                       try {\r
+                               password = access.decrypt(password, true);\r
+                       } catch (IOException e) {\r
+                               throw new CadiException("Error Decrypting Password",e);\r
+                       }\r
+               }\r
+\r
+               try {\r
+                       return set(new DME2BasicAuth(user,password,si));\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error setting up DME2BasicAuth",e);\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)\r
+        */\r
+       @Override\r
+       protected Rcli<DME2Client> rclient(URI uri, SecuritySetter<DME2Client> ss) {\r
+               DRcli dc = new DRcli(uri, ss);\r
+               dc.setManager(manager);\r
+               return dc;\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> transferSS(Principal principal) throws CadiException {\r
+               try {\r
+                       return principal==null?ss:new DME2TransferSS(principal, app);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating DME2TransferSS",e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> basicAuthSS(BasicPrincipal principal) throws CadiException {\r
+               try {\r
+                       return new DME2BasicAuth(principal,si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating DME2BasicAuth",e);\r
+               }\r
+\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> x509Alias(String alias) throws CadiException {\r
+               try {\r
+                       return new DME2x509SS(alias,si);\r
+               } catch (Exception e) {\r
+                       throw new CadiException("Error creating DME2x509SS",e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               // NOTE: DME2 had Retry Logic embedded lower.  \r
+               try {\r
+                       return (retryable.code(rclient(initURI,ss)));\r
+               } catch (ConnectException e) {\r
+                       // DME2 should catch\r
+                       try {\r
+                               manager.refresh();\r
+                       } catch (Exception e1) {\r
+                               throw new CadiException(e1);\r
+                       }\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
new file mode 100644 (file)
index 0000000..ffe1331
--- /dev/null
@@ -0,0 +1,148 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.security.GeneralSecurityException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.AbsTransferSS;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfo;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.http.HMangr;\r
+import com.att.cadi.http.HRcli;\r
+import com.att.cadi.http.HTransferSS;\r
+import com.att.cadi.http.HX509SS;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.inno.env.APIException;\r
+\r
+public class AAFConHttp extends AAFCon<HttpURLConnection> {\r
+       private final HMangr hman;\r
+\r
+       public AAFConHttp(Access access) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,Config.AAF_URL,new SecurityInfo<HttpURLConnection>(access));\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(Config.AAF_URL,null)));\r
+       }\r
+\r
+       public AAFConHttp(Access access, String tag) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,tag,new SecurityInfo<HttpURLConnection>(access));\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(tag,null)));\r
+       }\r
+\r
+       public AAFConHttp(Access access, String urlTag, SecurityInfo<HttpURLConnection> si) throws CadiException {\r
+               super(access,urlTag,si);\r
+               hman = new HMangr(access,Config.loadLocator(access, access.getProperty(urlTag,null)));\r
+       }\r
+\r
+       public AAFConHttp(Access access, Locator locator) throws CadiException, GeneralSecurityException, IOException {\r
+               super(access,Config.AAF_URL,new SecurityInfo<HttpURLConnection>(access));\r
+               hman = new HMangr(access,locator);\r
+       }\r
+\r
+       public AAFConHttp(Access access, Locator locator, SecurityInfo<HttpURLConnection> si) throws CadiException {\r
+               super(access,Config.AAF_URL,si);\r
+               hman = new HMangr(access,locator);\r
+       }\r
+\r
+       public AAFConHttp(Access access, Locator locator, SecurityInfo<HttpURLConnection> si, String tag) throws CadiException {\r
+               super(access,tag,si);\r
+               hman = new HMangr(access, locator);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)\r
+        */\r
+       @Override\r
+       public SecuritySetter<HttpURLConnection> basicAuth(String user, String password) throws CadiException {\r
+               if(password.startsWith("enc:???")) {\r
+                       try {\r
+                               password = access.decrypt(password, true);\r
+                       } catch (IOException e) {\r
+                               throw new CadiException("Error decrypting password",e);\r
+                       }\r
+               }\r
+               try {\r
+                       return set(new HBasicAuthSS(user,password,si));\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating HBasicAuthSS",e);\r
+               }\r
+       }\r
+\r
+       public SecuritySetter<HttpURLConnection> x509Alias(String alias) throws APIException, CadiException {\r
+               try {\r
+                       return set(new HX509SS(alias,si));\r
+               } catch (Exception e) {\r
+                       throw new CadiException("Error creating X509SS",e);\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)\r
+        */\r
+       @Override\r
+       protected Rcli<HttpURLConnection> rclient(URI ignoredURI, SecuritySetter<HttpURLConnection> ss) throws CadiException {\r
+               try {\r
+                       return new HRcli(hman, hman.loc.best() ,ss);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public AbsTransferSS<HttpURLConnection> transferSS(Principal principal) throws CadiException {\r
+               return new HTransferSS(principal, app,si);\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuthSS(java.security.Principal)\r
+        */\r
+       @Override\r
+       public SecuritySetter<HttpURLConnection> basicAuthSS(BasicPrincipal principal) throws CadiException {\r
+               try {\r
+                       return new HBasicAuthSS(principal,si);\r
+               } catch (IOException e) {\r
+                       throw new CadiException("Error creating HBasicAuthSS",e);\r
+               }\r
+       }\r
+\r
+       public HMangr hman() {\r
+               return hman;\r
+       }\r
+\r
+       @Override\r
+       public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               return hman.best(ss, (Retryable<RET>)retryable);\r
+       }\r
+       \r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
new file mode 100644 (file)
index 0000000..c1c25c2
--- /dev/null
@@ -0,0 +1,199 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.ConnectException;\r
+import java.net.URISyntaxException;\r
+import java.security.Principal;\r
+import java.util.Map;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.inno.env.APIException;\r
+\r
+import aaf.v2_0.Perm;\r
+import aaf.v2_0.Perms;\r
+\r
+/**\r
+ * Use AAF Service as Permission Service.\r
+ * \r
+ * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.\r
+ * \r
+ * If you want a simple Role Lur, use AAFRoleLur\r
+ * \r
+ *\r
+ */\r
+public class AAFLurPerm extends AbsAAFLur<AAFPermission> {\r
+       /**\r
+        *  Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this\r
+        *  point by AAF.  There is no "domain", aka, no "@att.com" in "ab1234@att.com".  \r
+        *  \r
+        *  The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.\r
+        *  Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely\r
+        * @throws APIException \r
+        * @throws URISyntaxException \r
+        * @throws DME2Exception \r
+        */\r
+       // Package on purpose\r
+       AAFLurPerm(AAFCon<?> con) throws CadiException, DME2Exception, URISyntaxException, APIException {\r
+               super(con);\r
+       }\r
+\r
+       // Package on purpose\r
+       AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws DME2Exception, URISyntaxException, APIException {\r
+               super(con,auc);\r
+       }\r
+\r
+       protected User<AAFPermission> loadUser(Principal p)  {\r
+               // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't \r
+               // have domains.  We are going to make the Transitive Class (see this.transmutative) to convert\r
+               Principal principal = transmutate.mutate(p);\r
+               if(principal==null)return null; // if not a valid Transmutated credential, don't bother calling...\r
+               return loadUser(p, p.getName());\r
+       }\r
+       \r
+       protected User<AAFPermission> loadUser(String name) {\r
+               return loadUser((Principal)null, name);\r
+       }\r
+       \r
+       private User<AAFPermission> loadUser(final Principal prin, final String name) {\r
+               \r
+               //TODO Create a dynamic way to declare domains supported.\r
+               final long start = System.nanoTime();\r
+               final boolean[] success = new boolean[]{false};\r
+               \r
+//             new Exception("loadUser").printStackTrace();\r
+               try {\r
+                       return aaf.best(new Retryable<User<AAFPermission>>() {\r
+                               @Override\r
+                               public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {\r
+                                       Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);\r
+                                       \r
+                                       // In the meantime, lookup User, create if necessary\r
+                                       User<AAFPermission> user = getUser(name);\r
+                                       Principal p;\r
+                                       if(prin == null) {\r
+                                               p = new Principal() {// Create a holder for lookups\r
+                                                       private String n = name;\r
+                                                       public String getName() {\r
+                                                               return n;\r
+                                                       }\r
+                                               };\r
+                                       } else {\r
+                                               p = prin;\r
+                                       }\r
+                                       \r
+                                       if(user==null) {\r
+                                               addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password\r
+                                       }\r
+                                       \r
+                                       // OK, done all we can, now get content\r
+                                       if(fp.get(aaf.timeout)) {\r
+                                               success[0]=true;\r
+                                               Map<String, Permission> newMap = user.newMap();\r
+                                               for(Perm perm : fp.value.getPerm()) {\r
+                                                       user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));\r
+                                                       aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');\r
+                                               }\r
+                                               user.setMap(newMap);\r
+                                               user.renewPerm();\r
+                                       } else {\r
+                                               int code;\r
+                                               switch(code=fp.code()) {\r
+                                                       case 401:\r
+                                                               aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");\r
+                                                               break;\r
+                                                       default:\r
+                                                               aaf.access.log(Access.Level.ERROR, code, fp.body());\r
+                                               }\r
+                                       }\r
+\r
+                                       return user;\r
+                               }\r
+                       });\r
+               } catch (Exception e) {\r
+                       aaf.access.log(e,"Calling","/authz/perms/user/"+name);\r
+                       return null;\r
+               } finally {\r
+                       float time = (System.nanoTime()-start)/1000000f;\r
+                       aaf.access.log(Level.AUDIT, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");\r
+               }\r
+       }\r
+\r
+       public Resp reload(User<AAFPermission> user) {\r
+               final String name = user.principal.getName();\r
+               long start = System.nanoTime();\r
+               boolean success = false;\r
+               try {\r
+                       Future<Perms> fp = aaf.client(AAFCon.AAF_VERSION).read(\r
+                                       "/authz/perms/user/"+name,\r
+                                       aaf.permsDF\r
+                                       );\r
+                       \r
+                       // OK, done all we can, now get content\r
+                       if(fp.get(aaf.timeout)) {\r
+                               success = true;\r
+                               Map<String,Permission> newMap = user.newMap(); \r
+                               for(Perm perm : fp.value.getPerm()) {\r
+                                       user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));\r
+                                       aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());\r
+                               }\r
+                               user.renewPerm();\r
+                               return Resp.REVALIDATED;\r
+                       } else {\r
+                               int code;\r
+                               switch(code=fp.code()) {\r
+                                       case 401:\r
+                                               aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");\r
+                                               break;\r
+                                       default:\r
+                                               aaf.access.log(Access.Level.ERROR, code, fp.body());\r
+                               }\r
+                               return Resp.UNVALIDATED;\r
+                       }\r
+               } catch (Exception e) {\r
+                       aaf.access.log(e,"Calling","/authz/perms/user/"+name);\r
+                       return Resp.INACCESSIBLE;\r
+               } finally {\r
+                       float time = (System.nanoTime()-start)/1000000f;\r
+                       aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected boolean isCorrectPermType(Permission pond) {\r
+               return pond instanceof AAFPermission;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
new file mode 100644 (file)
index 0000000..a36c11a
--- /dev/null
@@ -0,0 +1,199 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.User;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.CachedBasicPrincipal;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+import com.att.cadi.taf.basic.BasicHttpTafResp;\r
+\r
+public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {\r
+//     private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";\r
+//     private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";\r
+       private AAFCon<CLIENT> aaf;\r
+       private boolean warn;\r
+\r
+       public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {\r
+               super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);\r
+               aaf = con;\r
+               warn = turnOnWarning;\r
+       }\r
+\r
+       public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {\r
+               super(other);\r
+               aaf = con;\r
+               warn = turnOnWarning;\r
+       }\r
+\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               //TODO Do we allow just anybody to validate?\r
+\r
+               // Note: Either Carbon or Silicon based LifeForms ok\r
+               String auth = req.getHeader("Authorization");\r
+               \r
+               System.out.println("value of auth  ------1------- ++++++++++++++++++++++++++++++++++++++++++" +auth);\r
+               \r
+               if(auth == null) {\r
+                       return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);\r
+               } else  {\r
+                       if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");\r
+                       \r
+                       try {\r
+                               CachedBasicPrincipal bp = new CachedBasicPrincipal(this,auth,aaf.getRealm(),aaf.cleanInterval);\r
+                               System.out.println(" value of aaf.getRealm  --------2--------- +++++++++++++++++++++++++++++++++++++++++++++" +aaf.getRealm() );\r
+                               //System.out.println(" value of bp +++++++++++++++++++++++++++++++++++++++++++" +bp.toString());\r
+                               System.out.println(" value of bp.getName() -------3----- +++++++++++++++++++++++++++++++++++++++++++" +bp.getName().toString());\r
+                               System.out.println(" value of bp.getCred() -------4----- +++++++++++++++++++++++++++++++++++++++++++" +bp.getCred().toString());\r
+                               \r
+                               // First try Cache\r
+                               User<AAFPermission> usr = getUser(bp);\r
+                               \r
+                       //      System.out.println(" value of usr -------5-------++++++++++++++++++++++++++++++++++++++++++" +usr.toString());\r
+                               \r
+                               if(usr != null && usr.principal != null) {\r
+                                       if(usr.principal instanceof GetCred) {\r
+                                               if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {\r
+                                                       \r
+                                                       return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               Miss miss = missed(bp.getName());\r
+                                System.out.println(" value of miss before if loop  ---------6----- +++++++++++++++++++++++++++++++++++++" +miss );\r
+                               if(miss!=null && !miss.mayContinue(bp.getCred())) {\r
+                                       \r
+                                       System.out.println(" In if(miss!=null && !miss.mayContinue(bp.getCred())) -------7--------+++++++++++++++++++++++++++++++++++++++++++++");\r
+                                       \r
+                                       return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                       "User/Pass Retry limit exceeded"), \r
+                                                       RESP.FAIL,resp,aaf.getRealm(),true);\r
+                               }\r
+                               \r
+                               Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_VERSION).forUser(aaf.basicAuthSS(bp));\r
+                               \r
+                               //System.out.println("value of userAAF ------8---- +++++++++++++++++++++++" +userAAF);\r
+                               //System.out.println("value of userAAF +++++++++++++++++++++++" +userAAF.);\r
+                               Future<String> fp = userAAF.read("/authn/basicAuth", "text/plain");\r
+                               \r
+                               //System.out.println("value of fp --------9------ +++++++++++++++++++++++" +fp.toString());\r
+                               \r
+                               if(fp.get(aaf.timeout)) {\r
+                                       System.out.println("In fp.get check -----10----- +++++++++++++");\r
+                                       if(usr!=null)usr.principal = bp;\r
+\r
+                                       else addUser(new User<AAFPermission>(bp,aaf.cleanInterval));\r
+                                       return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);\r
+                               } else {\r
+                                       // Note: AddMiss checks for miss==null, and is part of logic\r
+                                       \r
+                                       System.out.println(" In the else part --------11--------++++++++++++++ ");\r
+                                       \r
+                                       boolean rv= addMiss(bp.getName(),bp.getCred());\r
+                                       System.out.println(" value of bp.getName() and bp.getCred() before if check  ----12--- ++++++++++++!!!!!!!!!!!++++++++++" +bp.getName() +"and " +bp.getCred());\r
+\r
+                                       if(rv) {\r
+                                               System.out.println("In if(rv) check -----13----- +++++++++++++");\r
+                                               return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                               "User/Pass combo invalid via AAF"), \r
+                                                               RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);\r
+                                       } else {\r
+                                               System.out.println("In if(rv) else check -----14----- +++++++++++++");\r
+                                               return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,\r
+                                                               "User/Pass combo invalid via AAF - Retry limit exceeded"), \r
+                                                               RESP.FAIL,resp,aaf.getRealm(),true);\r
+                                       }\r
+                               }\r
+                       } catch (IOException e) {\r
+                               String msg = buildMsg(null,req,"Invalid Auth Token");\r
+                               System.out.println("In IOException catch block -----15----- +++++++++++++");\r
+                               e.getStackTrace();\r
+                               e.printStackTrace();\r
+                               aaf.access.log(Level.INFO,msg,'(', e.getMessage(), ')');\r
+                               return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);\r
+                       } catch (Exception e) {\r
+                               String msg = buildMsg(null,req,"Authenticating Service unavailable");\r
+                               System.out.println("In Exception catch block  -----16----- +++++++++++++");\r
+                               e.getStackTrace();\r
+                               e.printStackTrace();\r
+                               aaf.access.log(Level.INFO,msg,'(', e.getMessage(), ')');\r
+                               return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {\r
+               StringBuilder sb = new StringBuilder();\r
+               for(Object s : msg) {\r
+                       sb.append(s.toString());\r
+               }\r
+               if(pr!=null) {\r
+                       sb.append(" for ");\r
+                       sb.append(pr.getName());\r
+               }\r
+               sb.append(" from ");\r
+               sb.append(req.getRemoteAddr());\r
+               sb.append(':');\r
+               sb.append(req.getRemotePort());\r
+               return sb.toString();\r
+       }\r
+\r
+\r
+       \r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               //  !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal\r
+               if(prin instanceof BasicPrincipal) {\r
+                       Future<String> fp;\r
+                       try {\r
+                               Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_VERSION).forUser(aaf.transferSS(prin));\r
+                               fp = userAAF.read("/authn/basicAuth", "text/plain");\r
+                               return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;\r
+                       } catch (Exception e) {\r
+                               aaf.access.log(e, "Cannot Revalidate",prin.getName());\r
+                               return Resp.INACCESSIBLE;\r
+                       }\r
+               }\r
+               return Resp.NOT_MINE;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
new file mode 100644 (file)
index 0000000..cc1e16c
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import javax.servlet.http.HttpServletRequest ;\r
+\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.principal.TrustPrincipal;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TrustNotTafResp;\r
+import com.att.cadi.taf.TrustTafResp;\r
+import com.att.inno.env.util.Split;\r
+\r
+public class AAFTrustChecker implements TrustChecker {\r
+       private final String tag,type,instance,action;\r
+       private Lur lur;\r
+\r
+       /**\r
+        * \r
+        * Instance will be replaced by Identity\r
+        * @param lur \r
+        *    \r
+        * @param tag\r
+        * @param perm\r
+        */\r
+       public AAFTrustChecker(final String tag, final String perm) {\r
+               this.tag = tag;\r
+               String[] split = Split.split('|', perm);\r
+               this.type = split[0];\r
+               this.instance = split[1];\r
+               this.action = split[2];\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.TrustChecker#setLur(com.att.cadi.Lur)\r
+        */\r
+       @Override\r
+       public void setLur(Lur lur) {\r
+               this.lur = lur;\r
+       }\r
+\r
+       @Override\r
+       public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {\r
+               String user_info = req.getHeader(tag);\r
+               if(user_info !=null ) {\r
+                       String[] info = Split.split(',', user_info);\r
+                       if(info.length>0) {\r
+                               String[] flds = Split.split(':',info[0]);\r
+                               if(flds.length>3 && "AS".equals(flds[3])) { // is it set for "AS"\r
+                                       if(!tresp.getPrincipal().getName().equals(flds[0])) { // We do trust ourselves, if a trust entry is made with self\r
+                                               if(lur.fish(tresp.getPrincipal(), new AAFPermission(type,instance,action))) {\r
+                                                       return new TrustTafResp(tresp,\r
+                                                                       new TrustPrincipal(tresp.getPrincipal(), flds[0]),\r
+                                                                       "  " + flds[0] + " validated using " + flds[2] + " by " + flds[1] + ','\r
+                                                               );\r
+                                               } else {\r
+                                                       return new TrustNotTafResp(tresp, "  " + tresp.getPrincipal().getName() + \r
+                                                                       " requested identity change to " + flds[0] + ", but does not have Authorization");\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return tresp;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
new file mode 100644 (file)
index 0000000..0e831b9
--- /dev/null
@@ -0,0 +1,275 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.v2_0;\r
+\r
+import java.net.URISyntaxException;\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachingLur;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.StrLur;\r
+import com.att.cadi.Transmutate;\r
+import com.att.cadi.User;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.AAFTransmutate;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Split;\r
+\r
+public abstract class AbsAAFLur<PERM extends Permission> extends AbsUserCache<PERM> implements StrLur, CachingLur<PERM> {\r
+       protected static final byte[] BLANK_PASSWORD = new byte[0];\r
+       protected static final Transmutate<Principal> transmutate = new AAFTransmutate();\r
+       private String[] debug = null;\r
+       public AAFCon<?> aaf;\r
+       private String[] supports;\r
+\r
+       public AbsAAFLur(AAFCon<?> con) throws DME2Exception, URISyntaxException, APIException {\r
+               super(con.access, con.cleanInterval, con.highCount, con.usageRefreshTriggerCount);\r
+               aaf = con;\r
+               setLur(this);\r
+               supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");\r
+       }\r
+\r
+       public AbsAAFLur(AAFCon<?> con, AbsUserCache<PERM> auc) throws DME2Exception, URISyntaxException, APIException {\r
+               super(auc);\r
+               aaf = con;\r
+               setLur(this);\r
+               supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");\r
+       }\r
+\r
+       @Override\r
+       public void setDebug(String ids) {\r
+               this.debug = ids==null?null:Split.split(',', ids);\r
+       }\r
+       \r
+       protected abstract User<PERM> loadUser(Principal bait);\r
+       protected abstract User<PERM> loadUser(String name);\r
+       public final boolean supports(String userName) {\r
+               if(userName!=null) {\r
+                       for(String s : supports) {\r
+                               if(userName.endsWith(s))\r
+                                       return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       protected abstract boolean isCorrectPermType(Permission pond);\r
+       \r
+       // This is where you build AAF CLient Code.  Answer the question "Is principal "bait" in the "pond"\r
+       public boolean fish(Principal bait, Permission pond) {\r
+               return fish(bait.getName(), pond);\r
+       }\r
+\r
+       public void fishAll(Principal bait, List<Permission> perms) {\r
+               fishAll(bait.getName(),perms);\r
+       }\r
+\r
+       // This is where you build AAF CLient Code.  Answer the question "Is principal "bait" in the "pond"\r
+       public boolean fish(String bait, Permission pond) {\r
+               if(isDebug(bait)) {\r
+                       boolean rv = false;\r
+                       StringBuilder sb = new StringBuilder("Log for ");\r
+                       sb.append(bait);\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser is not in Cache");\r
+                               } else {\r
+                                       if(user.noPerms())sb.append("\n\tUser has no Perms");\r
+                                       if(user.permExpired()) {\r
+                                               sb.append("\n\tUser's perm expired [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       } else {\r
+                                               sb.append("\n\tUser's perm expires [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       }\r
+                               }\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                                       sb.append("\n\tloadUser called");\r
+                               }\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser was not Loaded");\r
+                               } else if(user.contains(pond)) {\r
+                                       sb.append("\n\tUser contains ");\r
+                                       sb.append(pond.getKey());\r
+                                       rv = true;\r
+                               } else {\r
+                                       sb.append("\n\tUser does not contain ");\r
+                                       sb.append(pond.getKey());\r
+                                       List<Permission> perms = new ArrayList<Permission>();\r
+                                       user.copyPermsTo(perms);\r
+                                       for(Permission p : perms) {\r
+                                               sb.append("\n\t\t");\r
+                                               sb.append(p.getKey());\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               sb.append("AAF Lur does not support [");\r
+                               sb.append(bait);\r
+                               sb.append("]");\r
+                       }\r
+                       aaf.access.log(Level.INFO, sb);\r
+                       return rv;\r
+               } else {\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                               }\r
+                               return user==null?false:user.contains(pond);\r
+                       }\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       public void fishAll(String bait, List<Permission> perms) {\r
+               if(isDebug(bait)) {\r
+                       StringBuilder sb = new StringBuilder("Log for ");\r
+                       sb.append(bait);\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser is not in Cache");\r
+                               } else {\r
+                                       if(user.noPerms())sb.append("\n\tUser has no Perms");\r
+                                       if(user.permExpired()) {\r
+                                               sb.append("\n\tUser's perm expired [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       } else {\r
+                                               sb.append("\n\tUser's perm expires [");\r
+                                               sb.append(new Date(user.permExpires()));\r
+                                               sb.append(']');\r
+                                       }\r
+                               }\r
+                               if(user==null || (user.noPerms() && user.permExpired())) {\r
+                                       user = loadUser(bait);\r
+                                       sb.append("\n\tloadUser called");\r
+                               }\r
+                               if(user==null) {\r
+                                       sb.append("\n\tUser was not Loaded");\r
+                               } else {\r
+                                       sb.append("\n\tCopying Perms ");\r
+                                       user.copyPermsTo(perms);\r
+                                       for(Permission p : perms) {\r
+                                               sb.append("\n\t\t");\r
+                                               sb.append(p.getKey());\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               sb.append("AAF Lur does not support [");\r
+                               sb.append(bait);\r
+                               sb.append("]");\r
+                       }\r
+                       aaf.access.log(Level.INFO, sb);\r
+               } else {\r
+                       if(supports(bait)) {\r
+                               User<PERM> user = getUser(bait);\r
+                               if(user==null || (user.noPerms() && user.permExpired())) user = loadUser(bait);\r
+                               if(user!=null) {\r
+                                       user.copyPermsTo(perms);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void remove(String user) {\r
+               super.remove(user);\r
+       }\r
+\r
+       private boolean isDebug(String bait) {\r
+               if(debug!=null) {\r
+                       if(debug.length==1 && "all".equals(debug[0]))return true;\r
+                       for(String s : debug) {\r
+                               if(s.equals(bait))return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       /**\r
+        * This special case minimizes loops, avoids multiple Set hits, and calls all the appropriate Actions found.\r
+        * \r
+        * @param bait\r
+        * @param obj\r
+        * @param type\r
+        * @param instance\r
+        * @param actions\r
+        */\r
+       public<A> void fishOneOf(String bait, A obj, String type, String instance, List<Action<A>> actions) {\r
+               User<PERM> user = getUser(bait);\r
+               if(user==null || (user.noPerms() && user.permExpired()))user = loadUser(bait);\r
+//             return user==null?false:user.contains(pond);\r
+               if(user!=null) {\r
+                       ReuseAAFPermission perm = new ReuseAAFPermission(type,instance);\r
+                       for(Action<A> action : actions) {\r
+                               perm.setAction(action.getName());\r
+                               if(user.contains(perm)) {\r
+                                       if(action.exec(obj))return;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public static interface Action<A> {\r
+               public String getName();\r
+               /**\r
+                *  Return false to continue, True to end now\r
+                * @return\r
+                */\r
+               public boolean exec(A a);\r
+       }\r
+       \r
+       private class ReuseAAFPermission extends AAFPermission {\r
+               public ReuseAAFPermission(String type, String instance) {\r
+                       super(type,instance,null);\r
+               }\r
+\r
+               public void setAction(String s) {\r
+                       action = s;\r
+               }\r
+               \r
+               /**\r
+                * This function understands that AAF Keys are hierarchical, :A:B:C, \r
+                *  Cassandra follows a similar method, so we'll short circuit and do it more efficiently when there isn't a first hit\r
+                * @return\r
+                */\r
+//             public boolean setParentInstance() {\r
+//                     int i = instance.lastIndexOf(':');\r
+//                     if(i<0) return false;\r
+//                     instance = instance.substring(0, i);\r
+//                     return true;\r
+//             }\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/ArtifactDir.java b/aaf/src/src/main/java/com/att/cadi/cm/ArtifactDir.java
new file mode 100644 (file)
index 0000000..7ddf529
--- /dev/null
@@ -0,0 +1,273 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.io.PrintWriter;\r
+import java.security.KeyStore;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public abstract class ArtifactDir implements PlaceArtifact {\r
+\r
+       protected static final String C_R = "\n";\r
+       protected File dir;\r
+       private List<String> encodeds = new ArrayList<String>();\r
+       \r
+       private Symm symm;\r
+       // This checks for multiple passes of Dir on the same objects.  Run clear after done.\r
+       protected static Map<String,Object> processed = new HashMap<String,Object>();\r
+\r
+\r
+       /**\r
+        * Note:  Derived Classes should ALWAYS call "super.place(cert,arti)" first, and \r
+        * then "placeProperties(arti)" just after they implement\r
+        */\r
+       @Override\r
+       public final boolean place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               validate(arti);\r
+               \r
+               try {\r
+                       // Obtain/setup directory as required\r
+                       dir = new File(arti.getDir());\r
+                       if(processed.get("dir")==null) {\r
+                               if(!dir.exists()) {\r
+                                       Chmod.to755.chmod(dir);\r
+                                       if(!dir.mkdirs()) {\r
+                                               throw new CadiException("Could not create " + dir);\r
+                                       }\r
+                               }\r
+                               \r
+                               // Also place cm_url and Host Name\r
+                               addProperty(Config.CM_URL,trans.getProperty(Config.CM_URL));\r
+                               addProperty(Config.HOSTNAME,arti.getMachine());\r
+                       }\r
+                       symm = (Symm)processed.get("symm");\r
+                       if(symm==null) {\r
+                               // CADI Key Gen\r
+                               File f = new File(dir,arti.getAppName() + ".keyfile");\r
+                               if(!f.exists()) {\r
+                                       write(f,Chmod.to400,Symm.baseCrypt().keygen());\r
+                               }\r
+                               symm = Symm.obtain(f); \r
+\r
+                               addEncProperty("ChallengePassword", certInfo.getChallenge());\r
+                               \r
+                               processed.put("symm",symm);\r
+                       }\r
+\r
+                       _place(trans, certInfo,arti);\r
+                       \r
+                       placeProperties(arti);\r
+                       \r
+                       processed.put("dir",dir);\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Derived Classes implement this instead, so Dir can process first, and write any Properties last\r
+        * @param cert\r
+        * @param arti\r
+        * @return\r
+        * @throws CadiException\r
+        */\r
+       protected abstract boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException;\r
+\r
+       protected void addProperty(String tag, String value) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append(tag);\r
+               sb.append('=');\r
+               sb.append(value);\r
+               encodeds.add(sb.toString());\r
+       }\r
+\r
+       protected void addEncProperty(String tag, String value) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append(tag);\r
+               sb.append('=');\r
+               sb.append("enc:???");\r
+               sb.append(symm.enpass(value));\r
+               encodeds.add(sb.toString());\r
+       }\r
+\r
+       protected void write(File f, Chmod c, String ... data) throws IOException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               PrintStream ps = new PrintStream(fos);\r
+               try {\r
+                       for(String s : data) {\r
+                               ps.print(s);\r
+                       }\r
+               } finally {\r
+                       ps.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+\r
+       protected void write(File f, Chmod c, byte[] bytes) throws IOException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               try {\r
+                       fos.write(bytes);\r
+               } finally {\r
+                       fos.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+       \r
+       protected void write(File f, Chmod c, KeyStore ks, char[] pass ) throws IOException, CadiException {\r
+               f.setWritable(true,true);\r
+               \r
+               FileOutputStream fos = new FileOutputStream(f);\r
+               try {\r
+                       ks.store(fos, pass);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               } finally {\r
+                       fos.close();\r
+                       c.chmod(f);\r
+               }\r
+       }\r
+\r
+\r
+       private void validate(Artifact a) throws CadiException {\r
+               StringBuilder sb = new StringBuilder();\r
+               if(a.getDir()==null) {\r
+                       sb.append("File Artifacts require a path");\r
+               }\r
+\r
+               if(a.getAppName()==null) {\r
+                       if(sb.length()>0) {\r
+                               sb.append('\n');\r
+                       }\r
+                       sb.append("File Artifacts require an appName");\r
+               }\r
+               \r
+               if(sb.length()>0) {\r
+                       throw new CadiException(sb.toString());\r
+               }\r
+       }\r
+\r
+       private boolean placeProperties(Artifact arti) throws CadiException {\r
+               if(encodeds.size()==0) {\r
+                       return true;\r
+               }\r
+               boolean first=processed.get("dir")==null;\r
+               try {\r
+                       File f = new File(dir,arti.getAppName()+".props");\r
+                       if(f.exists()) {\r
+                               if(first) {\r
+                                       f.delete();\r
+                               } else {\r
+                                       f.setWritable(true);\r
+                               }\r
+                       }\r
+                       // Append if not first\r
+                       PrintWriter pw = new PrintWriter(new FileWriter(f,!first));\r
+                       \r
+                       // Write a Header\r
+                       if(first) {\r
+                               for(int i=0;i<60;++i) {\r
+                                       pw.print('#');\r
+                               }\r
+                               pw.println();\r
+                               pw.println("# Properties Generated by AT&T Certificate Manager");\r
+                               pw.print("#   by ");\r
+                               pw.println(System.getProperty("user.name"));\r
+                               pw.print("#   on ");\r
+                               pw.println(Chrono.dateStamp());\r
+                               pw.println("# @copyright 2016, AT&T");\r
+                               for(int i=0;i<60;++i) {\r
+                                       pw.print('#');\r
+                               }\r
+                               pw.println();\r
+                               for(String prop : encodeds) {\r
+                                       if(prop.startsWith("cm_") || prop.startsWith(Config.HOSTNAME)) {\r
+                                               pw.println(prop);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       try {\r
+                               for(String prop : encodeds) {\r
+                                       if(prop.startsWith("cadi")) {\r
+                                               pw.println(prop);\r
+                                       }\r
+                               }\r
+                       } finally {\r
+                               pw.close();\r
+                       }\r
+                       Chmod.to400.chmod(f);\r
+                       \r
+                       if(first) {\r
+                               // Challenge\r
+                               f = new File(dir,arti.getAppName()+".chal");\r
+                               if(f.exists()) {\r
+                                       f.delete();\r
+                               }\r
+                               pw = new PrintWriter(new FileWriter(f));\r
+                               try {\r
+                                       for(String prop : encodeds) {\r
+                                               if(prop.startsWith("Challenge")) {\r
+                                                       pw.println(prop);\r
+                                               }\r
+                                       }\r
+                               } finally {\r
+                                       pw.close();\r
+                               }\r
+                               Chmod.to400.chmod(f);\r
+                       }\r
+               } catch(Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       public static void clear() {\r
+               processed.clear();\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/CertException.java b/aaf/src/src/main/java/com/att/cadi/cm/CertException.java
new file mode 100644 (file)
index 0000000..a2694ce
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+public class CertException extends Exception {\r
+\r
+       /**\r
+        * \r
+        */\r
+       private static final long serialVersionUID = 1373028409048516401L;\r
+\r
+       public CertException() {\r
+       }\r
+\r
+       public CertException(String message) {\r
+               super(message);\r
+       }\r
+\r
+       public CertException(Throwable cause) {\r
+               super(cause);\r
+       }\r
+\r
+       public CertException(String message, Throwable cause) {\r
+               super(message, cause);\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/CmAgent.java b/aaf/src/src/main/java/com/att/cadi/cm/CmAgent.java
new file mode 100644 (file)
index 0000000..9e5e77a
--- /dev/null
@@ -0,0 +1,787 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStreamReader;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.security.KeyStore;\r
+import java.security.cert.X509Certificate;\r
+import java.util.ArrayDeque;\r
+import java.util.Deque;\r
+import java.util.GregorianCalendar;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.aaf.client.ErrMessage;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.client.EnvAccess;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.TimeTaken;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+import com.att.inno.env.util.Split;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+import certman.v1_0.Artifacts;\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+import certman.v1_0.CertificateRequest;\r
+\r
+public class CmAgent {\r
+       private static final String PRINT = "print";\r
+       private static final String FILE = "file";\r
+       private static final String PKCS12 = "pkcs12";\r
+       private static final String JKS = "jks";\r
+       private static final String SCRIPT="script";\r
+       \r
+       private static final String CM_VER = "1.0";\r
+       public static final int PASS_SIZE = 24;\r
+       private static int TIMEOUT;\r
+       \r
+       private static MyConsole cons;\r
+       \r
+       private static RosettaDF<CertificateRequest> reqDF;\r
+       private static RosettaDF<CertInfo> certDF;\r
+       private static RosettaDF<Artifacts> artifactsDF;\r
+       private static ErrMessage errMsg;\r
+       private static Map<String,PlaceArtifact> placeArtifact;\r
+       private static RosettaEnv env;\r
+\r
+       public static void main(String[] args) {\r
+               int exitCode = 0;\r
+               env = new RosettaEnv(Config.CADI_PROP_FILES,args);\r
+               Deque<String> cmds = new ArrayDeque<String>();\r
+               for(String p : args) {\r
+                       if(p.indexOf('=')<0) {\r
+                               cmds.add(p);\r
+                       }\r
+               }\r
+               \r
+               if(cmds.size()==0) {\r
+                       System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");\r
+                       System.out.println("   create   <mechID> [<machine>]");\r
+                       System.out.println("   read     <mechID> [<machine>]");\r
+                       System.out.println("   update   <mechID> [<machine>]");\r
+                       System.out.println("   delete   <mechID> [<machine>]");\r
+                       System.out.println("   copy     <mechID> <machine> <newmachine>[,<newmachine>]*");\r
+                       System.out.println("   place    <mechID> [<machine>]");\r
+                       System.out.println("   showpass <mechID> [<machine>]");\r
+                       System.out.println("   check    <mechID> [<machine>]");\r
+                       System.exit(1);\r
+               }\r
+               \r
+               TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));\r
+               cons = TheConsole.implemented()?new TheConsole():new SubStandardConsole();\r
+\r
+               try {\r
+                       reqDF = env.newDataFactory(CertificateRequest.class);\r
+                       artifactsDF = env.newDataFactory(Artifacts.class);\r
+                       certDF = env.newDataFactory(CertInfo.class);\r
+                       errMsg = new ErrMessage(env);\r
+\r
+                       placeArtifact = new HashMap<String,PlaceArtifact>();\r
+                       placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));\r
+                       placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));\r
+                       placeArtifact.put(FILE, new PlaceArtifactInFiles());\r
+                       placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));\r
+                       placeArtifact.put(SCRIPT, new PlaceArtifactScripts());\r
+                       \r
+                       Access access = new EnvAccess(env);\r
+                       Trans trans = env.newTrans();\r
+                       try {\r
+                               getProperty(env,false, Config.CM_URL,Config.CM_URL+": ");\r
+                               String str=env.getProperty(Config.CADI_ALIAS);\r
+                               if(str==null) { // ask for MechID pass\r
+                                       getProperty(env,false,Config.AAF_MECHID,"Your Identity: ");\r
+                                       getProperty(env,true,Config.AAF_MECHPASS,"Password: ");\r
+                               }\r
+                               AAFCon<?> aafcon = new AAFConHttp(access,Config.CM_URL);\r
+                                               \r
+                               String cmd = cmds.removeFirst();\r
+                               if("place".equals(cmd)) {\r
+                                       placeCerts(trans,aafcon,cmds);\r
+                               } else if("create".equals(cmd)) {\r
+                                       createArtifact(trans, aafcon,cmds);\r
+                               } else if("read".equals(cmd)) {\r
+                                       readArtifact(trans, aafcon, cmds);\r
+                               } else if("copy".equals(cmd)) {\r
+                                       copyArtifact(trans, aafcon, cmds);\r
+                               } else if("update".equals(cmd)) {\r
+                                       updateArtifact(trans, aafcon, cmds);\r
+                               } else if("delete".equals(cmd)) {\r
+                                       deleteArtifact(trans, aafcon, cmds);\r
+                               } else if("showpass".equals(cmd)) {\r
+                                       showPass(trans,aafcon,cmds);\r
+                               } else if("check".equals(cmd)) {\r
+                                       try {\r
+                                               exitCode = check(trans,aafcon,cmds);\r
+                                       } catch (Exception e) {\r
+                                               exitCode = 1;\r
+                                               throw e;\r
+                                       }\r
+                               } else {\r
+                                       cons.printf("Unknown command \"%s\"\n", cmd);\r
+                               }\r
+                       } finally {\r
+                               StringBuilder sb = new StringBuilder();\r
+                trans.auditTrail(4, sb, Trans.REMOTE);\r
+                if(sb.length()>0) {\r
+                       trans.info().log("Trans Info\n",sb);\r
+                }\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+               if(exitCode!=0) {\r
+                       System.exit(exitCode);\r
+               }\r
+       }\r
+\r
+       private static String getProperty(Env env, boolean secure, String tag, String prompt, Object ... def) {\r
+               String value;\r
+               if((value=env.getProperty(tag))==null) {\r
+                       if(secure) {\r
+                               value = new String(cons.readPassword(prompt, def));\r
+                       } else {\r
+                               value = cons.readLine(prompt,def).trim();\r
+                       }\r
+                       if(value!=null) {\r
+                               if(value.length()>0) {\r
+                                       env.setProperty(tag,value);\r
+                               } else if(def.length==1) {\r
+                                       value=def[0].toString();\r
+                                       env.setProperty(tag,value);\r
+                               }\r
+                       }\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private interface MyConsole {\r
+               public String readLine(String fmt, Object ... args);\r
+               public char[] readPassword(String fmt, Object ... args);\r
+               public void printf(String fmt, Object ...args);\r
+       }\r
+\r
+       private static class TheConsole implements MyConsole {\r
+               @Override\r
+               public String readLine(String fmt, Object... args) {\r
+                       String rv = System.console().readLine(fmt, args);\r
+                       if(args.length>0 && args[0]!=null && rv.length()==0) {\r
+                               rv = args[0].toString();\r
+                       }\r
+                       return rv;\r
+               }\r
+\r
+               @Override\r
+               public char[] readPassword(String fmt, Object... args) {\r
+                       return System.console().readPassword(fmt, args);\r
+               }\r
+               \r
+               public static boolean implemented() {\r
+                       return System.console()!=null;\r
+               }\r
+\r
+               @Override\r
+               public void printf(String fmt, Object... args) {\r
+                       System.console().printf(fmt, args);\r
+               }\r
+       }\r
+       \r
+       // Substandard, because System.in doesn't do Passwords..\r
+       private static class SubStandardConsole implements MyConsole {\r
+               BufferedReader br = new BufferedReader(new InputStreamReader(System.in));\r
+               @Override\r
+               public String readLine(String fmt, Object... args) {\r
+                       String rv;\r
+                       try {\r
+                               System.out.printf(fmt,args);\r
+                               rv = br.readLine();\r
+                               if(args.length==1 && rv.length()==0) {\r
+                                       rv = args[0].toString();\r
+                               }\r
+                       } catch (IOException e) {\r
+                               System.err.println("uh oh...");\r
+                               rv = "";\r
+                       }\r
+                       return rv;\r
+               }\r
+\r
+               @Override\r
+               public char[] readPassword(String fmt, Object... args) {\r
+                       try {\r
+                               System.out.printf(fmt,args);\r
+                               return br.readLine().toCharArray();\r
+                       } catch (IOException e) {\r
+                               System.err.println("uh oh...");\r
+                               return new char[0];\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               public void printf(String fmt, Object... args) {\r
+                       System.out.printf(fmt, args);\r
+               }\r
+       }\r
+\r
+//     private static class AutoData implements MyConsole {\r
+////           private Env env;\r
+//             private Map<String,String> data;\r
+//\r
+//             @Override\r
+//             public String readLine(String fmt, Object... args) {\r
+//                     String rv=data.get(fmt);\r
+//                     return rv==null?"":rv;\r
+//             }\r
+//\r
+//             @Override\r
+//             public char[] readPassword(String fmt, Object... args) {\r
+//                     String rv=data.get(fmt);\r
+//                     return rv==null?new char[0]:rv.toCharArray();\r
+//             }\r
+//             \r
+//             @Override\r
+//             public void printf(String fmt, Object... args) {\r
+//                     System.out.printf(fmt, args);\r
+//             }\r
+//\r
+//     }\r
+//     \r
+       private static String mechID(Deque<String> cmds) {\r
+               if(cmds.size()<1) {\r
+                       String alias = env.getProperty(Config.CADI_ALIAS);\r
+                       return alias!=null?alias:cons.readLine("MechID: ");\r
+               }\r
+               return cmds.removeFirst();      \r
+       }\r
+\r
+       private static String machine(Deque<String> cmds) throws UnknownHostException {\r
+               if(cmds.size()>0) {\r
+                       return cmds.removeFirst();\r
+               } else {\r
+                       String mach = env.getProperty(Config.HOSTNAME);\r
+                       return mach!=null?mach:InetAddress.getLocalHost().getHostName();\r
+               }\r
+       }\r
+\r
+       private static String[] machines(Deque<String> cmds)  {\r
+               String machines;\r
+               if(cmds.size()>0) {\r
+                       machines = cmds.removeFirst();\r
+               } else {\r
+                       machines = cons.readLine("Machines (sep by ','): ");\r
+               }\r
+               return Split.split(',', machines);\r
+       }\r
+\r
+       private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               Artifacts artifacts = new Artifacts();\r
+               Artifact arti = new Artifact();\r
+               artifacts.getArtifact().add(arti);\r
+               arti.setMechid(mechID!=null?mechID:cons.readLine("MechID: "));\r
+               arti.setMachine(machine!=null?machine:cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));\r
+               arti.setCa(cons.readLine("CA: (%s): ","aaf"));\r
+               \r
+               String resp = cons.readLine("Types [file,jks,pkcs12] (%s): ", "jks");\r
+               for(String s : Split.splitTrim(',', resp)) {\r
+                       arti.getType().add(s);\r
+               }\r
+               // Always do Script\r
+               if(!resp.contains(SCRIPT)) {\r
+                       arti.getType().add(SCRIPT);\r
+               }\r
+\r
+               // Note: Sponsor is set on Creation by CM\r
+               String configRootName = AAFCon.reverseDomain(arti.getMechid());\r
+               arti.setAppName(cons.readLine("AppName (%s): ",configRootName));\r
+               arti.setDir(cons.readLine("Directory (%s): ", System.getProperty("user.dir")));\r
+               arti.setOsUser(cons.readLine("OS User (%s): ", System.getProperty("user.name")));\r
+               arti.setRenewDays(Integer.parseInt(cons.readLine("Renewal Days (%s):", "30")));\r
+               arti.setNotification(toNotification(cons.readLine("Notification (mailto owner):", "")));\r
+               \r
+               TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);\r
+                       if(future.get(TIMEOUT)) {\r
+                               trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                       errMsg.toMsg(future));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       private static String toNotification(String notification) {\r
+               if(notification==null) {\r
+                       notification="";\r
+               } else if(notification.length()>0) {\r
+                       if(notification.indexOf(':')<0) {\r
+                               notification = "mailto:" + notification;\r
+                       }\r
+               }\r
+               return notification;\r
+       }\r
+       \r
+\r
+       private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Read Artifact", Env.SUB);\r
+               try {\r
+                       Future<Artifacts> future = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+       \r
+                       if(future.get(TIMEOUT)) {\r
+                               boolean printed = false;\r
+                               for(Artifact a : future.value.getArtifact()) {\r
+                                       cons.printf("MechID:          %s\n",a.getMechid()); \r
+                                       cons.printf("  Sponsor:       %s\n",a.getSponsor()); \r
+                                       cons.printf("Machine:         %s\n",a.getMachine()); \r
+                                       cons.printf("CA:              %s\n",a.getCa()); \r
+                                       StringBuilder sb = new StringBuilder();\r
+                                       boolean first = true;\r
+                                       for(String t : a.getType()) {\r
+                                               if(first) {first=false;}\r
+                                               else{sb.append(',');}\r
+                                               sb.append(t);\r
+                                       }\r
+                                       cons.printf("Types:           %s\n",sb);\r
+                                       cons.printf("AppName:         %s\n",a.getAppName()); \r
+                                       cons.printf("Directory:       %s\n",a.getDir());\r
+                                       cons.printf("O/S User:        %s\n",a.getOsUser());\r
+                                       cons.printf("Renew Days:      %d\n",a.getRenewDays());\r
+                                       cons.printf("Notification     %s\n",a.getNotification());\r
+                                       printed = true;\r
+                               }\r
+                               if(!printed) {\r
+                                       cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(future));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               String[] newmachs = machines(cmds);\r
+               if(newmachs==null || newmachs == null) {\r
+                       trans.error().log("No machines listed to copy to");\r
+               } else {\r
+                       TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);\r
+                       try {\r
+                               Future<Artifacts> future = aafcon.client(CM_VER)\r
+                                               .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       \r
+                               if(future.get(TIMEOUT)) {\r
+                                       boolean printed = false;\r
+                                       for(Artifact a : future.value.getArtifact()) {\r
+                                               for(String m : newmachs) {\r
+                                                       a.setMachine(m);\r
+                                                       Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);\r
+                                                       if(fup.get(TIMEOUT)) {\r
+                                                               trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);\r
+                                                       } else {\r
+                                                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                                                       errMsg.toMsg(fup));\r
+                                                       }\r
+       \r
+                                                       printed = true;\r
+                                               }\r
+                                       }\r
+                                       if(!printed) {\r
+                                               cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                                       }\r
+                               } else {\r
+                                       trans.error().log(errMsg.toMsg(future));\r
+                               }\r
+                       } finally {\r
+                               tt.done();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> fread = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+       \r
+                       if(fread.get(TIMEOUT)) {\r
+                               Artifacts artifacts = new Artifacts();\r
+                               for(Artifact a : fread.value.getArtifact()) {\r
+                                       Artifact arti = new Artifact();\r
+                                       artifacts.getArtifact().add(arti);\r
+                                       \r
+                                       cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());\r
+                                       arti.setMechid(a.getMechid());\r
+                                       arti.setMachine(a.getMachine());\r
+                                       arti.setCa(cons.readLine("CA: (%s): ",a.getCa()));\r
+                                       StringBuilder sb = new StringBuilder();\r
+                                       boolean first = true;\r
+                                       for(String t : a.getType()) {\r
+                                               if(first) {first=false;}\r
+                                               else{sb.append(',');}\r
+                                               sb.append(t);\r
+                                       }\r
+       \r
+                                       String resp = cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);\r
+                                       for(String s : Split.splitTrim(',', resp)) {\r
+                                               arti.getType().add(s);\r
+                                       }\r
+                                       // Always do Script\r
+                                       if(!resp.contains(SCRIPT)) {\r
+                                               arti.getType().add(SCRIPT);\r
+                                       }\r
+\r
+                                       // Note: Sponsor is set on Creation by CM\r
+                                       arti.setAppName(cons.readLine("AppName (%s): ",a.getAppName()));\r
+                                       arti.setDir(cons.readLine("Directory (%s): ", a.getDir()));\r
+                                       arti.setOsUser(cons.readLine("OS User (%s): ", a.getOsUser()));\r
+                                       arti.setRenewDays(Integer.parseInt(cons.readLine("Renew Days (%s):", a.getRenewDays())));\r
+                                       arti.setNotification(toNotification(cons.readLine("Notification (%s):", a.getNotification())));\r
+       \r
+                               }\r
+                               if(artifacts.getArtifact().size()==0) {\r
+                                       cons.printf("Artifact for %s %s does not exist", mechID, machine);\r
+                               } else {\r
+                                       Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);\r
+                                       if(fup.get(TIMEOUT)) {\r
+                                               trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);\r
+                                       } else {\r
+                                               trans.error().printf("Call to AAF Certman failed, %s",\r
+                                                       errMsg.toMsg(fup));\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s %s, %s",\r
+                                               errMsg.toMsg(fread),mechID,machine);\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechid = mechID(cmds);\r
+               String machine = mechID(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Void> future = aafcon.client(CM_VER)\r
+                                       .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );\r
+       \r
+                       if(future.get(TIMEOUT)) {\r
+                               trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);\r
+                       } else {\r
+                               trans.error().printf("Call to AAF Certman failed, %s %s, %s",\r
+                                       errMsg.toMsg(future),mechid,machine);\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       \r
+\r
+       private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               boolean rv = false;\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       cons.printf("There are no artifacts for %s %s", mechID, machine);\r
+                               } else {\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               CertificateRequest cr = new CertificateRequest();\r
+                                               cr.setMechid(a.getMechid());\r
+                                               cr.setSponsor(a.getSponsor());\r
+                                               cr.getFqdns().add(a.getMachine());\r
+                                               Future<String> f = aafcon.client(CM_VER)\r
+                                                               .setQueryParams("withTrust")\r
+                                                               .updateRespondString("/cert/" + a.getCa(),reqDF, cr);\r
+                                               if(f.get(TIMEOUT)) {\r
+                                                       CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();\r
+                                                       for(String type : a.getType()) {\r
+                                                               PlaceArtifact pa = placeArtifact.get(type);\r
+                                                               if(pa!=null) {\r
+                                                                       if(rv = pa.place(trans, capi, a)) {\r
+                                                                               notifyPlaced(a,rv);\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                                       // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact\r
+                                                       ArtifactDir.clear();\r
+                                               } else {\r
+                                                       trans.error().log(errMsg.toMsg(f));\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+               return rv;\r
+       }\r
+       \r
+       private static void notifyPlaced(Artifact a, boolean rv) {\r
+               \r
+               \r
+       }\r
+\r
+       private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+\r
+               TimeTaken tt = trans.start("Show Password", Env.REMOTE);\r
+               try {\r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       cons.printf("No Artifacts found for %s on %s", mechID, machine);\r
+                               } else {\r
+                                       String id = aafcon.defID();\r
+                                       boolean allowed;\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               allowed = id!=null && (id.equals(a.getSponsor()) ||\r
+                                                               (id.equals(a.getMechid()) \r
+                                                                               && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));\r
+                                               if(!allowed) {\r
+                                                       Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" + \r
+                                                                       a.getAppName() + ".certman|"+a.getCa()+"|showpass","*/*");\r
+                                                       if(pf.get(TIMEOUT)) {\r
+                                                               allowed = true;\r
+                                                       } else {\r
+                                                               trans.error().log(errMsg.toMsg(pf));\r
+                                                       }\r
+                                               }\r
+                                               if(allowed) {\r
+                                                       File dir = new File(a.getDir());\r
+                                                       Properties props = new Properties();\r
+                                                       FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));\r
+                                                       try {\r
+                                                               props.load(fis);\r
+                                                               fis.close();\r
+                                                               fis = new FileInputStream(new File(dir,a.getAppName()+".chal"));\r
+                                                               props.load(fis);\r
+                                                       } finally {\r
+                                                               fis.close();\r
+                                                       }\r
+                                                       \r
+                                                       File f = new File(dir,a.getAppName()+".keyfile");\r
+                                                       if(f.exists()) {\r
+                                                               Symm symm = Symm.obtain(f);\r
+                                                               \r
+                                                               for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {\r
+                                                                       Entry<Object,Object> en = iter.next();\r
+                                                                       if(en.getValue().toString().startsWith("enc:???")) {\r
+                                                                               System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));\r
+                                                                       }\r
+                                                               }\r
+                                                       } else {\r
+                                                               trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",\r
+                                                                               f.getCanonicalPath(),a.getMechid(), a.getMachine());\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+\r
+       }\r
+       \r
+\r
+       /**\r
+        * Check returns Error Codes, so that Scripts can know what to do\r
+        * \r
+        *   0 - Check Complete, nothing to do\r
+        *   1 - General Error\r
+        *   2 - Error for specific Artifact - read check.msg\r
+        *   10 - Certificate Updated - check.msg is email content\r
+        *   \r
+        * @param trans\r
+        * @param aafcon\r
+        * @param cmds\r
+        * @return\r
+        * @throws Exception\r
+        */\r
+       private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {\r
+               int exitCode=1;\r
+               String mechID = mechID(cmds);\r
+               String machine = machine(cmds);\r
+               \r
+               TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);\r
+               try {\r
+               \r
+                       Future<Artifacts> acf = aafcon.client(CM_VER)\r
+                                       .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);\r
+                       if(acf.get(TIMEOUT)) {\r
+                               // Have to wait for JDK 1.7 source...\r
+                               //switch(artifact.getType()) {\r
+                               if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {\r
+                                       cons.printf("No Artifacts found for %s on %s", mechID, machine);\r
+                               } else {\r
+                                       String id = aafcon.defID();\r
+                                       GregorianCalendar now = new GregorianCalendar();\r
+                                       for(Artifact a : acf.value.getArtifact()) {\r
+                                               if(id.equals(a.getMechid())) {\r
+                                                       File dir = new File(a.getDir());\r
+                                                       Properties props = new Properties();\r
+                                                       FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));\r
+                                                       try {\r
+                                                               props.load(fis);\r
+                                                       } finally {\r
+                                                               fis.close();\r
+                                                       }\r
+                                                       \r
+                                                       String prop;                                            \r
+                                                       File f;\r
+       \r
+                                                       if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||\r
+                                                               !(f=new File(prop)).exists()) {\r
+                                                                       trans.error().printf("Keyfile must exist to check Certificates for %s on %s",\r
+                                                                               a.getMechid(), a.getMachine());\r
+                                                       } else {\r
+                                                               String ksf = props.getProperty(Config.CADI_KEYSTORE);\r
+                                                               String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);\r
+                                                               if(ksf==null || ksps == null) {\r
+                                                                       trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",\r
+                                                                                       Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());\r
+                                                               } else {\r
+                                                                       KeyStore ks = KeyStore.getInstance("JKS");\r
+                                                                       Symm symm = Symm.obtain(f);\r
+                                                                       \r
+                                                                       fis = new FileInputStream(ksf);\r
+                                                                       try {\r
+                                                                               ks.load(fis,symm.depass(ksps).toCharArray());\r
+                                                                       } finally {\r
+                                                                               fis.close();\r
+                                                                       }\r
+                                                                       X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);\r
+                                                                       String msg = null;\r
+\r
+                                                                       if(cert==null) {\r
+                                                                               msg = String.format("X509Certificate does not exist for %s on %s in %s",\r
+                                                                                               a.getMechid(), a.getMachine(), ksf);\r
+                                                                               trans.error().log(msg);\r
+                                                                               exitCode = 2;\r
+                                                                       } else {\r
+                                                                               GregorianCalendar renew = new GregorianCalendar();\r
+                                                                               renew.setTime(cert.getNotAfter());\r
+                                                                               renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());\r
+                                                                               if(renew.after(now)) {\r
+                                                                                       msg = String.format("As of %s, X509Certificate for %s on %s, expiration %s is still within %d renewal days.\n", \r
+                                                                                                       Chrono.dateOnlyStamp(), a.getMechid(), a.getMachine(), cert.getNotAfter(),a.getRenewDays());\r
+                                                                                       trans.info().log(msg);\r
+                                                                                       exitCode = 0; // OK\r
+                                                                               } else {\r
+                                                                                       trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n", \r
+                                                                                                       a.getMechid(), a.getMachine(),cert.getNotAfter());\r
+                                                                                       cmds.offerLast(mechID);\r
+                                                                                       cmds.offerLast(machine);\r
+                                                                                       if(placeCerts(trans,aafcon,cmds)) {\r
+                                                                                               msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n", \r
+                                                                                                               a.getMechid(), a.getMachine());\r
+                                                                                               exitCode = 10; // Refreshed\r
+                                                                                       } else {\r
+                                                                                               msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n", \r
+                                                                                                               a.getMechid(), a.getMachine());\r
+                                                                                               exitCode = 1; // Error Renewing\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       }\r
+                                                                       if(msg!=null) {\r
+                                                                               FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getAppName()+".msg");\r
+                                                                               try {\r
+                                                                                       fos.write(msg.getBytes());\r
+                                                                               } finally {\r
+                                                                                       fos.close();\r
+                                                                               }\r
+                                                                       }\r
+                                                               }\r
+                                                               \r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               trans.error().log(errMsg.toMsg(acf));\r
+                               exitCode=1;\r
+                       }\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+               return exitCode;\r
+       }\r
+\r
+}\r
+                       \r
+               \r
+\r
+\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/Factory.java b/aaf/src/src/main/java/com/att/cadi/cm/Factory.java
new file mode 100644 (file)
index 0000000..6fc9b27
--- /dev/null
@@ -0,0 +1,447 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.DataInputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.Reader;\r
+import java.io.StringReader;\r
+import java.security.InvalidKeyException;\r
+import java.security.Key;\r
+import java.security.KeyFactory;\r
+import java.security.KeyPair;\r
+import java.security.KeyPairGenerator;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.security.PrivateKey;\r
+import java.security.PublicKey;\r
+import java.security.SecureRandom;\r
+import java.security.Signature;\r
+import java.security.SignatureException;\r
+import java.security.cert.Certificate;\r
+import java.security.cert.CertificateEncodingException;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.CertificateFactory;\r
+import java.security.cert.X509Certificate;\r
+import java.security.spec.InvalidKeySpecException;\r
+import java.security.spec.PKCS8EncodedKeySpec;\r
+import java.security.spec.X509EncodedKeySpec;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.crypto.Cipher;\r
+import javax.crypto.NoSuchPaddingException;\r
+\r
+import com.att.cadi.Symm;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.TimeTaken;\r
+import com.att.inno.env.Trans;\r
+\r
+public class Factory {\r
+       public static final String KEY_ALGO = "RSA";\r
+       private static final String PRIVATE_KEY_HEADER = KEY_ALGO + " PRIVATE KEY";\r
+       public static final String SIG_ALGO = "SHA256withRSA";\r
+\r
+       public  static final int KEY_LENGTH = 2048;\r
+       private static final KeyPairGenerator keygen;\r
+       private static final KeyFactory keyFactory;\r
+       private static final CertificateFactory certificateFactory;\r
+       private static final SecureRandom random;\r
+       \r
+       \r
+       private static final Symm base64 = Symm.base64.copy(64);\r
+\r
+       static {\r
+                       random = new SecureRandom();\r
+                       KeyPairGenerator tempKeygen;\r
+                       try {\r
+                               tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");\r
+                               tempKeygen.initialize(KEY_LENGTH, random);\r
+                       } catch (NoSuchAlgorithmException e) {\r
+                               tempKeygen = null;\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+                       keygen = tempKeygen;\r
+\r
+                       KeyFactory tempKeyFactory;\r
+                       try {\r
+                               tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"\r
+                       } catch (NoSuchAlgorithmException e) {\r
+                               tempKeyFactory = null;\r
+                               e.printStackTrace(System.err);\r
+                       };\r
+                       keyFactory = tempKeyFactory;\r
+                        \r
+                       CertificateFactory tempCertificateFactory;\r
+                       try {\r
+                               tempCertificateFactory = CertificateFactory.getInstance("X.509");\r
+                       } catch (CertificateException e) {\r
+                               tempCertificateFactory = null;\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+                       certificateFactory = tempCertificateFactory;\r
+\r
+                \r
+       }\r
+\r
+\r
+       public static KeyPair generateKeyPair(Trans trans) {\r
+               TimeTaken tt;\r
+               if(trans!=null) {\r
+                       tt = trans.start("Generate KeyPair", Env.SUB);\r
+               } else {\r
+                       tt = null;\r
+               }\r
+               try {\r
+                       return keygen.generateKeyPair();\r
+               } finally {\r
+                       if(tt!=null) {\r
+                               tt.done();\r
+                       }\r
+               }\r
+       }  \r
+\r
+       private static final String LINE_END = "-----\n";\r
+\r
+       protected static String textBuilder(String kind, byte[] bytes) throws IOException {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append("-----BEGIN ");\r
+               sb.append(kind);\r
+               sb.append(LINE_END);\r
+\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               base64.encode(bais, baos);\r
+               sb.append(new String(baos.toByteArray()));\r
+               \r
+               if(sb.charAt(sb.length()-1)!='\n') {\r
+                       sb.append('\n');\r
+               }\r
+               sb.append("-----END ");\r
+               sb.append(kind);\r
+               sb.append(LINE_END);\r
+               return sb.toString();\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {\r
+               byte[] bytes = decode(new StringReader(pk));\r
+               return toPrivateKey(trans, bytes);\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {\r
+               TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);\r
+               try {\r
+                       return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));\r
+               } catch (InvalidKeySpecException e) {\r
+                       throw new CertException("Translating Private Key from PKCS8 KeySpec",e);\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {\r
+               TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);\r
+               try {\r
+                       return toPrivateKey(trans,decode(file));\r
+               }finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+\r
+       public static String toString(Trans trans, PrivateKey pk) throws IOException {\r
+               trans.debug().log("Private Key to String");\r
+               return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());\r
+       }\r
+\r
+       public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {\r
+               TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);\r
+               try {\r
+                       ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());\r
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+                       Symm.base64noSplit.decode(bais, baos);\r
+\r
+                       return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));\r
+               } catch (InvalidKeySpecException e) {\r
+                       trans.error().log(e,"Translating Public Key from X509 KeySpec");\r
+                       return null;\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+       \r
+       public static String toString(Trans trans, PublicKey pk) throws IOException {\r
+               trans.debug().log("Public Key to String");\r
+               return textBuilder("PUBLIC KEY",pk.getEncoded());\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, String x509) throws CertificateException {\r
+               return toX509Certificate(trans, x509.getBytes());\r
+       }\r
+       \r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, List<String> x509s) throws CertificateException {\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               try {\r
+                       for(String x509 : x509s) {\r
+                               baos.write(x509.getBytes());\r
+                       }\r
+               } catch (IOException e) {\r
+                       throw new CertificateException(e);\r
+               }\r
+               return toX509Certificate(trans, new ByteArrayInputStream(baos.toByteArray()));\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, byte[] x509) throws CertificateException {\r
+               return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {\r
+               FileInputStream fis = new FileInputStream(file);\r
+               try {\r
+                       return toX509Certificate(trans,fis);\r
+               } finally {\r
+                       try {\r
+                               fis.close();\r
+                       } catch (IOException e) {\r
+                               throw new CertificateException(e);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static Collection<? extends Certificate> toX509Certificate(Trans trans, InputStream is) throws CertificateException {\r
+               TimeTaken tt=trans.start("Reconstitute Certificates", Env.SUB);\r
+               try {\r
+                       return certificateFactory.generateCertificates(is);\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       \r
+\r
+       public static String toString(Trans trans, Certificate cert) throws IOException, CertException {\r
+               if(trans.debug().isLoggable()) {\r
+                       StringBuilder sb = new StringBuilder("Certificate to String");\r
+                       if(cert instanceof X509Certificate) {\r
+                               sb.append(" - ");\r
+                               sb.append(((X509Certificate)cert).getSubjectDN());\r
+                       }\r
+                       trans.debug().log(sb);\r
+               }\r
+               try {\r
+                       if(cert==null) {\r
+                               throw new CertException("Certificate not built");\r
+                       }\r
+                       return textBuilder("CERTIFICATE",cert.getEncoded());\r
+               } catch (CertificateEncodingException e) {\r
+                       throw new CertException(e);\r
+               }\r
+       }\r
+\r
+       public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {\r
+               return Cipher.getInstance(KEY_ALGO); \r
+       }\r
+\r
+       public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {\r
+               Cipher cipher = Cipher.getInstance(KEY_ALGO);\r
+               cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);\r
+               return cipher;\r
+       }\r
+\r
+       public static byte[] strip(Reader rdr) throws IOException {\r
+               BufferedReader br = new BufferedReader(rdr);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               String line;\r
+               while((line=br.readLine())!=null) {\r
+                       if(line.length()>0 &&\r
+                          !line.startsWith("-----") &&\r
+                          line.indexOf(':')<0) {  // Header elements\r
+                               baos.write(line.getBytes());\r
+                       }\r
+               }\r
+               return baos.toByteArray();\r
+       }\r
+       \r
+       public static class StripperInputStream extends InputStream {\r
+               private Reader created;\r
+               private BufferedReader br;\r
+               private int idx;\r
+               private String line;\r
+\r
+               public StripperInputStream(Reader rdr) {\r
+                       if(rdr instanceof BufferedReader) {\r
+                               br = (BufferedReader)rdr;\r
+                       } else {\r
+                               br = new BufferedReader(rdr);\r
+                       }\r
+                       created = null;\r
+               }\r
+               \r
+               public StripperInputStream(File file) throws FileNotFoundException {\r
+                       this(new FileReader(file));\r
+                       created = br;\r
+               }\r
+\r
+               public StripperInputStream(InputStream is) throws FileNotFoundException {\r
+                       this(new InputStreamReader(is));\r
+                       created = br;\r
+               }\r
+\r
+               @Override\r
+               public int read() throws IOException {\r
+                       if(line==null || idx>=line.length()) {\r
+                               while((line=br.readLine())!=null) {\r
+                                       if(line.length()>0 &&\r
+                                          !line.startsWith("-----") &&\r
+                                          line.indexOf(':')<0) {  // Header elements\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if(line==null) {\r
+                                       return -1;\r
+                               }\r
+                               idx = 0;\r
+                       }\r
+                       return line.charAt(idx++);\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see java.io.InputStream#close()\r
+                */\r
+               @Override\r
+               public void close() throws IOException {\r
+                       if(created!=null) {\r
+                               created.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static class Base64InputStream extends InputStream {\r
+               private InputStream created;\r
+               private InputStream is;\r
+               private byte trio[];\r
+               private byte duo[];\r
+               private int idx;\r
+\r
+               \r
+               public Base64InputStream(File file) throws FileNotFoundException {\r
+                       this(new FileInputStream(file));\r
+                       created = is;\r
+               }\r
+\r
+               public Base64InputStream(InputStream is) throws FileNotFoundException {\r
+                       this.is = is;\r
+                       trio = new byte[3];\r
+                       idx = 4;\r
+               }\r
+\r
+               @Override\r
+               public int read() throws IOException {\r
+                       if(duo==null || idx>=duo.length) {\r
+                               int read = is.read(trio);\r
+                               if(read==-1) {\r
+                                       return -1;\r
+                               }\r
+                               duo = Symm.base64.decode(trio);\r
+                               if(duo==null || duo.length==0) {\r
+                                       return -1;\r
+                               }\r
+                               idx=0;\r
+                       }\r
+                       \r
+                       return duo[idx++];\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see java.io.InputStream#close()\r
+                */\r
+               @Override\r
+               public void close() throws IOException {\r
+                       if(created!=null) {\r
+                               created.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static byte[] decode(byte[] bytes) throws IOException {\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               Symm.base64.decode(bais, baos);\r
+               return baos.toByteArray();\r
+       }\r
+       \r
+       public static byte[] decode(File f) throws IOException {\r
+               FileReader fr = new FileReader(f);\r
+               try {\r
+                       return Factory.decode(fr);\r
+               } finally {\r
+                       fr.close();\r
+               }\r
+\r
+       }\r
+       public static byte[] decode(Reader rdr) throws IOException {\r
+               return decode(strip(rdr));\r
+       }\r
+\r
+\r
+       public static byte[] binary(File file) throws IOException {\r
+               DataInputStream dis = new DataInputStream(new FileInputStream(file));\r
+               try {\r
+                       byte[] bytes = new byte[(int)file.length()];\r
+                       dis.readFully(bytes);\r
+                       return bytes;\r
+               } finally {\r
+                       dis.close();\r
+               }\r
+       }\r
+\r
+\r
+       public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {\r
+               TimeTaken tt = trans.start("Sign Data", Env.SUB);\r
+               try {\r
+                       Signature sig = Signature.getInstance(SIG_ALGO);\r
+                       sig.initSign(pk, random);\r
+                       sig.update(bytes);\r
+                       return sig.sign();\r
+               } finally {\r
+                       tt.done();\r
+               }\r
+       }\r
+\r
+       // TODO IMPLEMENT!\r
+       public static void getSignature(byte[] signed) {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifact.java b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifact.java
new file mode 100644 (file)
index 0000000..b5a3fb0
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.inno.env.Trans;\r
+\r
+public interface PlaceArtifact {\r
+       public boolean place(Trans trans, CertInfo cert, Artifact arti) throws CadiException;\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
new file mode 100644 (file)
index 0000000..219eb4a
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+\r
+public class PlaceArtifactInFiles extends ArtifactDir {\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               try {\r
+                       // Setup Public Cert\r
+                       File f = new File(dir,arti.getAppName()+".crt");\r
+                       write(f,Chmod.to644,certInfo.getCerts().get(0),C_R);\r
+                       \r
+                       // Setup Private Key\r
+                       f = new File(dir,arti.getAppName()+".key");\r
+                       write(f,Chmod.to400,certInfo.getPrivatekey(),C_R);\r
+                       \r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+}\r
+\r
+\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java
new file mode 100644 (file)
index 0000000..abe0586
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+import java.security.KeyStore;\r
+import java.security.PrivateKey;\r
+import java.security.cert.Certificate;\r
+import java.security.cert.X509Certificate;\r
+import java.util.Collection;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public class PlaceArtifactInKeystore extends ArtifactDir {\r
+       private String kst;\r
+       //TODO get ROOT DNs or Trusted DNs from Certificate Manager.\r
+       private static String[] rootDNs = new String[]{                 \r
+                       "CN=ATT CADI Root CA - Test, O=ATT, OU=CSO, C=US",      \r
+                       "CN=ATT AAF CADI CA, OU=CSO, O=ATT, C=US"\r
+       };\r
+\r
+       public PlaceArtifactInKeystore(String kst) {\r
+               this.kst = kst;\r
+       }\r
+\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               File fks = new File(dir,arti.getAppName()+'.'+kst);\r
+               try {\r
+                       KeyStore jks = KeyStore.getInstance(kst);\r
+                       if(fks.exists()) {\r
+                               fks.delete();\r
+                       }       \r
+\r
+                       // Get the Cert(s)... Might include Trust store\r
+                       Collection<? extends Certificate> certColl = Factory.toX509Certificate(trans, certInfo.getCerts());\r
+                       Certificate[] certs = new Certificate[certColl.size()];\r
+                       certColl.toArray(certs);\r
+                       \r
+                       boolean first = true;\r
+                       StringBuilder issuers = new StringBuilder();\r
+                       for(Certificate c : certs) {\r
+                               if(c instanceof X509Certificate) {\r
+                                       X509Certificate xc = (X509Certificate)c;\r
+                                       String issuer = xc.getIssuerDN().toString();\r
+                                       for(String root : rootDNs) {\r
+                                               if(root.equals(issuer)) {\r
+                                                       if(first) {\r
+                                                               first=false;\r
+                                                       } else {\r
+                                                               issuers.append(":");\r
+                                                       }\r
+                                                       if(xc.getSubjectDN().toString().contains("Issuing CA")) {\r
+                                                               issuers.append(xc.getSubjectDN());\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       addProperty(Config.CADI_X509_ISSUERS,issuers.toString());\r
+\r
+                       // Add CADI Keyfile Entry to Properties\r
+                       addProperty(Config.CADI_KEYFILE,arti.getDir()+'/'+arti.getAppName() + ".keyfile");\r
+                       // Set Keystore Password\r
+                       addProperty(Config.CADI_KEYSTORE,fks.getCanonicalPath());\r
+                       String keystorePass = Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       addEncProperty(Config.CADI_KEYSTORE_PASSWORD,keystorePass);\r
+                       char[] keystorePassArray = keystorePass.toCharArray();\r
+                       jks.load(null,keystorePassArray); // load in\r
+                       \r
+                       // Add Private Key/Cert Entry for App\r
+                       // Note: Java SSL security classes, while having a separate key from keystore,\r
+                       // is documented to not actually work. \r
+                       // java.security.UnrecoverableKeyException: Cannot recover key\r
+                       // You can create a custom Key Manager to make it work, but Practicality  \r
+                       // dictates that you live with the default, meaning, they are the same\r
+                       String keyPass = keystorePass; //Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       PrivateKey pk = Factory.toPrivateKey(trans, certInfo.getPrivatekey());\r
+                       addEncProperty(Config.CADI_KEY_PASSWORD, keyPass);\r
+                       addProperty(Config.CADI_ALIAS, arti.getMechid());\r
+//                     Set<Attribute> attribs = new HashSet<Attribute>();\r
+//                     if(kst.equals("pkcs12")) {\r
+//                             // Friendly Name\r
+//                             attribs.add(new PKCS12Attribute("1.2.840.113549.1.9.20", arti.getAppName()));\r
+//                     } \r
+//                     \r
+                       KeyStore.ProtectionParameter protParam = \r
+                                       new KeyStore.PasswordProtection(keyPass.toCharArray());\r
+                       \r
+                       KeyStore.PrivateKeyEntry pkEntry = \r
+                               new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]});\r
+                       jks.setEntry(arti.getMechid(), \r
+                                       pkEntry, protParam);\r
+               \r
+                       // Write out\r
+                       write(fks,Chmod.to400,jks,keystorePassArray);\r
+                       \r
+                       // Change out to TrustStore\r
+                       fks = new File(dir,arti.getAppName()+".trust."+kst);\r
+                       jks = KeyStore.getInstance(kst);\r
+                       \r
+                       // Set Truststore Password\r
+                       addProperty(Config.CADI_TRUSTSTORE,fks.getCanonicalPath());\r
+                       String trustStorePass = Symm.randomGen(CmAgent.PASS_SIZE);\r
+                       addEncProperty(Config.CADI_TRUSTSTORE_PASSWORD,trustStorePass);\r
+                       char[] truststorePassArray = trustStorePass.toCharArray();\r
+                       jks.load(null,truststorePassArray); // load in\r
+                       \r
+                       // Add Trusted Certificates\r
+                       for(int i=1; i<certs.length;++i) {\r
+                               jks.setCertificateEntry("cadi_" + arti.getCa() + '_' + i, certs[i]);\r
+                       }\r
+                       // Write out\r
+                       write(fks,Chmod.to400,jks,truststorePassArray);\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java
new file mode 100644 (file)
index 0000000..7815a8e
--- /dev/null
@@ -0,0 +1,53 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.PrintStream;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+import com.att.inno.env.Trans;\r
+\r
+public class PlaceArtifactOnStream implements PlaceArtifact {\r
+       private PrintStream out;\r
+\r
+       public PlaceArtifactOnStream(PrintStream printStream) {\r
+               out = printStream;\r
+       }\r
+\r
+       @Override\r
+       public boolean place(Trans trans, CertInfo capi, Artifact a) {\r
+               if(capi.getNotes()!=null && capi.getNotes().length()>0) {\r
+                       trans.info().printf("Warning:    %s\n",capi.getNotes());\r
+               }\r
+               out.printf("Challenge:  %s\n",capi.getChallenge());\r
+               out.printf("PrivateKey:\n%s\n",capi.getPrivatekey());\r
+               out.println("Certificate Chain:");\r
+               for(String c : capi.getCerts()) {\r
+                       out.println(c);\r
+               }\r
+               return true;\r
+       }\r
+}\r
diff --git a/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
new file mode 100644 (file)
index 0000000..0525739
--- /dev/null
@@ -0,0 +1,124 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.cm;\r
+\r
+import java.io.File;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.util.Chmod;\r
+import com.att.inno.env.Trans;\r
+import com.att.inno.env.util.Chrono;\r
+\r
+import certman.v1_0.Artifacts.Artifact;\r
+import certman.v1_0.CertInfo;\r
+\r
+public class PlaceArtifactScripts extends ArtifactDir {\r
+       @Override\r
+       public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {\r
+               try {\r
+                       // Setup check.sh script\r
+                       String filename = arti.getAppName()+".check.sh";\r
+                       File f1 = new File(dir,filename);\r
+                       String email = arti.getNotification() + '\n';\r
+                       if(email.startsWith("mailto:")) {\r
+                               email=email.substring(7);\r
+                       }  else {\r
+                               email=arti.getOsUser() + '\n';\r
+                       }\r
+                       write(f1,Chmod.to644,\r
+                                       "#!/bin/bash " + f1.getCanonicalPath()+'\n',\r
+                                       "# Certificate Manager Check Script\n",\r
+                                       "# Check on Certificate, and renew if needed.\n",\r
+                                       "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',\r
+                                       "DIR="+arti.getDir()+'\n',\r
+                                       "APP="+arti.getAppName()+'\n',\r
+                                       "EMAIL="+email,\r
+                                       checkScript\r
+                                       );\r
+                       \r
+                       // Setup check.sh script\r
+                       File f2 = new File(dir,arti.getAppName()+".crontab.sh");\r
+                       write(f2,Chmod.to644,\r
+                                       "#!/bin/bash " + f1.getCanonicalPath()+'\n',\r
+                                       "# Certificate Manager Crontab Loading Script\n",\r
+                                       "# Add/Update a Crontab entry, that adds a check on Certificate Manager generated Certificate nightly.\n",\r
+                                       "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',\r
+                                       "TFILE=\"/tmp/cmcron$$.temp\"\n",\r
+                                       "DIR=\""+arti.getDir()+"\"\n",\r
+                                       "CF=\""+arti.getAppName()+" Certificate Check Script\"\n",\r
+                                       "SCRIPT=\""+f1.getCanonicalPath()+"\"\n",\r
+                                       cronScript\r
+                                       );\r
+\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       private final static String checkScript = \r
+                       "> $DIR/$APP.msg\n\n" +\r
+                       "function mailit {\n" +\r
+                       "  printf \"$*\" | /bin/mail -s \"AAF Certman Notification for `uname -n`\" $EMAIL\n"+\r
+                       "}\n\n" +\r
+                       System.getProperty("java.home") + "/bin/" +"java -jar " +\r
+                               System.getProperty("java.class.path") +\r
+                               " cadi_prop_files=$DIR/$APP.props check 2>  $DIR/$APP.STDERR > $DIR/$APP.STDOUT\n" +\r
+                       "case \"$?\" in\n" +\r
+                       "  0)\n" +\r
+                       "    # Note: Validation will be mailed only the first day after any modification\n" +\r
+                       "    if [ \"`find $DIR -mtime 0 -name $APP.check.sh`\" != \"\" ] ; then\n" +\r
+                       "       mailit `echo \"Certficate Validated:\\n\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    else\n" +\r
+                       "       cat $DIR/$APP.msg\n" +\r
+                       "    fi\n" +\r
+                       "    ;;\n" +\r
+                       "  1) mailit \"Error with Certificate Check:\\\\n\\\\nCheck logs $DIR/$APP.STDOUT and $DIR/$APP.STDERR on `uname -n`\"\n" +\r
+                       "    ;;\n" +\r
+                       "  2) mailit `echo \"Certificate Check Error\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    ;;\n" +\r
+                       "  10) mailit `echo \"Certificate Replaced\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "      if [ -e $DIR/$APP.restart.sh ]; then\n" +\r
+                       "        # Note: it is THIS SCRIPT'S RESPONSIBILITY to notify upon success or failure as necessary!!\n" +\r
+                       "        /bin/sh $DIR/$APP.restart.sh\n" +\r
+                       "      fi\n" +\r
+                       "    ;;\n" +\r
+                       "  *) mailit `echo \"Unknown Error code for CM Agent\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +\r
+                       "    ;;\n" +\r
+                       " esac\n\n" +\r
+                       " # Note: make sure to cover this sripts' exit Code\n";\r
+       \r
+       private final static String cronScript = \r
+                       "crontab -l | sed -n \"/#### BEGIN $CF/,/END $CF ####/!p\" > $TFILE\n" +\r
+                       "# Note: Randomize Minutes (0-60) and hours (1-4)\n" +\r
+                       "echo \"#### BEGIN $CF ####\" >> $TFILE\n" +\r
+                       "echo \"$(( $RANDOM % 60)) $(( $(( $RANDOM % 3 )) + 1 )) * * * /bin/bash $SCRIPT " +\r
+                               ">> $DIR/cronlog 2>&1 \" >> $TFILE\n" +\r
+                       "echo \"#### END $CF ####\" >> $TFILE\n" +\r
+                       "crontab $TFILE\n" +\r
+                       "rm $TFILE\n";\r
+}\r
+\r
+\r
+\r
diff --git a/aaf/src/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java b/aaf/src/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java
new file mode 100644 (file)
index 0000000..f65f03f
--- /dev/null
@@ -0,0 +1,117 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+\r
+public class TestAccess implements Access {\r
+       private Symm symm;\r
+       private PrintStream out;\r
+\r
+       public TestAccess(PrintStream out) {\r
+               this.out = out;\r
+               InputStream is = ClassLoader.getSystemResourceAsStream("cadi.properties");\r
+               try {\r
+                       System.getProperties().load(is);\r
+               } catch (IOException e) {\r
+                       e.printStackTrace(out);\r
+               } finally {\r
+                       try {\r
+                               is.close();\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(out);\r
+                       }\r
+               }\r
+               \r
+               String keyfile = System.getProperty(Config.CADI_KEYFILE);\r
+               if(keyfile==null) {\r
+                       System.err.println("No " + Config.CADI_KEYFILE + " in Classpath");\r
+               } else {\r
+                       try {\r
+                               is = new FileInputStream(keyfile);\r
+                               try {\r
+                                       symm = Symm.obtain(is);\r
+                               } finally {\r
+                                       is.close();\r
+                               }\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(out);\r
+                       }\r
+               }\r
+               \r
+\r
+\r
+       }\r
+       \r
+       public void log(Level level, Object... elements) {\r
+               boolean first = true;\r
+               for(int i=0;i<elements.length;++i) {\r
+                       if(first)first = false;\r
+                       else out.print(' ');\r
+                       out.print(elements[i].toString());\r
+               }\r
+               out.println();\r
+       }\r
+\r
+       public void log(Exception e, Object... elements) {\r
+               e.printStackTrace(out);\r
+               log(Level.ERROR,elements);\r
+       }\r
+\r
+       public void setLogLevel(Level level) {\r
+               \r
+       }\r
+\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return true;\r
+       }\r
+\r
+       public ClassLoader classLoader() {\r
+               return ClassLoader.getSystemClassLoader();\r
+       }\r
+\r
+       public String getProperty(String string, String def) {\r
+               String rv = System.getProperty(string);\r
+               return rv==null?def:rv;\r
+       }\r
+\r
+       public void load(InputStream is) throws IOException {\r
+               \r
+       }\r
+\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/src/test/resources/cadi.properties b/aaf/src/src/test/resources/cadi.properties
new file mode 100644 (file)
index 0000000..4f38cf5
--- /dev/null
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+##\r
+## AUTHZ API (authz-service) Properties\r
+##\r
+\r
+cadi_prop_file=com.att.aaf.props;com.att.aaf.common.props\r
+\r
+#cadi_trust_all_x509=true\r
+#cadi_alias=aaf.att\r
+https.protocols=TLSv1.1,TLSv1.2\r
+\r
+cm_url=https://XXX:8150\r
+\r
+basic_realm=localized\r
+basic_warn=false\r
+localhost_deny=false\r
+\r
+cass_group_name=com.att.aaf\r
+cass_cluster_name=mithrilcsp.sbc.com\r
+aaf_default_realm=com.att.csp\r
+\r
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE\r
+aaf_id=???\r
+aaf_password=enc:XXX\r
+\r
+aaf_user_expires=3000\r
+aaf_clean_interval=4000\r
+\r
diff --git a/aaf/src/src/test/resources/log4j.properties b/aaf/src/src/test/resources/log4j.properties
new file mode 100644 (file)
index 0000000..91b81ef
--- /dev/null
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+#\r
+# Licensed to the Apache Software Foundation (ASF) under one\r
+# or more contributor license agreements.  See the NOTICE file\r
+# distributed with this work for additional information\r
+# regarding copyright ownership.  The ASF licenses this file\r
+# to you under the Apache License, Version 2.0 (the\r
+# "License"); you may not use this file except in compliance\r
+# with the License.  You may obtain a copy of the License at\r
+#\r
+#     http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing,\r
+# software distributed under the License is distributed on an\r
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
+# KIND, either express or implied.  See the License for the\r
+# specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender\r
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout\r
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] %m %n\r
+\r
+# General Apache libraries\r
+log4j.rootLogger=WARN,stdout\r
+log4j.logger.org.apache=WARN,stdout\r
+log4j.logger.dme2=WARN,stdout\r
+log4j.logger.init=INFO,stdout\r
+log4j.logger.authz=INFO,stdout\r
+log4j.logger.audit=WARN,stdout\r
+\r
+\r
+\r
diff --git a/aaf/src/src/test/resources/logging.props b/aaf/src/src/test/resources/logging.props
new file mode 100644 (file)
index 0000000..9a30a2a
--- /dev/null
@@ -0,0 +1,38 @@
+| ############################################################ 
+# Default Logging Configuration File 
+# 
+# You can use a different file by specifying a filename 
+# with the java.util.logging.config.file system property. 
+# For example java -Djava.util.logging.config.file=myfile 
+############################################################ 
+
+############################################################ 
+# Global properties 
+############################################################ 
+
+# "handlers" specifies a comma separated list of log Handler 
+# classes. These handlers will be installed during VM startup. 
+# Note that these classes must be on the system classpath. 
+# By default we only configure a ConsoleHandler, which will only 
+# show messages at the INFO and above levels. 
+handlers=java.util.logging.FileHandler 
+
+# Default global logging level. 
+# This specifies which kinds of events are logged across 
+# all loggers. For any given facility this global level 
+# can be overriden by a facility specific level 
+# Note that the ConsoleHandler also has a separate level 
+# setting to limit messages printed to the console. 
+.level=INFO 
+
+############################################################ 
+# Handler specific properties. 
+# Describes specific configuration info for Handlers. 
+############################################################ 
+java.util.logging.FileHandler.properties=autoFlush,fileName,dataPattern,name 
+java.util.logging.FileHandler.fileName=%h/.aaf/dme2.log 
+java.util.logging.FileHandlerFileHandler.autoFlush=true 
+java.util.logging.FileHandlerFileHandler.name=DailyRollingFileHandler 
+java.util.logging.FileHandlerFileHandler.datePattern='.'yyyy-MM-dd 
+com.att.aft.dme2.events.server.summary=INFO
+
diff --git a/aaf/src/test/java/com/att/aaf/content/JU_Content.java b/aaf/src/test/java/com/att/aaf/content/JU_Content.java
new file mode 100644 (file)
index 0000000..676dcc1
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.content;\r
+\r
+import java.io.StringReader;\r
+\r
+import org.junit.AfterClass;\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+import aaf.v2_0.Error;\r
+\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaData;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class JU_Content {\r
+\r
+       @BeforeClass\r
+       public static void setUpBeforeClass() throws Exception {\r
+       }\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+\r
+       @Test\r
+       public void parseErrorJSON() throws Exception {\r
+               final String msg = "{\"messageId\":\"SVC2000\",\"text\":\"Select which cred to delete (or 0 to delete all):" +\r
+                       "1) %1" +\r
+                       "2) %2" +\r
+                       "3) %3" +\r
+                       "4) %4" +\r
+                       "Run same command again with chosen entry as last parameter\"," +\r
+                       "\"variables\":[" +\r
+                       "\"m55555@jr583u.cred.test.com 1 Wed Oct 08 11:48:08 CDT 2014\"," +\r
+                       "\"m55555@jr583u.cred.test.com 1 Thu Oct 09 12:54:46 CDT 2014\"," +\r
+                       "\"m55555@jr583u.cred.test.com 1 Tue Jan 06 05:00:00 CST 2015\"," +\r
+                       "\"m55555@jr583u.cred.test.com 1 Wed Jan 07 05:00:00 CST 2015\"]}";\r
+               \r
+               Error err = new Error();\r
+               err.setText("Hello");\r
+               err.getVariables().add("I'm a teapot");\r
+               err.setMessageId("12");\r
+               \r
+               \r
+//             System.out.println(msg);\r
+               RosettaEnv env = new RosettaEnv();\r
+               RosettaDF<aaf.v2_0.Error> errDF = env.newDataFactory(aaf.v2_0.Error.class);\r
+               errDF.in(RosettaData.TYPE.JSON);\r
+               errDF.out(RosettaData.TYPE.JSON);\r
+               RosettaData<Error> data = errDF.newData();\r
+               data.load(err);\r
+               System.out.println(data.asString());\r
+               \r
+               data.load(new StringReader(msg));\r
+               err = data.asObject();\r
+               System.out.println(err.getText());\r
+       }\r
+               \r
+\r
+}\r
diff --git a/aaf/src/test/java/com/att/aaf/example/CadiTest.java b/aaf/src/test/java/com/att/aaf/example/CadiTest.java
new file mode 100644 (file)
index 0000000..f6cbce2
--- /dev/null
@@ -0,0 +1,59 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.example;\r
+\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.http.HClient;\r
+import com.att.cadi.http.HX509SS;\r
+\r
+public class CadiTest {\r
+       public static void main(String args[]) {\r
+               Access access = new PropAccess();\r
+               try {\r
+                       SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);\r
+                       HClient hclient = new HClient(\r
+                               new HX509SS(si),\r
+                               new URI("https://mithrilcsp.sbc.com:8085"),3000);\r
+                       hclient.setMethod("OPTIONS");\r
+                       hclient.setPathInfo("/gui/cadi/log/toggle/INFO");\r
+                       hclient.send();\r
+                       Future<String> future = hclient.futureReadString();\r
+                       if(future.get(5000)) {\r
+                               System.out.println(future.value);\r
+                       } else {\r
+                               System.out.printf("Error: %d-%s", future.code(),future.body());\r
+                       }\r
+                               \r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/aaf/example/ExampleAuthCheck.java b/aaf/src/test/java/com/att/aaf/example/ExampleAuthCheck.java
new file mode 100644 (file)
index 0000000..78b5e99
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.example;\r
+\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.locator.DNSLocator;\r
+\r
+public class ExampleAuthCheck {\r
+       public static void main(String args[]) {\r
+               // Link or reuse to your Logging mechanism\r
+               PropAccess myAccess = new PropAccess(); // \r
+               \r
+               try {\r
+                       AAFConHttp acon = new AAFConHttp(myAccess, new DNSLocator(\r
+                                       myAccess,"https","localhost","8100"));\r
+                       AAFAuthn<?> authn = acon.newAuthn();\r
+                       long start; \r
+                       for (int i=0;i<10;++i) {\r
+                               start = System.nanoTime();\r
+                               String err = authn.validate("", "gritty");\r
+                               if(err!=null) System.err.println(err);\r
+                               else System.out.println("I'm ok");\r
+                               \r
+                               err = authn.validate("bogus", "gritty");\r
+                               if(err!=null) System.err.println(err + " (correct error)");\r
+                               else System.out.println("I'm ok");\r
+\r
+                               System.out.println((System.nanoTime()-start)/1000000f + " ms");\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0.java b/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0.java
new file mode 100644 (file)
index 0000000..11092df
--- /dev/null
@@ -0,0 +1,114 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.example;\r
+\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.aaf.v2_0.AAFConDME2;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+\r
+public class ExamplePerm2_0 {\r
+       public static void main(String args[]) {\r
+\r
+               // Link or reuse to your Logging mechanism\r
+               PropAccess myAccess = new PropAccess();  \r
+               \r
+               // \r
+               try {\r
+                       AAFCon<?> acon = new AAFConDME2(myAccess);\r
+                       \r
+                       // AAFLur has pool of DME clients as needed, and Caches Client lookups\r
+                       AAFLurPerm aafLur = acon.newLur();\r
+                       \r
+                       // Note: If you need both Authn and Authz construct the following:\r
+                       AAFAuthn<?> aafAuthn = acon.newAuthn(aafLur);\r
+\r
+                       // Do not set Mech ID until after you construct AAFAuthn,\r
+                       // because we initiate  "401" info to determine the Realm of \r
+                       // of the service we're after.\r
+                       acon.basicAuth("mc0897@aaf.att.com", "XXXXXX");\r
+\r
+                       try {\r
+                               \r
+                               // Normally, you obtain Principal from Authentication System.\r
+                               // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()\r
+                               // If you use CADI as Authenticator, it will get you these Principals from\r
+                               // CSP or BasicAuth mechanisms.\r
+                               String id = "mc0897@aaf.att.com"; //"cluster_admin@gridcore.att.com";\r
+\r
+                               // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.\r
+                               String ok = aafAuthn.validate(id, "XXXXXX");\r
+                               if(ok!=null)System.out.println(ok);\r
+                               \r
+                               ok = aafAuthn.validate(id, "wrongPass");\r
+                               if(ok!=null)System.out.println(ok);\r
+\r
+\r
+                               // AAF Style permissions are in the form\r
+                               // Type, Instance, Action \r
+                               AAFPermission perm = new AAFPermission("com.att.grid.core.coh",":dev_cluster", "WRITE");\r
+                               \r
+                               // Now you can ask the LUR (Local Representative of the User Repository about Authorization\r
+                               // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object \r
+                               // instead of creating your own LUR\r
+                               System.out.println("Does " + id + " have " + perm);\r
+                               if(aafLur.fish(id, perm)) {\r
+                                       System.out.println("Yes, you have permission");\r
+                               } else {\r
+                                       System.out.println("No, you don't have permission");\r
+                               }\r
+\r
+                               System.out.println("Does Bogus have " + perm);\r
+                               if(aafLur.fish("Bogus", perm)) {\r
+                                       System.out.println("Yes, you have permission");\r
+                               } else {\r
+                                       System.out.println("No, you don't have permission");\r
+                               }\r
+\r
+                               // Or you can all for all the Permissions available\r
+                               List<Permission> perms = new ArrayList<Permission>();\r
+                               \r
+                               aafLur.fishAll(id,perms);\r
+                               for(Permission prm : perms) {\r
+                                       System.out.println(prm.getKey());\r
+                               }\r
+                               \r
+                               // It might be helpful in some cases to clear the User's identity from the Cache\r
+                               aafLur.remove(id);\r
+                       } finally {\r
+                               aafLur.destroy();\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0_DME2.java b/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0_DME2.java
new file mode 100644 (file)
index 0000000..2012465
--- /dev/null
@@ -0,0 +1,114 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.example;\r
+\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+import com.att.cadi.locator.DNSLocator;\r
+\r
+public class ExamplePerm2_0_DME2 {\r
+       public static void main(String args[]) {\r
+               // Link or reuse to your Logging mechanism\r
+               PropAccess myAccess = new PropAccess();  \r
+               \r
+               // \r
+               try {\r
+                       AAFConHttp acon = new AAFConHttp(myAccess, new DNSLocator(\r
+                                       myAccess,"https","localhost","8100"));\r
+                       \r
+                       // AAFLur has pool of DME clients as needed, and Caches Client lookups\r
+                       AAFLurPerm aafLur = acon.newLur();\r
+                       \r
+                       // Note: If you need both Authn and Authz construct the following:\r
+                       AAFAuthn<?> aafAuthn = acon.newAuthn(aafLur);\r
+\r
+                       // Do not set Mech ID until after you construct AAFAuthn,\r
+                       // because we initiate  "401" info to determine the Realm of \r
+                       // of the service we're after.\r
+                       acon.basicAuth("mc0897@aaf.att.com", "XXXXXX");\r
+\r
+                       try {\r
+                               \r
+                               // Normally, you obtain Principal from Authentication System.\r
+                               // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()\r
+                               // If you use CADI as Authenticator, it will get you these Principals from\r
+                               // CSP or BasicAuth mechanisms.\r
+                               String id = "mc0897@aaf.att.com"; //"cluster_admin@gridcore.att.com";\r
+\r
+                               // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.\r
+                               String ok = aafAuthn.validate(id, "XXXXXX");\r
+                               if(ok!=null)System.out.println(ok);\r
+                               \r
+                               ok = aafAuthn.validate(id, "wrongPass");\r
+                               if(ok!=null)System.out.println(ok);\r
+\r
+\r
+                               // AAF Style permissions are in the form\r
+                               // Type, Instance, Action \r
+                               AAFPermission perm = new AAFPermission("com.att.grid.core.coh",":dev_cluster", "WRITE");\r
+                               \r
+                               // Now you can ask the LUR (Local Representative of the User Repository about Authorization\r
+                               // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object \r
+                               // instead of creating your own LUR\r
+                               System.out.println("Does " + id + " have " + perm);\r
+                               if(aafLur.fish(id, perm)) {\r
+                                       System.out.println("Yes, you have permission");\r
+                               } else {\r
+                                       System.out.println("No, you don't have permission");\r
+                               }\r
+\r
+                               System.out.println("Does Bogus have " + perm);\r
+                               if(aafLur.fish("Bogus", perm)) {\r
+                                       System.out.println("Yes, you have permission");\r
+                               } else {\r
+                                       System.out.println("No, you don't have permission");\r
+                               }\r
+\r
+                               // Or you can all for all the Permissions available\r
+                               List<Permission> perms = new ArrayList<Permission>();\r
+                               \r
+                               aafLur.fishAll(id,perms);\r
+                               for(Permission prm : perms) {\r
+                                       System.out.println(prm.getKey());\r
+                               }\r
+                               \r
+                               // It might be helpful in some cases to clear the User's identity from the Cache\r
+                               aafLur.remove(id);\r
+                       } finally {\r
+                               aafLur.destroy();\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/aaf/example/X509Test.java b/aaf/src/test/java/com/att/aaf/example/X509Test.java
new file mode 100644 (file)
index 0000000..e1b6be6
--- /dev/null
@@ -0,0 +1,90 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.example;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.locator.DNSLocator;\r
+import com.att.cadi.lur.LocalPermission;\r
+\r
+public class X509Test {\r
+       public static void main(String args[]) {\r
+               // Link or reuse to your Logging mechanism\r
+               \r
+               PropAccess myAccess = new PropAccess();\r
+               \r
+               // \r
+               try {\r
+                       AAFConHttp con = new AAFConHttp(myAccess, \r
+                                       new DNSLocator(myAccess,"https","mithrilcsp.sbc.com","8100"));\r
+                       \r
+                       // AAFLur has pool of DME clients as needed, and Caches Client lookups\r
+                       AAFLurPerm aafLur = con.newLur();\r
+                       \r
+                       // Note: If you need both Authn and Authz construct the following:\r
+//                     AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);\r
+                       \r
+                       // con.x509Alias("aaf.att"); // alias in keystore\r
+\r
+                       try {\r
+                               \r
+                               // Normally, you obtain Principal from Authentication System.\r
+//                             // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()\r
+//                             // If you use CADI as Authenticator, it will get you these Principals from\r
+//                             // CSP or BasicAuth mechanisms.\r
+//                             String id = "cluster_admin@gridcore.att.com";\r
+//\r
+//                             // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.\r
+                               Future<String> fs = \r
+                                               con.client("2.0").read("/authz/perms/com.att.aaf.ca","application/Perms+json");\r
+                               if(fs.get(3000)) {\r
+                                       System.out.println(fs.value);\r
+                               } else {\r
+                                       System.out.println("Error: "  + fs.code() + ':' + fs.body());\r
+                               }\r
+                               \r
+                               // Check on Perms with LUR\r
+                               if(aafLur.fish(new Principal() {\r
+                                       @Override\r
+                                       public String getName() {\r
+                                               return "m12345@aaf.att.com";\r
+                                       }\r
+                               }, new LocalPermission("com.att.aaf.ca|aaf|request"))) {\r
+                                       System.out.println("Has Perm");\r
+                               } else {\r
+                                       System.out.println("Does NOT Have Perm");\r
+                               }\r
+                       } finally {\r
+                               aafLur.destroy();\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_JMeter.java b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_JMeter.java
new file mode 100644 (file)
index 0000000..b71a9ba
--- /dev/null
@@ -0,0 +1,146 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileReader;\r
+import java.io.PrintWriter;\r
+import java.io.StringWriter;\r
+import java.net.HttpURLConnection;\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Properties;\r
+\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+import com.att.cadi.aaf.v2_0.AAFTaf;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.locator.DNSLocator;\r
+import com.att.cadi.principal.CachedBasicPrincipal;\r
+\r
+import junit.framework.Assert;\r
+\r
+public class JU_JMeter {\r
+       private static AAFConHttp aaf;\r
+       private static AAFAuthn<HttpURLConnection> aafAuthn;\r
+       private static AAFLurPerm aafLur;\r
+       private static ArrayList<Principal> perfIDs;\r
+       \r
+       private static AAFTaf<HttpURLConnection> aafTaf;\r
+       private static PropAccess access;\r
+\r
+       @BeforeClass\r
+       public static void before() throws Exception {\r
+               if(aafLur==null) {\r
+                       Properties props = System.getProperties();\r
+                       props.setProperty("AFT_LATITUDE", "32.780140");\r
+                       props.setProperty("AFT_LONGITUDE", "-96.800451");\r
+                       props.setProperty("DME2_EP_REGISTRY_CLASS","DME2FS");\r
+                       props.setProperty("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");\r
+                       props.setProperty("AFT_ENVIRONMENT", "AFTUAT");\r
+                       props.setProperty("SCLD_PLATFORM", "NON-PROD");\r
+                       props.setProperty(Config.AAF_URL,"https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");\r
+                       props.setProperty(Config.AAF_READ_TIMEOUT, "2000");\r
+                       int timeToLive = 3000;\r
+                       props.setProperty(Config.AAF_CLEAN_INTERVAL, Integer.toString(timeToLive));\r
+                       props.setProperty(Config.AAF_HIGH_COUNT, "4");\r
+\r
+                       String aafPerfIDs = props.getProperty("AAF_PERF_IDS");\r
+                       perfIDs = new ArrayList<Principal>();\r
+                       File perfFile = null;\r
+                       if(aafPerfIDs!=null) {\r
+                               perfFile = new File(aafPerfIDs);\r
+                       }\r
+\r
+                       access = new PropAccess();\r
+                       aaf = new AAFConHttp(access, new DNSLocator(access,"https","localhost","8100"));\r
+                       aafTaf = new AAFTaf<HttpURLConnection>(aaf,false);\r
+                       aafLur = aaf.newLur(aafTaf);\r
+                       aafAuthn = aaf.newAuthn(aafTaf);\r
+                       aaf.basicAuth("testid@aaf.att.com", "whatever");\r
+\r
+                       if(perfFile==null||!perfFile.exists()) {\r
+                               perfIDs.add(new CachedBasicPrincipal(aafTaf, \r
+                                               "Basic dGVzdGlkOndoYXRldmVy", \r
+                                               "aaf.att.com",timeToLive));\r
+                               perfIDs.add(new Princ("ab1234@aaf.att.com")); // Example of Local ID, which isn't looked up\r
+                       } else {\r
+                               BufferedReader ir = new BufferedReader(new FileReader(perfFile));\r
+                               try {\r
+                                       String line;\r
+                                       while((line = ir.readLine())!=null) {\r
+                                               if((line=line.trim()).length()>0)\r
+                                                       perfIDs.add(new Princ(line));\r
+                                       }\r
+                               } finally {\r
+                                       ir.close();\r
+                               }\r
+                       }\r
+                       Assert.assertNotNull(aafLur);\r
+               }\r
+       }\r
+\r
+       private static class Princ implements Principal {\r
+               private String name;\r
+               public Princ(String name) {\r
+                       this.name = name;\r
+               }\r
+               public String getName() {\r
+                       return name;\r
+               }\r
+               \r
+       };\r
+       \r
+       private static int index = -1;\r
+       \r
+       private synchronized Principal getIndex() {\r
+               if(perfIDs.size()<=++index)index=0;\r
+               return perfIDs.get(index);\r
+       }\r
+       @Test\r
+       public void test() {\r
+               try {\r
+                               aafAuthn.validate("testid@aaf.att.com", "whatever");\r
+                               List<Permission> perms = new ArrayList<Permission>();\r
+                               aafLur.fishAll(getIndex(), perms);\r
+//                             Assert.assertFalse(perms.isEmpty());\r
+//                             for(Permission p : perms) {\r
+//                                     //access.log(Access.Level.AUDIT, p.permType());\r
+//                             }\r
+               } catch (Exception e) {\r
+                       StringWriter sw = new StringWriter();\r
+                       e.printStackTrace(new PrintWriter(sw));\r
+                       Assert.assertFalse(sw.toString(),true);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_Lur2_0Call.java b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_Lur2_0Call.java
new file mode 100644 (file)
index 0000000..2608980
--- /dev/null
@@ -0,0 +1,576 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.IOException;\r
+import java.io.UnsupportedEncodingException;\r
+import java.net.HttpURLConnection;\r
+import java.security.Principal;\r
+import java.util.Collection;\r
+import java.util.Enumeration;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+\r
+import javax.servlet.AsyncContext;\r
+import javax.servlet.DispatcherType;\r
+import javax.servlet.RequestDispatcher;\r
+import javax.servlet.ServletContext;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletInputStream;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.Cookie;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+import javax.servlet.http.HttpSession;\r
+import javax.servlet.http.Part;\r
+\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+import com.att.cadi.aaf.v2_0.AAFTaf;\r
+import com.att.cadi.locator.DNSLocator;\r
+import com.att.cadi.lur.ConfigPrincipal;\r
+import com.att.cadi.lur.LocalPermission;\r
+import com.att.cadi.taf.TafResp;\r
+\r
+public class JU_Lur2_0Call {\r
+       private static AAFConHttp aaf;\r
+       private static PropAccess access;\r
+\r
+       @BeforeClass\r
+       public static void setUpBeforeClass() throws Exception {\r
+               access = new PropAccess();\r
+               aaf = new AAFConHttp(access,new DNSLocator(access,"https","localhost","8100"));\r
+               aaf.basicAuth("testid", "whatever");\r
+       }\r
+\r
+       @Test \r
+       public void test() throws Exception {\r
+       \r
+               AAFLurPerm aafLur = aaf.newLur();\r
+\r
+               Principal pri = new ConfigPrincipal("testid@aaf.att.com","whatever");\r
+               for (int i = 0; i < 10; ++i) {\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|write"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kumquat|write"),false);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|read"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kumquat|read"),true);\r
+                       \r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","write"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","kumquat","write"),false);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","read"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","kumquat","read"),true);\r
+\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum.*|read"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|!wr*"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance"),true);\r
+\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!kum.*","read"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","!wr*"),true);\r
+\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum[Qq]uat|read"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my[iI]nstance|!wr*"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my[iI]nstance|!wr*"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|!wr*"),true);\r
+\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!kum[Qq]uat","read"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!my[iI]nstance","!wr*"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!my[iI]nstance","!wr*"),true);\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","!wr*"),true);\r
+                       \r
+\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my.nstance|!wr*"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|my.nstance|!wr*"),false);\r
+                       \r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|my.nstance|!wr*"),false);\r
+                       \r
+                       //Maitrayee, aren't we going to have issues if we do RegExp with "."?\r
+                       //Is it too expensive to only do Reg Ex in presence of special characters, []{}*, etc? Not sure this helps for GRID.\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kum.quat|read"),true);\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum..uat|read"),true);\r
+                       \r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance"),true); // ok if Stored Action is "*"\r
+                       \r
+                       // Key Evaluations\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*:!my.*|write"),true); // ok if Stored Action is "*"\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*|write"),false); // not ok if key lengths don't match "*"\r
+                       print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*:myCF|write"),true); // ok if Stored Action is "*"\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*:!my.*","write"),true); // ok if Stored Action is "*"\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*:myCF","write"),true); // ok if Stored Action is "*"\r
+                       print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*","write"),false); // not ok if key lengths don't match\r
+                       \r
+               }\r
+\r
+               print(aafLur, pri, new LocalPermission("bogus"),false);\r
+\r
+//             try {\r
+//                     Thread.sleep(7000);\r
+//             } catch (InterruptedException e) {\r
+//                     e.printStackTrace();\r
+//             }\r
+               for (int i = 0; i < 10; ++i)\r
+                       print(aafLur, pri, new LocalPermission("supergroup"),false);\r
+\r
+               System.out.println("All Done");\r
+       }\r
+       @Test\r
+       public void testTaf() throws Exception {\r
+               AAFTaf<?> aaft = new AAFTaf<HttpURLConnection>(aaf,true);\r
+               \r
+               TafResp resp;\r
+               // No Header\r
+               resp = aaft.validate(LifeForm.CBLF, new Req(), null);\r
+               assertEquals(TafResp.RESP.TRY_AUTHENTICATING, resp.isAuthenticated());\r
+\r
+               String auth = "Basic " + Symm.base64.encode("testid:whatever");\r
+               resp = aaft.validate(LifeForm.CBLF, new Req("Authorization",auth), null);\r
+               assertEquals(TafResp.RESP.IS_AUTHENTICATED, resp.isAuthenticated());\r
+               \r
+       }\r
+//     @Test\r
+//     public void testRole() throws CadiException {\r
+//             TestAccess ta = new TestAccess();\r
+//             AAFLurRole1_0 aafLur = new AAFLurRole1_0(\r
+//                             ta,\r
+////                           "http://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=1.0.0/envContext=UAT/routeOffer=BAU_SE",\r
+//                             "http://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=1.0.0/envContext=DEV/routeOffer=D1",\r
+//                             "m12345", "m12345pass", 50000, // dme Time\r
+//                             // 5*60000); // 5 minutes User Expiration\r
+//                             50000, // 5 seconds after Expiration\r
+//                             200); // High Count of items.. These do not take much memory\r
+//\r
+//             Principal pri = new ConfigPrincipal("xy1234","whatever);\r
+//             for (int i = 0; i < 10; ++i) {\r
+////                   print(aafLur, pri, new LocalPermission("*|*|*|com.att.authz"));\r
+//                     print(aafLur, pri, new LocalPermission("service|myInstance|write"),false);\r
+//                     print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|write"),false);\r
+//                     print(aafLur, pri, new LocalPermission("com.att.cadi"),true);\r
+//                     print(aafLur, pri, new LocalPermission("global"),true);\r
+//                     print(aafLur, pri, new LocalPermission("kumquat"),false);\r
+//             }\r
+//\r
+//             print(aafLur, pri, new LocalPermission("bogus"),false);\r
+//\r
+//             for (int i = 0; i < 10; ++i)\r
+//                     print(aafLur, pri, new LocalPermission("supergroup"),false);\r
+//\r
+//             System.out.println("All Done");\r
+//     }\r
+\r
+\r
+       private void print(Lur aafLur, Principal pri, Permission perm, boolean shouldBe)\r
+                       throws CadiException {\r
+               long start = System.nanoTime();\r
+       \r
+               // The Call\r
+               boolean ok = aafLur.fish(pri, perm);\r
+       \r
+               assertEquals(shouldBe,ok);\r
+               float ms = (System.nanoTime() - start) / 1000000f;\r
+               if (ok) {\r
+                       System.out.println("Yes, part of " + perm.getKey() + " (" + ms\r
+                                       + "ms)");\r
+               } else {\r
+                       System.out.println("No, not part of " + perm.getKey() + " (" + ms\r
+                                       + "ms)");\r
+               }\r
+       }\r
+\r
+       @SuppressWarnings("rawtypes")\r
+       public class Req implements HttpServletRequest {\r
+               private String[] headers;\r
+\r
+               public Req(String ... headers) {\r
+                       this.headers = headers;\r
+               }\r
+\r
+               public Object getAttribute(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Enumeration getAttributeNames() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getCharacterEncoding() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public void setCharacterEncoding(String env)\r
+                               throws UnsupportedEncodingException {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+\r
+               public int getContentLength() {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public String getContentType() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public ServletInputStream getInputStream() throws IOException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getParameter(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Enumeration getParameterNames() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String[] getParameterValues(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Map getParameterMap() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getProtocol() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getScheme() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getServerName() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public int getServerPort() {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public BufferedReader getReader() throws IOException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRemoteAddr() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRemoteHost() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public void setAttribute(String name, Object o) {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+\r
+               public void removeAttribute(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+\r
+               public Locale getLocale() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Enumeration getLocales() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public boolean isSecure() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               public RequestDispatcher getRequestDispatcher(String path) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRealPath(String path) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public int getRemotePort() {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public String getLocalName() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getLocalAddr() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public int getLocalPort() {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public String getAuthType() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public Cookie[] getCookies() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public long getDateHeader(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public String getHeader(String name) {\r
+                       for(int i=1;i<headers.length;i=i+2) {\r
+                               if(headers[i-1].equals(name)) return headers[i];\r
+                       }\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Enumeration getHeaders(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @SuppressWarnings("unchecked")\r
+               public Enumeration getHeaderNames() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public int getIntHeader(String name) {\r
+                       // TODO Auto-generated method stub\r
+                       return 0;\r
+               }\r
+\r
+               public String getMethod() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getPathInfo() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getPathTranslated() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getContextPath() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getQueryString() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRemoteUser() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public boolean isUserInRole(String role) {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               public Principal getUserPrincipal() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRequestedSessionId() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getRequestURI() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public StringBuffer getRequestURL() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public String getServletPath() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public HttpSession getSession(boolean create) {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public HttpSession getSession() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               public boolean isRequestedSessionIdValid() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               public boolean isRequestedSessionIdFromCookie() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               public boolean isRequestedSessionIdFromURL() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               public boolean isRequestedSessionIdFromUrl() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               @Override\r
+               public ServletContext getServletContext() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public AsyncContext startAsync() throws IllegalStateException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public AsyncContext startAsync(ServletRequest servletRequest,\r
+                               ServletResponse servletResponse) throws IllegalStateException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public boolean isAsyncStarted() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               @Override\r
+               public boolean isAsyncSupported() {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               @Override\r
+               public AsyncContext getAsyncContext() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public DispatcherType getDispatcherType() {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public boolean authenticate(HttpServletResponse response)\r
+                               throws IOException, ServletException {\r
+                       // TODO Auto-generated method stub\r
+                       return false;\r
+               }\r
+\r
+               @Override\r
+               public void login(String username, String password)\r
+                               throws ServletException {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+\r
+               @Override\r
+               public void logout() throws ServletException {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+\r
+               @Override\r
+               public Collection<Part> getParts() throws IOException, ServletException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+\r
+               @Override\r
+               public Part getPart(String name) throws IOException, ServletException {\r
+                       // TODO Auto-generated method stub\r
+                       return null;\r
+               }\r
+               \r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_PermEval.java b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_PermEval.java
new file mode 100644 (file)
index 0000000..efd108f
--- /dev/null
@@ -0,0 +1,109 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import static org.junit.Assert.*;\r
+\r
+import org.junit.AfterClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.aaf.PermEval;\r
+\r
+public class JU_PermEval {\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() {\r
+               assertTrue(PermEval.evalInstance(":com.att.temp:role:write",":!com.att.*:role:write"));\r
+               \r
+               // TRUE\r
+               assertTrue(PermEval.evalAction("fred","fred"));\r
+               assertTrue(PermEval.evalAction("fred,wilma","fred"));\r
+               assertTrue(PermEval.evalAction("barney,betty,fred,wilma","fred"));\r
+               assertTrue(PermEval.evalAction("*","fred"));\r
+               \r
+               assertTrue(PermEval.evalInstance("fred","fred"));\r
+               assertTrue(PermEval.evalInstance("fred,wilma","fred"));\r
+               assertTrue(PermEval.evalInstance("barney,betty,fred,wilma","fred"));\r
+               assertTrue(PermEval.evalInstance("*","fred"));\r
+               \r
+               assertTrue(PermEval.evalInstance(":fred:fred",":fred:fred"));\r
+               assertTrue(PermEval.evalInstance(":fred:fred,wilma",":fred:fred"));\r
+               assertTrue(PermEval.evalInstance(":fred:barney,betty,fred,wilma",":fred:fred"));\r
+               assertTrue(PermEval.evalInstance("*","fred"));\r
+               assertTrue(PermEval.evalInstance(":*:fred",":fred:fred"));\r
+               assertTrue(PermEval.evalInstance(":fred:*",":fred:fred"));\r
+               assertTrue(PermEval.evalInstance(":fred:fred",":!f.*:fred"));\r
+               assertTrue(PermEval.evalInstance(":fred:fred",":fred:!f.*"));\r
+               \r
+               /// FALSE\r
+               assertFalse(PermEval.evalInstance("fred","wilma"));\r
+               assertFalse(PermEval.evalInstance("fred,barney,betty","wilma"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":fred:wilma"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":wilma:fred"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":wilma:!f.*"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":!f.*:wilma"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":!w.*:!f.*"));\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":!f.*:!w.*"));\r
+\r
+               assertFalse(PermEval.evalInstance(":fred:fred",":fred:!x.*"));\r
+\r
+               // MSO Tests 12/3/2015\r
+               assertFalse(PermEval.evalInstance("/v1/services/features/*","/v1/services/features"));\r
+               assertFalse(PermEval.evalInstance(":v1:services:features:*",":v1:services:features"));\r
+               assertTrue(PermEval.evalInstance("/v1/services/features/*","/v1/services/features/api1"));\r
+               assertTrue(PermEval.evalInstance(":v1:services:features:*",":v1:services:features:api2"));\r
+               // MSO - Xue Gao\r
+               assertTrue(PermEval.evalInstance(":v1:requests:*",":v1:requests:test0-service"));   \r
+\r
+\r
+               \r
+               // Same tests, with Slashes\r
+               assertTrue(PermEval.evalInstance("/fred/fred","/fred/fred"));\r
+               assertTrue(PermEval.evalInstance("/fred/fred,wilma","/fred/fred"));\r
+               assertTrue(PermEval.evalInstance("/fred/barney,betty,fred,wilma","/fred/fred"));\r
+               assertTrue(PermEval.evalInstance("*","fred"));\r
+               assertTrue(PermEval.evalInstance("/*/fred","/fred/fred"));\r
+               assertTrue(PermEval.evalInstance("/fred/*","/fred/fred"));\r
+               assertTrue(PermEval.evalInstance("/fred/fred","/!f.*/fred"));\r
+               assertTrue(PermEval.evalInstance("/fred/fred","/fred/!f.*"));\r
+               \r
+               /// FALSE\r
+               assertFalse(PermEval.evalInstance("fred","wilma"));\r
+               assertFalse(PermEval.evalInstance("fred,barney,betty","wilma"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/fred/wilma"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/wilma/fred"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/wilma/!f.*"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/!f.*/wilma"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/!w.*/!f.*"));\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/!f.*/!w.*"));\r
+\r
+               assertFalse(PermEval.evalInstance("/fred/fred","/fred/!x.*"));\r
+               \r
+       }\r
+\r
+}\r
diff --git a/aaf/src/test/java/com/att/cadi/lur/aaf/test/MultiThreadPermHit.java b/aaf/src/test/java/com/att/cadi/lur/aaf/test/MultiThreadPermHit.java
new file mode 100644 (file)
index 0000000..cec5404
--- /dev/null
@@ -0,0 +1,146 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.aaf.AAFPermission;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFConHttp;\r
+import com.att.cadi.aaf.v2_0.AAFLurPerm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.locator.PropertyLocator;\r
+\r
+public class MultiThreadPermHit {\r
+       public static void main(String args[]) {\r
+               // Link or reuse to your Logging mechanism\r
+               PropAccess myAccess = new PropAccess(); // \r
+               \r
+               // \r
+               try {\r
+                       AAFConHttp con = new AAFConHttp(myAccess,new PropertyLocator("https://mithrilcsp.sbc.com:8100"));\r
+                       \r
+                       // AAFLur has pool of DME clients as needed, and Caches Client lookups\r
+                       final AAFLurPerm aafLur = con.newLur();\r
+                       aafLur.setDebug("m12345@aaf.att.com");\r
+\r
+                       // Note: If you need both Authn and Authz construct the following:\r
+                       AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);\r
+                       \r
+                       // Do not set Mech ID until after you construct AAFAuthn,\r
+                       // because we initiate  "401" info to determine the Realm of \r
+                       // of the service we're after.\r
+                       final String id = myAccess.getProperty(Config.AAF_MECHID,null);\r
+                       final String pass = myAccess.decrypt(myAccess.getProperty(Config.AAF_MECHPASS,null),false);\r
+                       if(id!=null && pass!=null) {\r
+                               try {\r
+                                       \r
+                                       // Normally, you obtain Principal from Authentication System.\r
+       //                              // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()\r
+       //                              // If you use CADI as Authenticator, it will get you these Principals from\r
+       //                              // CSP or BasicAuth mechanisms.\r
+       //                              String id = "cluster_admin@gridcore.att.com";\r
+       //\r
+       //                              // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.\r
+                                       String ok;\r
+                                       ok = aafAuthn.validate(id, pass);\r
+                                       if(ok!=null) {\r
+                                               System.out.println(ok);\r
+                                       }\r
+\r
+                                       List<Permission> pond = new ArrayList<Permission>();\r
+                                       for(int i=0;i<20;++i) {\r
+                                               pond.clear();\r
+                                               aafLur.fishAll(i+id, pond);\r
+                                               if(ok!=null && i%1000==0) {\r
+                                                       System.out.println(i + " " + ok);\r
+                                               }\r
+                                       }\r
+\r
+                                       for(int i=0;i<1000000;++i) {\r
+                                               ok = aafAuthn.validate( i+ id, "wrongPass");\r
+                                               if(ok!=null && i%1000==0) {\r
+                                                       System.out.println(i + " " + ok);\r
+                                               }\r
+                                       }\r
+       \r
+                                       final AAFPermission perm = new AAFPermission("com.att.aaf.access","*","*");\r
+                                       \r
+                                       // Now you can ask the LUR (Local Representative of the User Repository about Authorization\r
+                                       // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object \r
+                                       // instead of creating your own LUR\r
+                                       for(int i=0;i<4;++i) {\r
+                                               if(aafLur.fish(id, perm)) {\r
+                                                       System.out.println("Yes, " + id + " has permission for " + perm.getKey());\r
+                                               } else {\r
+                                                       System.out.println("No, " + id + " does not have permission for " + perm.getKey());\r
+                                               }\r
+                                       }\r
+       \r
+       \r
+                                       // Or you can all for all the Permissions available\r
+                                       List<Permission> perms = new ArrayList<Permission>();\r
+       \r
+                                       \r
+                                       aafLur.fishAll(id,perms);\r
+                                       System.out.println("Perms for " + id);\r
+                                       for(Permission prm : perms) {\r
+                                               System.out.println(prm.getKey());\r
+                                       }\r
+                                       \r
+                                       System.out.println("Press any key to continue");\r
+                                       System.in.read();\r
+                                       \r
+                                       for(int j=0;j<5;++j) {\r
+                                               new Thread(new Runnable() {\r
+                                                       @Override\r
+                                                       public void run() {\r
+                                                               for(int i=0;i<20;++i) {\r
+                                                                       if(aafLur.fish(id, perm)) {\r
+                                                                               System.out.println("Yes, " + id + " has permission for " + perm.getKey());\r
+                                                                       } else {\r
+                                                                               System.out.println("No, " + id + " does not have permission for " + perm.getKey());\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }).start();\r
+                                       }\r
+       \r
+                                       \r
+                               } finally {\r
+                                       aafLur.destroy();\r
+                               }\r
+                       } else { // checked on IDs\r
+                               System.err.println(Config.AAF_MECHID + " and/or " + Config.AAF_MECHPASS + " are not set.");\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+}\r
diff --git a/aaf/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java b/aaf/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java
new file mode 100644 (file)
index 0000000..0554d1d
--- /dev/null
@@ -0,0 +1,123 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.aaf.test;\r
+\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+\r
+public class TestAccess implements Access {\r
+       private Symm symm;\r
+       private PrintStream out;\r
+\r
+       public TestAccess(PrintStream out) {\r
+               this.out = out;\r
+               InputStream is = ClassLoader.getSystemResourceAsStream("cadi.properties");\r
+               try {\r
+                       System.getProperties().load(is);\r
+               } catch (IOException e) {\r
+                       e.printStackTrace(out);\r
+               } finally {\r
+                       try {\r
+                               is.close();\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(out);\r
+                       }\r
+               }\r
+               \r
+               String keyfile = System.getProperty(Config.CADI_KEYFILE);\r
+               if(keyfile==null) {\r
+                       System.err.println("No " + Config.CADI_KEYFILE + " in Classpath");\r
+               } else {\r
+                       try {\r
+                               is = new FileInputStream(keyfile);\r
+                               try {\r
+                                       symm = Symm.obtain(is);\r
+                               } finally {\r
+                                       is.close();\r
+                               }\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(out);\r
+                       }\r
+               }\r
+               \r
+\r
+\r
+       }\r
+       \r
+       public void log(Level level, Object... elements) {\r
+               boolean first = true;\r
+               for(int i=0;i<elements.length;++i) {\r
+                       if(first)first = false;\r
+                       else out.print(' ');\r
+                       out.print(elements[i].toString());\r
+               }\r
+               out.println();\r
+       }\r
+\r
+       public void log(Exception e, Object... elements) {\r
+               e.printStackTrace(out);\r
+               log(Level.ERROR,elements);\r
+       }\r
+\r
+       public void setLogLevel(Level level) {\r
+               \r
+       }\r
+\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return true;\r
+       }\r
+\r
+       public ClassLoader classLoader() {\r
+               return ClassLoader.getSystemClassLoader();\r
+       }\r
+\r
+       public String getProperty(String string, String def) {\r
+               String rv = System.getProperty(string);\r
+               return rv==null?def:rv;\r
+       }\r
+\r
+       public void load(InputStream is) throws IOException {\r
+               \r
+       }\r
+\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object... elements) {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/aaf/src/test/resources/cadi.properties b/aaf/src/test/resources/cadi.properties
new file mode 100644 (file)
index 0000000..4f38cf5
--- /dev/null
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+##\r
+## AUTHZ API (authz-service) Properties\r
+##\r
+\r
+cadi_prop_file=com.att.aaf.props;com.att.aaf.common.props\r
+\r
+#cadi_trust_all_x509=true\r
+#cadi_alias=aaf.att\r
+https.protocols=TLSv1.1,TLSv1.2\r
+\r
+cm_url=https://XXX:8150\r
+\r
+basic_realm=localized\r
+basic_warn=false\r
+localhost_deny=false\r
+\r
+cass_group_name=com.att.aaf\r
+cass_cluster_name=mithrilcsp.sbc.com\r
+aaf_default_realm=com.att.csp\r
+\r
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE\r
+aaf_id=???\r
+aaf_password=enc:XXX\r
+\r
+aaf_user_expires=3000\r
+aaf_clean_interval=4000\r
+\r
diff --git a/aaf/src/test/resources/log4j.properties b/aaf/src/test/resources/log4j.properties
new file mode 100644 (file)
index 0000000..91b81ef
--- /dev/null
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+#\r
+# Licensed to the Apache Software Foundation (ASF) under one\r
+# or more contributor license agreements.  See the NOTICE file\r
+# distributed with this work for additional information\r
+# regarding copyright ownership.  The ASF licenses this file\r
+# to you under the Apache License, Version 2.0 (the\r
+# "License"); you may not use this file except in compliance\r
+# with the License.  You may obtain a copy of the License at\r
+#\r
+#     http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing,\r
+# software distributed under the License is distributed on an\r
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
+# KIND, either express or implied.  See the License for the\r
+# specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender\r
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout\r
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] %m %n\r
+\r
+# General Apache libraries\r
+log4j.rootLogger=WARN,stdout\r
+log4j.logger.org.apache=WARN,stdout\r
+log4j.logger.dme2=WARN,stdout\r
+log4j.logger.init=INFO,stdout\r
+log4j.logger.authz=INFO,stdout\r
+log4j.logger.audit=WARN,stdout\r
+\r
+\r
+\r
diff --git a/aaf/src/test/resources/logging.props b/aaf/src/test/resources/logging.props
new file mode 100644 (file)
index 0000000..9a30a2a
--- /dev/null
@@ -0,0 +1,38 @@
+| ############################################################ 
+# Default Logging Configuration File 
+# 
+# You can use a different file by specifying a filename 
+# with the java.util.logging.config.file system property. 
+# For example java -Djava.util.logging.config.file=myfile 
+############################################################ 
+
+############################################################ 
+# Global properties 
+############################################################ 
+
+# "handlers" specifies a comma separated list of log Handler 
+# classes. These handlers will be installed during VM startup. 
+# Note that these classes must be on the system classpath. 
+# By default we only configure a ConsoleHandler, which will only 
+# show messages at the INFO and above levels. 
+handlers=java.util.logging.FileHandler 
+
+# Default global logging level. 
+# This specifies which kinds of events are logged across 
+# all loggers. For any given facility this global level 
+# can be overriden by a facility specific level 
+# Note that the ConsoleHandler also has a separate level 
+# setting to limit messages printed to the console. 
+.level=INFO 
+
+############################################################ 
+# Handler specific properties. 
+# Describes specific configuration info for Handlers. 
+############################################################ 
+java.util.logging.FileHandler.properties=autoFlush,fileName,dataPattern,name 
+java.util.logging.FileHandler.fileName=%h/.aaf/dme2.log 
+java.util.logging.FileHandlerFileHandler.autoFlush=true 
+java.util.logging.FileHandlerFileHandler.name=DailyRollingFileHandler 
+java.util.logging.FileHandlerFileHandler.datePattern='.'yyyy-MM-dd 
+com.att.aft.dme2.events.server.summary=INFO
+
diff --git a/cass/.gitignore b/cass/.gitignore
new file mode 100644 (file)
index 0000000..cf85207
--- /dev/null
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/cass/etc/cadi.properties b/cass/etc/cadi.properties
new file mode 100644 (file)
index 0000000..f9676b0
--- /dev/null
@@ -0,0 +1,69 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+##\r
+## AUTHZ API (authz-service) Properties\r
+##\r
+\r
+## DISCOVERY (DME2) Parameters on the Command Line\r
+AFT_LATITUDE=38.627345\r
+AFT_LONGITUDE=-90.193774\r
+AFT_ENVIRONMENT=AFTUAT\r
+\r
+# CADI \r
+cadi_keyfile=/opt/app/aaf/common/com.att.aaf.keyfile\r
+cadi_loglevel=WARN\r
+\r
+# CASSANDRA Required for APP\r
+cass_group_name=com.att.aaf\r
+\r
+# CASSANDRA Optional\r
+cass_cluster_name=mithril\r
+\r
+# AAF Required for APP\r
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE\r
+DME2_EP_REGISTRY_CLASS=DME2FS\r
+AFT_DME2_EP_REGISTRY_FS_DIR=/Volumes/Data/src/authz/dme2reg\r
+\r
+aaf_default_realm=aaf.localized\r
+aaf_id=XX@NS\r
+aaf_password=enc:\r
+cadi_loglevel=DEBUG\r
+\r
+# AAF Optional\r
+# Connection Time Out (milliseconds)\r
+aaf_conn_timeout=10000\r
+# User Cache Expiration (milliseconds)\r
+aaf_user_expires=600000\r
+# High count... Rough top number of objects held in Cache per cycle.  If high is reached, more are\r
+# recycled next time.  \r
+aaf_high_count=1000\r
+\r
+##\r
+## Localized Passwords\r
+##\r
+basic_realm=aaf.localized\r
+local_users=root@aaf.localized%<PASS>:/dbname\r
diff --git a/cass/pom.xml b/cass/pom.xml
new file mode 100644 (file)
index 0000000..89582d6
--- /dev/null
@@ -0,0 +1,115 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<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">\r
+       <parent>\r
+               <groupId>com.att.cadi</groupId>\r
+               <artifactId>parent</artifactId>\r
+               <version>1.3.2</version>\r
+               <relativePath>..</relativePath>\r
+       </parent>\r
+\r
+       <modelVersion>4.0.0</modelVersion>\r
+       <name>CADI Cassandra Plugin</name>\r
+       <packaging>jar</packaging>\r
+       <url>https://github.com/att/AAF</url>\r
+       <description>CADI</description>\r
+       <artifactId>cadi-cass</artifactId>\r
+\r
+       <dependencies>\r
+               <dependency>\r
+                       <groupId>com.att.cadi</groupId>\r
+                       <artifactId>cadi-aaf</artifactId>\r
+               </dependency>\r
+               \r
+               <dependency>\r
+               <groupId>org.apache.cassandra</groupId>\r
+               <artifactId>cassandra-all</artifactId>\r
+               <version>2.1.14</version>\r
+               <scope>compile</scope>\r
+               <exclusions>\r
+                     <exclusion> \r
+                       <groupId>org.slf4j</groupId>\r
+                       <artifactId>slf4j-log4j12</artifactId>\r
+                     </exclusion>\r
+                     <exclusion> \r
+                       <groupId>log4j</groupId>\r
+                       <artifactId>log4j</artifactId>\r
+                     </exclusion>\r
+                   </exclusions> \r
+               </dependency>\r
+               \r
+       </dependencies>\r
+       <build>\r
+               <plugins>\r
+                       <plugin>\r
+                               <groupId>org.apache.maven.plugins</groupId>\r
+                               <artifactId>maven-jarsigner-plugin</artifactId>\r
+                       </plugin>\r
+               \r
+               <plugin>\r
+                       <groupId>org.apache.maven.plugins</groupId>\r
+                       <artifactId>maven-javadoc-plugin</artifactId>\r
+                                       <configuration>\r
+                       <failOnError>false</failOnError>\r
+                       </configuration>\r
+                       <executions>\r
+                               <execution>\r
+                                       <id>attach-javadocs</id>\r
+                                       <goals>\r
+                                               <goal>jar</goal>\r
+                                       </goals>\r
+                               </execution>\r
+                       </executions>\r
+               </plugin> \r
+          \r
+          \r
+              <plugin>\r
+                     <groupId>org.apache.maven.plugins</groupId>\r
+                     <artifactId>maven-source-plugin</artifactId>\r
+                     <version>2.2.1</version>\r
+                     <executions>\r
+                       <execution>\r
+                         <id>attach-sources</id>\r
+                         <goals>\r
+                           <goal>jar-no-fork</goal>\r
+                         </goals>\r
+                       </execution>\r
+                     </executions>\r
+                   </plugin>\r
+\r
+                       \r
+               <plugin>\r
+                       <groupId>org.sonatype.plugins</groupId>\r
+                       <artifactId>nexus-staging-maven-plugin</artifactId>\r
+                       <version>1.6.7</version>\r
+                       <extensions>true</extensions>\r
+                       <configuration>\r
+                       <serverId>ossrhdme</serverId>\r
+                       <nexusUrl>https://oss.sonatype.org/</nexusUrl>\r
+                       <autoReleaseAfterClose>true</autoReleaseAfterClose>\r
+                       </configuration>\r
+               </plugin>\r
+               </plugins>\r
+       </build>        \r
+</project>\r
diff --git a/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticatedUser.java b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticatedUser.java
new file mode 100644 (file)
index 0000000..d720e28
--- /dev/null
@@ -0,0 +1,112 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cass;\r
+\r
+import java.security.Principal;\r
+\r
+import org.apache.cassandra.auth.AuthenticatedUser;\r
+\r
+import com.att.cadi.Access;\r
+\r
+public class AAFAuthenticatedUser extends AuthenticatedUser implements Principal {\r
+       private boolean anonymous = false, supr=false, local=false;\r
+       private String fullName;\r
+//     private Access access;\r
+\r
+       public AAFAuthenticatedUser(Access access, String name) {\r
+               super(name);\r
+//             this.access = access;\r
+           int endIndex = name.indexOf("@");\r
+           if(endIndex >= 0) {\r
+               fullName = name;\r
+           } else {\r
+               fullName = name + '@' + AAFBase.default_realm;\r
+           }\r
+       }\r
+       \r
+       public String getFullName() {\r
+               return fullName;\r
+       }\r
+       \r
+       public String getName() {\r
+               return fullName;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see org.apache.cassandra.auth.AuthenticatedUser#isAnonymous()\r
+        */\r
+       @Override\r
+       public boolean isAnonymous() {\r
+               return anonymous;\r
+       }\r
+\r
+       public void setAnonymous(boolean anon) {\r
+               anonymous = anon;\r
+       }\r
+\r
+       public boolean getAnonymous() {\r
+               return anonymous;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see org.apache.cassandra.auth.AuthenticatedUser#isSuper()\r
+        */\r
+       @Override\r
+       public boolean isSuper() {\r
+               return supr;\r
+       }\r
+\r
+       public void setSuper(boolean supr) {\r
+               this.supr = supr;\r
+       }\r
+\r
+       public boolean getSuper() {\r
+               return supr;\r
+       }\r
+\r
+       /**\r
+        * We check Local so we can compare with the right Lur.  This is AAF Plugin only.\r
+        * @return\r
+        */\r
+       public boolean isLocal() {\r
+               return local;\r
+       }\r
+       \r
+       public void setLocal(boolean val) {\r
+               local = val;\r
+       }\r
+\r
+       @Override\r
+         public boolean equals(Object o) {\r
+                 if (this == o) return true;\r
+             if (!(o instanceof AAFAuthenticatedUser)) return false;\r
+             return ((AuthenticatedUser)o).getName().equals(this.getName());\r
+         }\r
+\r
+         @Override\r
+         public int hashCode() {\r
+                 //access.log(Level.DEBUG, "AAFAuthentication hashcode ",getName().hashCode());\r
+             return getName().hashCode();\r
+         }  \r
+}\r
diff --git a/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticator.java b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticator.java
new file mode 100644 (file)
index 0000000..8228899
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cass;\r
+\r
+import java.io.IOException;\r
+import java.io.UnsupportedEncodingException;\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.apache.cassandra.auth.AuthenticatedUser;\r
+import org.apache.cassandra.auth.IAuthenticator;\r
+import org.apache.cassandra.auth.ISaslAwareAuthenticator;\r
+import org.apache.cassandra.exceptions.AuthenticationException;\r
+import org.apache.cassandra.exceptions.InvalidRequestException;\r
+import org.apache.cassandra.exceptions.RequestExecutionException;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CredVal.Type;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+\r
+public class AAFAuthenticator extends AAFBase implements ISaslAwareAuthenticator  {\r
+\r
+       public boolean requireAuthentication() {\r
+                return true;\r
+        }\r
+         \r
+         /**\r
+          * Invoked to authenticate an user\r
+          */\r
+         public AuthenticatedUser authenticate(Map<String, String> credentials) throws AuthenticationException {\r
+                   String username = (String)credentials.get("username");\r
+                   if (username == null) {\r
+                     throw new AuthenticationException("'username' is missing");\r
+                   }\r
+                   \r
+                   AAFAuthenticatedUser aau = new AAFAuthenticatedUser(access,username);\r
+                   String fullName=aau.getFullName();\r
+                   access.log(Level.DEBUG, "Authenticating", aau.getName(),"(", fullName,")");\r
+                   \r
+                   String password = (String)credentials.get("password");\r
+                   if (password == null) {\r
+                     throw new AuthenticationException("'password' is missing");\r
+                   } else if(password.startsWith("bsf:")) {\r
+                       try {\r
+                                       password = Symm.base64noSplit.depass(password);\r
+                               } catch (IOException e) {\r
+                                       throw new AuthenticationException("AAF bnf: Password cannot be decoded");\r
+                               }\r
+                       } else if(password.startsWith("enc:???")) {\r
+                               try {\r
+                                       password = access.decrypt(password, true);\r
+                               } catch (IOException e) {\r
+                                       throw new AuthenticationException("AAF Encrypted Password cannot be decrypted");\r
+                               }\r
+                   }\r
+                   \r
+                   if(localLur!=null) {\r
+                       access.log(Level.DEBUG, "Validating",fullName, "with LocalTaf", password); \r
+                       if(localLur.validate(fullName, Type.PASSWORD, password.getBytes())) {\r
+                                   aau.setAnonymous(true);\r
+                                   aau.setLocal(true);\r
+                                   access.log(Level.DEBUG, fullName, "is authenticated locally"); \r
+                               return aau;\r
+                       }\r
+                   }\r
+                   \r
+                   String aafResponse;\r
+                   try {\r
+                       access.log(Level.DEBUG, "Validating",fullName, "with AAF");//, password); \r
+                       aafResponse = aafAuthn.validate(fullName, password);\r
+                           if(aafResponse != null) { // Reason for failing.\r
+                               access.log(Level.AUDIT, "AAF reports ",fullName,":",aafResponse);\r
+                               throw new AuthenticationException(aafResponse);\r
+                           }\r
+                           access.log(Level.AUDIT, fullName, "is authenticated"); //,password);\r
+                           // This tells Cassandra to skip checking it's own tables for User Entries.\r
+                           aau.setAnonymous(true);\r
+                   } catch (AuthenticationException ex) {\r
+                       throw ex;\r
+                   } catch(Exception ex) {\r
+                       access.log(ex,"Exception validating user");                             \r
+                       throw new AuthenticationException("Exception validating user");\r
+                   }\r
+                   \r
+                   return aau; \r
+         }\r
+         \r
+         public void create(String username, Map<IAuthenticator.Option, Object> options) throws InvalidRequestException, RequestExecutionException {\r
+                 access.log(Level.INFO,"Use AAF CLI to create user");\r
+         }\r
+         \r
+         public void alter(String username, Map<IAuthenticator.Option, Object> options) throws RequestExecutionException {\r
+                 access.log(Level.INFO,"Use AAF CLI to alter user");\r
+         }\r
+         \r
+         public void drop(String username) throws RequestExecutionException {\r
+                 access.log(Level.INFO,"Use AAF CLI to delete user");\r
+         }\r
+         \r
+         public SaslAuthenticator newAuthenticator() {\r
+                 return new ISaslAwareAuthenticator.SaslAuthenticator() {\r
+                   private boolean complete = false;\r
+                   private Map<String, String> credentials;\r
+\r
+                   public byte[] evaluateResponse(byte[] clientResponse) throws AuthenticationException {\r
+                     this.credentials = decodeCredentials(clientResponse);\r
+                     this.complete = true;\r
+                     return null;\r
+                   }\r
+\r
+                   public boolean isComplete() {\r
+                     return this.complete;\r
+                   }\r
+\r
+                   public AuthenticatedUser getAuthenticatedUser() throws AuthenticationException {\r
+                     return AAFAuthenticator.this.authenticate(this.credentials);\r
+                   }\r
+\r
+                   private Map<String, String> decodeCredentials(byte[] bytes) throws AuthenticationException {\r
+                       access.log(Level.DEBUG,"Decoding credentials from client token");\r
+                     byte[] user = null;\r
+                     byte[] pass = null;\r
+                     int end = bytes.length;\r
+                     for (int i = bytes.length - 1; i >= 0; i--)\r
+                     {\r
+                       if (bytes[i] != 0)\r
+                         continue;\r
+                       if (pass == null)\r
+                         pass = Arrays.copyOfRange(bytes, i + 1, end);\r
+                       else if (user == null)\r
+                         user = Arrays.copyOfRange(bytes, i + 1, end);\r
+                       end = i;\r
+                     }\r
+\r
+                     if (user == null)\r
+                       throw new AuthenticationException("Authentication ID must not be null");\r
+                     if (pass == null) {\r
+                       throw new AuthenticationException("Password must not be null");\r
+                     }\r
+                     Map<String,String> credentials = new HashMap<String,String>();\r
+                     try {\r
+                         credentials.put(IAuthenticator.USERNAME_KEY, new String(user, Config.UTF_8));\r
+                         credentials.put(IAuthenticator.PASSWORD_KEY, new String(pass, Config.UTF_8));\r
+                               } catch (UnsupportedEncodingException e) {\r
+                                       throw new AuthenticationException(e.getMessage());\r
+                               }\r
+                     return credentials;\r
+                   }\r
+                 };      \r
+         }\r
+\r
+}\r
+\r
diff --git a/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthorizer.java b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthorizer.java
new file mode 100644 (file)
index 0000000..a923e9b
--- /dev/null
@@ -0,0 +1,228 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cass;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.apache.cassandra.auth.AuthenticatedUser;\r
+import org.apache.cassandra.auth.IAuthorizer;\r
+import org.apache.cassandra.auth.IResource;\r
+import org.apache.cassandra.auth.Permission;\r
+import org.apache.cassandra.auth.PermissionDetails;\r
+import org.apache.cassandra.exceptions.RequestExecutionException;\r
+import org.apache.cassandra.exceptions.RequestValidationException;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.aaf.v2_0.AbsAAFLur;\r
+import com.att.cadi.lur.LocalPermission;\r
+\r
+public class AAFAuthorizer extends AAFBase implements IAuthorizer {\r
+       // Returns every permission on the resource granted to the user.\r
+    public Set<Permission> authorize(AuthenticatedUser user, IResource resource) {\r
+       String uname, rname;\r
+       access.log(Level.DEBUG,"Authorizing",uname=user.getName(),"for",rname=resource.getName());\r
+\r
+       Set<Permission> permissions;\r
+\r
+       if(user instanceof AAFAuthenticatedUser) {\r
+               AAFAuthenticatedUser aafUser = (AAFAuthenticatedUser) user;\r
+                       aafUser.setAnonymous(false);\r
+                       \r
+                       if(aafUser.isLocal()) {\r
+                               permissions = checkPermissions(aafUser, new LocalPermission(\r
+                                       rname.replaceFirst("data", cluster_name)\r
+                               ));\r
+                       } else {\r
+                               permissions = checkPermissions(\r
+                                               aafUser,\r
+                                               perm_type,\r
+                                               ':'+rname.replaceFirst("data", cluster_name).replace('/', ':'));\r
+                       }\r
+       } else {\r
+               permissions = Permission.NONE;\r
+       }\r
+       \r
+       access.log(Level.INFO,"Permissions on",rname,"for",uname,':', permissions);\r
+\r
+        return permissions;\r
+    }\r
+    \r
+    /**\r
+     * Check only for Localized IDs (see cadi.properties)\r
+     * @param aau\r
+     * @param perm\r
+     * @return\r
+     */\r
+    private Set<Permission> checkPermissions(AAFAuthenticatedUser aau, LocalPermission perm) {\r
+       if(localLur.fish(aau.getFullName(), perm)) {\r
+//             aau.setSuper(true);\r
+               return Permission.ALL;\r
+       } else {\r
+               return Permission.NONE;\r
+       }\r
+    }\r
+    \r
+    /**\r
+     * Check remoted AAF Permissions\r
+     * @param aau\r
+     * @param type\r
+     * @param instance\r
+     * @return\r
+     */\r
+    private Set<Permission> checkPermissions(AAFAuthenticatedUser aau, String type, String instance) {\r
+               // Can perform ALL actions\r
+        String fullName = aau.getFullName();\r
+        PermHolder ph = new PermHolder(aau);\r
+        aafLur.fishOneOf(fullName, ph,type,instance,actions);\r
+        return ph.permissions;\r
+    }   \r
+\r
+    private class PermHolder {\r
+       private AAFAuthenticatedUser aau;\r
+               public PermHolder(AAFAuthenticatedUser aau) {\r
+               this.aau = aau;\r
+       }\r
+       public Set<Permission> permissions = Permission.NONE;\r
+               public void mutable() {\r
+                       if(permissions==Permission.NONE) {\r
+                               permissions = new HashSet<Permission>();\r
+                       }\r
+               }\r
+    };\r
\r
+   /**\r
+    * This specialty List avoid extra Object Creation, and allows the Lur to do a Vistor on all appropriate Perms\r
+    */\r
+   private static final ArrayList<AbsAAFLur.Action<PermHolder>> actions = new ArrayList<AbsAAFLur.Action<PermHolder>>();\r
+   static {\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "*";\r
+               }\r
+               \r
+               public boolean exec(PermHolder a) {\r
+               a.aau.setSuper(true);\r
+               a.permissions = Permission.ALL;\r
+                       return true;\r
+               }\r
+          });\r
+          \r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "SELECT";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.SELECT);\r
+                       return false;\r
+               }\r
+          });\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "MODIFY";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.MODIFY);\r
+                       return false;\r
+               }\r
+          });\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "CREATE";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.CREATE);\r
+                       return false;\r
+               }\r
+          });\r
+\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "ALTER";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.ALTER);\r
+                       return false;\r
+               }\r
+          });\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "DROP";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.DROP);\r
+                       return false;\r
+               }\r
+          });\r
+          actions.add(new AbsAAFLur.Action<PermHolder>() {\r
+               public String getName() {\r
+                       return "AUTHORIZE";\r
+               }\r
+               \r
+               public boolean exec(PermHolder ph) {\r
+                       ph.mutable();\r
+               ph.permissions.add(Permission.AUTHORIZE);\r
+                       return false;\r
+               }\r
+          });\r
+\r
+\r
+   }; \r
+   \r
+   \r
+    public void grant(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String to) throws RequestExecutionException {\r
+       access.log(Level.INFO, "Use AAF CLI to grant permission(s) to user/role");\r
+    }\r
+\r
+    public void revoke(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String from) throws RequestExecutionException {\r
+       access.log(Level.INFO,"Use AAF CLI to revoke permission(s) for user/role");\r
+    }\r
+\r
+    public Set<PermissionDetails> list(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String of) throws RequestValidationException, RequestExecutionException {\r
+       access.log(Level.INFO,"Use AAF CLI to find the list of permissions");\r
+       return null;\r
+    }\r
+\r
+    // Called prior to deleting the user with DROP USER query. Internal hook, so no permission checks are needed here.\r
+    public void revokeAll(String droppedUser) {\r
+       access.log(Level.INFO,"Use AAF CLI to revoke permission(s) for user/role");\r
+    }\r
+\r
+    // Called after a resource is removed (DROP KEYSPACE, DROP TABLE, etc.).\r
+    public void revokeAll(IResource droppedResource) {\r
+       access.log(Level.INFO,"Use AAF CLI to delete the unused permission", droppedResource.getName());\r
+    }\r
+\r
+}\r
diff --git a/cass/src/main/java/com/att/cadi/aaf/cass/AAFBase.java b/cass/src/main/java/com/att/cadi/aaf/cass/AAFBase.java
new file mode 100644 (file)
index 0000000..32690f4
--- /dev/null
@@ -0,0 +1,193 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cass;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.InputStream;\r
+import java.net.URL;\r
+import java.util.HashSet;\r
+import java.util.Properties;\r
+import java.util.Set;\r
+\r
+import org.apache.cassandra.auth.DataResource;\r
+import org.apache.cassandra.auth.IAuthenticator;\r
+import org.apache.cassandra.config.DatabaseDescriptor;\r
+import org.apache.cassandra.exceptions.ConfigurationException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.SLF4JAccess;\r
+import com.att.cadi.aaf.v2_0.AAFAuthn;\r
+import com.att.cadi.aaf.v2_0.AAFCon;\r
+import com.att.cadi.aaf.v2_0.AbsAAFLur;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.lur.LocalLur;\r
+import com.att.cadi.aaf.AAFPermission;\r
+\r
+public abstract class AAFBase {\r
+       protected static final Set<IAuthenticator.Option> options;\r
+       protected static final Set<DataResource> dataResource;\r
+\r
+       static {\r
+               options = new HashSet<IAuthenticator.Option>();\r
+               options.add(IAuthenticator.Option.PASSWORD);\r
+               \r
+               dataResource = new HashSet<DataResource>();\r
+               dataResource.add(DataResource.columnFamily("system_auth", "credentials"));\r
+       }\r
+       \r
+       protected static Access access;\r
+       protected static LocalLur localLur;\r
+       protected static AAFCon<?> aafcon;\r
+       protected static AAFAuthn<?> aafAuthn;\r
+       protected static AbsAAFLur<AAFPermission> aafLur;\r
+       protected static String default_realm;\r
+    protected static String cluster_name;\r
+    protected static String perm_type;\r
+       private static boolean props_ok = false;\r
+       \r
+       /**\r
+        * If you use your own Access Class, this must be called before \r
+        * "setup()" is invoked by Cassandra.\r
+        * \r
+        * Otherwise, it will default to reading Properties CADI style.\r
+        * \r
+        * @param access\r
+        */\r
+       public static void setAccess(Access access) {\r
+               AAFBase.access = access;\r
+       }\r
+\r
+       \r
+    public void validateConfiguration() throws ConfigurationException {\r
+       setup();\r
+       if(!props_ok)  {\r
+               throw new ConfigurationException("AAF not initialized");\r
+       }\r
+    }\r
+    \r
+       @SuppressWarnings("unchecked")\r
+       public synchronized void setup() {\r
+               if(aafAuthn == null) {\r
+                       try {\r
+                               if(access==null) {\r
+                                       String value = System.getProperty(Config.CADI_PROP_FILES, "cadi.properties");\r
+                                       Properties initial = new Properties();\r
+                                       URL cadi_props = ClassLoader.getSystemResource(value);\r
+                                       if(cadi_props == null) {\r
+                                               File cp = new File(value);\r
+                                               if(cp.exists()) {\r
+                                                       InputStream is = new FileInputStream(cp);\r
+                                                       try {\r
+                                                               initial.load(is);\r
+                                                       } finally {\r
+                                                               is.close();\r
+                                                       }\r
+                                               } else {\r
+                                                       System.out.printf("%s does not exist as File or in Classpath\n",value);\r
+                                                       initial.setProperty(Config.CADI_PROP_FILES, value);\r
+                                               }\r
+                                       } else {\r
+                                               InputStream is = cadi_props.openStream();\r
+                                               try {\r
+                                                       initial.load(is);\r
+                                               } finally {\r
+                                                       is.close();\r
+                                               }\r
+                                       }\r
+                                       access = new SLF4JAccess(initial);\r
+                               }\r
+                               props_ok = true;\r
+                               if((perm_type = Config.logProp(access, "cass_group_name",null))==null) {\r
+                                       props_ok=false;\r
+                               } else {\r
+                                       perm_type = perm_type + ".cass";\r
+                               }\r
+                               \r
+                               if((cluster_name = Config.logProp(access,"cass_cluster_name",null))==null) {\r
+                                       if((cluster_name = DatabaseDescriptor.getClusterName())==null) {\r
+                                               props_ok=false;\r
+                                       }\r
+                               }\r
+\r
+                               if((default_realm = Config.logProp(access, Config.AAF_DEFAULT_REALM, null))==null) {\r
+                                       props_ok=false;\r
+                               }\r
+                               \r
+                               if(props_ok==false) {\r
+                                       return;\r
+                               }\r
+\r
+                               // AAFLur has pool of DME clients as needed, and Caches Client lookups\r
+                               Lur lur = Config.configLur(access);\r
+                               // Loop through to find AAFLur out of possible Lurs, to reuse AAFCon\r
+                               if(lur instanceof EpiLur) {\r
+                                       EpiLur elur = (EpiLur)lur;\r
+                                       for(int i=0; (lur = elur.get(i))!=null;++i) {\r
+                                               if(lur instanceof AbsAAFLur) {\r
+                                                       aafLur=(AbsAAFLur<AAFPermission>)lur;\r
+                                                       aafcon = aafLur.aaf;\r
+                                                       aafAuthn = aafLur.aaf.newAuthn(aafLur);\r
+                                                       break;\r
+                                               } else if(lur instanceof LocalLur) {\r
+                                                       localLur = (LocalLur)lur;\r
+                                               }\r
+                                       }\r
+                               } else if(lur instanceof AbsAAFLur) {\r
+                                       aafLur=(AbsAAFLur<AAFPermission>)lur;\r
+                                       aafcon = aafLur.aaf;\r
+                                       aafAuthn = aafLur.aaf.newAuthn(aafLur);\r
+                               }\r
+                               if(aafAuthn==null) {\r
+                                       access.log(Level.INIT,"Failed to instantiate full AAF access");\r
+                                       props_ok = false;\r
+                               }\r
+                       } catch (Exception e) {\r
+                               aafAuthn=null;\r
+                               if(access!=null)access.log(e, "Failed to initialize AAF");\r
+                               props_ok = false;\r
+                       }\r
+               }               \r
+       }\r
+\r
+       public Set<DataResource> protectedResources() {\r
+               access.log(Level.DEBUG, "Data Resource asked for: it's",dataResource.isEmpty()?"":"not","empty");\r
+               return dataResource;\r
+       }\r
+       \r
+       public Set<IAuthenticator.Option> supportedOptions() {\r
+               access.log(Level.DEBUG, "supportedOptions() called");\r
+               return options;\r
+       }\r
+         \r
+       public Set<IAuthenticator.Option> alterableOptions() {\r
+               access.log(Level.DEBUG, "alterableOptions() called");\r
+               return options;\r
+       }\r
+\r
+\r
+}\r
diff --git a/cass/src/test/java/com/att/aaf/cass/JU_CASS.java b/cass/src/test/java/com/att/aaf/cass/JU_CASS.java
new file mode 100644 (file)
index 0000000..f25a6b5
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.aaf.cass;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.apache.cassandra.auth.AuthenticatedUser;\r
+import org.apache.cassandra.auth.IResource;\r
+import org.apache.cassandra.auth.Permission;\r
+import org.junit.AfterClass;\r
+import org.junit.Assert;\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.aaf.cass.AAFAuthenticator;\r
+import com.att.cadi.aaf.cass.AAFAuthorizer;\r
+\r
+public class JU_CASS {\r
+\r
+       private static AAFAuthenticator aa;\r
+       private static AAFAuthorizer an;\r
+\r
+       @BeforeClass\r
+       public static void setUpBeforeClass() throws Exception {\r
+               System.setProperty("cadi_prop_files", "etc/cadi.properties");\r
+               \r
+               aa = new AAFAuthenticator();\r
+               an = new AAFAuthorizer();\r
+\r
+               aa.setup();\r
+               an.setup(); // does nothing after aa.\r
+               \r
+               aa.validateConfiguration();\r
+               \r
+       }\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() throws Exception {\r
+                       Map<String,String> creds = new HashMap<String,String>();\r
+                       creds.put("username", "XXX@NS");\r
+                       creds.put("password", "enc:???");\r
+                       AuthenticatedUser aaf = aa.authenticate(creds);\r
+\r
+                       // Test out "aaf_default_domain\r
+                       creds.put("username", "XX");\r
+                       aaf = aa.authenticate(creds);\r
+                       \r
+                       IResource resource = new IResource() {\r
+                               public String getName() {\r
+                                       return "data/authz";\r
+                               }\r
+\r
+                               public IResource getParent() {\r
+                                       return null;\r
+                               }\r
+\r
+                               public boolean hasParent() {\r
+                                       return false;\r
+                               }\r
+\r
+                               public boolean exists() {\r
+                                       return true;\r
+                               }\r
+                               \r
+                       };\r
+                       \r
+                       Set<Permission> perms = an.authorize(aaf, resource);\r
+                       \r
+                       // Test out "AAF" access\r
+                       creds.put("username", "XXX@NS");\r
+                       creds.put("password", "enc:???");\r
+                       aaf = aa.authenticate(creds);\r
+                       perms = an.authorize(aaf, resource);\r
+                       Assert.assertFalse(perms.isEmpty());\r
+\r
+                       perms = an.authorize(aaf, resource);\r
+                       Assert.assertFalse(perms.isEmpty());\r
+                       \r
+       }\r
+\r
+}\r
diff --git a/cass/src/test/java/com/att/cadi/aaf/cass/test/JU_CASS.java b/cass/src/test/java/com/att/cadi/aaf/cass/test/JU_CASS.java
new file mode 100644 (file)
index 0000000..9bfc17e
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.aaf.cass.test;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.apache.cassandra.auth.AuthenticatedUser;\r
+import org.apache.cassandra.auth.IResource;\r
+import org.apache.cassandra.auth.Permission;\r
+import org.junit.AfterClass;\r
+import org.junit.Assert;\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.aaf.cass.AAFAuthenticator;\r
+import com.att.cadi.aaf.cass.AAFAuthorizer;\r
+\r
+public class JU_CASS {\r
+\r
+       private static AAFAuthenticator aa;\r
+       private static AAFAuthorizer an;\r
+\r
+       @BeforeClass\r
+       public static void setUpBeforeClass() throws Exception {\r
+               System.setProperty("cadi_prop_files", "etc/cadi.properties");\r
+               \r
+               aa = new AAFAuthenticator();\r
+               an = new AAFAuthorizer();\r
+\r
+               aa.setup();\r
+               an.setup(); // does nothing after aa.\r
+               \r
+               aa.validateConfiguration();\r
+               \r
+       }\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() throws Exception {\r
+                       Map<String,String> creds = new HashMap<String,String>();\r
+                       creds.put("username", "XXX@NS");\r
+                       creds.put("password", "enc:???");\r
+                       AuthenticatedUser aaf = aa.authenticate(creds);\r
+\r
+                       // Test out "aaf_default_domain\r
+                       creds.put("username", "XX");\r
+                       aaf = aa.authenticate(creds);\r
+                       \r
+                       IResource resource = new IResource() {\r
+                               public String getName() {\r
+                                       return "data/authz";\r
+                               }\r
+\r
+                               public IResource getParent() {\r
+                                       return null;\r
+                               }\r
+\r
+                               public boolean hasParent() {\r
+                                       return false;\r
+                               }\r
+\r
+                               public boolean exists() {\r
+                                       return true;\r
+                               }\r
+                               \r
+                       };\r
+                       \r
+                       Set<Permission> perms = an.authorize(aaf, resource);\r
+                       \r
+                       // Test out "AAF" access\r
+                       creds.put("username", "XXX@NS");\r
+                       creds.put("password", "enc:???");\r
+                       aaf = aa.authenticate(creds);\r
+                       perms = an.authorize(aaf, resource);\r
+                       Assert.assertFalse(perms.isEmpty());\r
+\r
+                       perms = an.authorize(aaf, resource);\r
+                       Assert.assertFalse(perms.isEmpty());\r
+                       \r
+       }\r
+\r
+}\r
diff --git a/client/.gitignore b/client/.gitignore
new file mode 100644 (file)
index 0000000..cf85207
--- /dev/null
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/client/pom.xml b/client/pom.xml
new file mode 100644 (file)
index 0000000..562a92a
--- /dev/null
@@ -0,0 +1,108 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<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">\r
+<parent>\r
+               <groupId>com.att.cadi</groupId>\r
+               <artifactId>parent</artifactId>\r
+               <version>1.3.2</version>\r
+               <relativePath>..</relativePath>\r
+       </parent>\r
+       \r
+       <name>CADI Client</name>\r
+       <artifactId>cadi-client</artifactId>\r
+       <packaging>jar</packaging>\r
+       <url>https://github.com/att/AAF</url>\r
+       <description>CADI</description>\r
+       <modelVersion>4.0.0</modelVersion>\r
+\r
+       <dependencies>\r
+               <dependency>\r
+                       <groupId>com.att.inno</groupId>\r
+                       <artifactId>rosetta</artifactId>\r
+               </dependency>\r
+               <dependency>\r
+                       <groupId>com.att.cadi</groupId>\r
+                       <artifactId>cadi-core</artifactId>\r
+               </dependency>\r
+               <dependency>\r
+                       <groupId>com.att.aft</groupId>\r
+                       <artifactId>dme2</artifactId>\r
+                       <scope>compile</scope>\r
+               </dependency>\r
+               \r
+       </dependencies>\r
+\r
+       <build>\r
+               <plugins>\r
+                       <plugin>\r
+                               <groupId>org.apache.maven.plugins</groupId>\r
+                               <artifactId>maven-jarsigner-plugin</artifactId>\r
+                       </plugin>\r
+                                               <plugin>\r
+                       <groupId>org.apache.maven.plugins</groupId>\r
+                       <artifactId>maven-javadoc-plugin</artifactId>\r
+                                       <configuration>\r
+                       <failOnError>false</failOnError>\r
+                       </configuration>\r
+                       <executions>\r
+                               <execution>\r
+                                       <id>attach-javadocs</id>\r
+                                       <goals>\r
+                                               <goal>jar</goal>\r
+                                       </goals>\r
+                               </execution>\r
+                       </executions>\r
+               </plugin> \r
+          \r
+          \r
+              <plugin>\r
+                     <groupId>org.apache.maven.plugins</groupId>\r
+                     <artifactId>maven-source-plugin</artifactId>\r
+                     <version>2.2.1</version>\r
+                     <executions>\r
+                       <execution>\r
+                         <id>attach-sources</id>\r
+                         <goals>\r
+                           <goal>jar-no-fork</goal>\r
+                         </goals>\r
+                       </execution>\r
+                     </executions>\r
+                   </plugin>\r
+       \r
\r
+               <plugin>\r
+                       <groupId>org.sonatype.plugins</groupId>\r
+                       <artifactId>nexus-staging-maven-plugin</artifactId>\r
+                       <version>1.6.7</version>\r
+                       <extensions>true</extensions>\r
+                       <configuration>\r
+                       <serverId>ossrhdme</serverId>\r
+                       <nexusUrl>https://oss.sonatype.org/</nexusUrl>\r
+                       <autoReleaseAfterClose>true</autoReleaseAfterClose>\r
+                       </configuration>\r
+               </plugin>\r
+               </plugins>\r
+       </build>\r
+       \r
+</project>\r
diff --git a/client/src/main/java/com/att/cadi/client/AAFClient.java b/client/src/main/java/com/att/cadi/client/AAFClient.java
new file mode 100644 (file)
index 0000000..843f3b1
--- /dev/null
@@ -0,0 +1,199 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.net.HttpURLConnection;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.http.HMangr;\r
+import com.att.cadi.locator.DME2Locator;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+import com.att.rosetta.env.RosettaEnv;\r
+\r
+public class AAFClient {\r
+       private RosettaEnv env;\r
+       private Map<Class<?>,RosettaDF<?>> map = new HashMap<Class<?>,RosettaDF<?>>();\r
+       HMangr hman;\r
+       HBasicAuthSS ss;\r
+\r
+       public AAFClient(RosettaEnv env) throws Exception {\r
+               this.env = env;\r
+               Access access = new EnvAccess(env);\r
+               String user = access.getProperty(Config.AAF_MECHID,null);\r
+               String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);\r
+               \r
+               SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);\r
+               DME2Manager dm = new DME2Manager("APIclient DME2Manager", System.getProperties());\r
+               DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));\r
+\r
+               int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));\r
+\r
+               hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");\r
+               ss = new HBasicAuthSS(user, password, si);\r
+       }\r
+\r
+       public AAFClient(RosettaEnv env, DME2Manager dm) throws Exception {\r
+               this.env = env;\r
+               Access access = new EnvAccess(env);\r
+               String user = access.getProperty(Config.AAF_MECHID,null);\r
+               String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);\r
+               \r
+               SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);\r
+               DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));\r
+\r
+               int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));\r
+\r
+               hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");\r
+               ss = new HBasicAuthSS(user, password, si);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private synchronized<T> RosettaDF<T> getDF(Class<T> cls) throws APIException {\r
+               RosettaDF<?> rdf;\r
+               synchronized (env) {\r
+                       rdf = map.get(cls);\r
+                       if(rdf==null) {\r
+                               rdf = env.newDataFactory(cls);\r
+                               map.put(cls, rdf);\r
+                       }\r
+               }\r
+               return (RosettaDF<T>)rdf;\r
+       }\r
+\r
+       // Package on purpose\r
+       static class Call<T> {\r
+               protected final static String VOID_CONTENT_TYPE="application/Void+json;version=2.0";\r
+               \r
+               protected RosettaDF<T> df;\r
+               protected AAFClient client;\r
+\r
+               public Call(AAFClient ac, RosettaDF<T> df) {\r
+                       this.client = ac;\r
+                       this.df = df;\r
+               }\r
+       }\r
+       \r
+\r
+       ///////////  Calls /////////////////\r
+       /**\r
+        * Returns a Get Object... same as "get"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Get<T> read(Class<T> cls) throws APIException {\r
+               return new Get<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Get Object... same as "read"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Get<T> get(Class<T> cls) throws APIException {\r
+               return new Get<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Post Object... same as "create"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Post<T> post(Class<T> cls) throws APIException {\r
+               return new Post<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Post Object... same as "post"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Post<T> create(Class<T> cls) throws APIException {\r
+               return new Post<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Put Object... same as "update"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Put<T> put(Class<T> cls) throws APIException {\r
+               return new Put<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Put Object... same as "put"\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Put<T> update(Class<T> cls) throws APIException {\r
+               return new Put<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Delete Object\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public<T> Delete<T> delete(Class<T> cls) throws APIException {\r
+               return new Delete<T>(this,getDF(cls));\r
+       }\r
+\r
+       /**\r
+        * Returns a Delete Object\r
+        * \r
+        * @param cls\r
+        * @return\r
+        * @throws APIException\r
+        */\r
+       public Delete<Void> delete() throws APIException {\r
+               return new Delete<Void>(this,null);\r
+       }\r
+\r
+       public Put<Void> put() {\r
+               return new Put<Void>(this,null);        \r
+       }\r
+       \r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java b/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java
new file mode 100644 (file)
index 0000000..ef8abf4
--- /dev/null
@@ -0,0 +1,94 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.io.IOException;\r
+\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.SecurityInfoC;\r
+\r
+public abstract class AbsBasicAuth<CLIENT> implements SecuritySetter<CLIENT> {\r
+               protected static final String REPEAT_OFFENDER="This call is aborted because of repeated usage of invalid Passwords";\r
+               private static final int MAX_TEMP_COUNT = 10;\r
+               private static final int MAX_SPAM_COUNT = 10000;\r
+               private static final long WAIT_TIME = 1000*60*4;\r
+               \r
+               protected final String headValue;\r
+               protected SecurityInfoC<CLIENT> securityInfo;\r
+               protected String user;\r
+               private long lastMiss;\r
+               private int count;\r
+\r
+               public AbsBasicAuth(String user, String pass, SecurityInfoC<CLIENT> si) throws IOException {\r
+                       this.user = user;\r
+                       headValue = "Basic " + Symm.base64.encode(user + ':' + pass);\r
+                       securityInfo = si;\r
+                       lastMiss=0L;\r
+                       count=0;\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see com.att.cadi.SecuritySetter#getID()\r
+                */\r
+               @Override\r
+               public String getID() {\r
+                       return user;\r
+               }\r
+               \r
+               public boolean isDenied() {\r
+                       if(lastMiss>0 && lastMiss>System.currentTimeMillis()) {\r
+                               return true;\r
+                       } else {\r
+                               lastMiss=0L;\r
+                               return false;\r
+                       }\r
+               }\r
+               \r
+               public synchronized int setLastResponse(int httpcode) {\r
+                       if(httpcode == 401) {\r
+                               ++count;\r
+                               if(lastMiss==0L && count>MAX_TEMP_COUNT) {\r
+                                       lastMiss=System.currentTimeMillis()+WAIT_TIME;\r
+                               }\r
+//                             if(count>MAX_SPAM_COUNT) {\r
+//                                     System.err.printf("Your service has %d consecutive bad service logins to AAF. \nIt will now exit\n",\r
+//                                                     count);\r
+//                                     System.exit(401);\r
+//                             }\r
+                               if(count%1000==0) {\r
+                                       System.err.printf("Your service has %d consecutive bad service logins to AAF. AAF Access will be disabled after %d\n",\r
+                                               count,MAX_SPAM_COUNT);\r
+                               }\r
+\r
+                       } else {\r
+                               lastMiss=0;\r
+                       }\r
+                       return count;\r
+               }\r
+               \r
+               public int count() {\r
+                       return count;\r
+               }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/AbsTransferSS.java b/client/src/main/java/com/att/cadi/client/AbsTransferSS.java
new file mode 100644 (file)
index 0000000..3056187
--- /dev/null
@@ -0,0 +1,74 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.TGuardPrincipal;\r
+import com.att.cadi.principal.TrustPrincipal;\r
+\r
+public abstract class AbsTransferSS<CLIENT> implements SecuritySetter<CLIENT> {\r
+       protected String value;\r
+       protected SecurityInfoC<CLIENT> securityInfo;\r
+       protected SecuritySetter<CLIENT> defSS;\r
+       private Principal principal;\r
+\r
+       //Format:<ID>:<APP>:<protocol>[:AS][,<ID>:<APP>:<protocol>]*\r
+       public AbsTransferSS(Principal principal, String app) {\r
+               init(principal, app);\r
+       }\r
+\r
+       public AbsTransferSS(Principal principal, String app, SecurityInfoC<CLIENT> si) {\r
+               init(principal,app);\r
+               securityInfo = si;\r
+               this.defSS = si.defSS;\r
+       }\r
+\r
+       private void init(Principal principal, String app)  {\r
+               this.principal=principal;\r
+               if(principal==null) {\r
+                       return;\r
+               } else if(principal instanceof BasicPrincipal) {\r
+                       value = principal.getName() + ':' + app + ":BasicAuth:AS";\r
+               } else if(principal instanceof TrustPrincipal) {\r
+                       TrustPrincipal tp = (TrustPrincipal)principal;\r
+                       // recursive\r
+                       init(tp.original(),app);\r
+                       value += principal.getName() + ':' + app + ":Trust:AS" + ',' + tp.userChain();\r
+               } else if(principal instanceof TGuardPrincipal) {\r
+                       value = principal.getName() + ':' + app + ":TGUARD:AS";\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.SecuritySetter#getID()\r
+        */\r
+       @Override\r
+       public String getID() {\r
+               return principal==null?"":principal.getName();\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Delete.java b/client/src/main/java/com/att/cadi/client/Delete.java
new file mode 100644 (file)
index 0000000..9367d4d
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public class Delete<T> extends AAFClient.Call<T> {\r
+       public Delete(AAFClient ac, RosettaDF<T> df) {\r
+               super(ac,df);\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public Result<T> delete(final String pathInfo, final T t) throws Exception {\r
+               if(t==null) {\r
+                       return (Result<T>)delete(pathInfo);\r
+               }\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<T>>() {\r
+                               @Override\r
+                               public Result<T> code(Rcli<?> client) throws APIException, CadiException {\r
+                                       Future<T> ft = client.delete(pathInfo,df,t); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+\r
+       public Result<Void> delete(final String pathInfo) throws Exception {\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<Void>>() {\r
+                               @Override\r
+                               public Result<Void> code(Rcli<?> client) throws APIException, CadiException {\r
+                                       Future<Void> ft = client.delete(pathInfo,VOID_CONTENT_TYPE); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+\r
+\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/EClient.java b/client/src/main/java/com/att/cadi/client/EClient.java
new file mode 100644 (file)
index 0000000..f508029
--- /dev/null
@@ -0,0 +1,53 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+\r
+public interface EClient<CT> {\r
+       public void setMethod(String meth);\r
+       public void setPathInfo(String pathinfo);\r
+       public void setPayload(Transfer transfer);\r
+       public void addHeader(String tag, String value);\r
+       public void setQueryParams(String q);\r
+       public void setFragment(String f);\r
+       public void send() throws APIException;\r
+       public<T> Future<T> futureCreate(Class<T> t);\r
+       public Future<String> futureReadString();\r
+       public<T> Future<T> futureRead(RosettaDF<T> df,Data.TYPE type);\r
+       public<T> Future<T> future(T t);\r
+       public Future<Void> future(HttpServletResponse resp, int expected) throws APIException;\r
+       \r
+       public interface Transfer {\r
+               public void transfer(OutputStream os) throws IOException, APIException;\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/EnvAccess.java b/client/src/main/java/com/att/cadi/client/EnvAccess.java
new file mode 100644 (file)
index 0000000..f331c9a
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+import com.att.inno.env.Decryptor;\r
+import com.att.inno.env.Env;\r
+import com.att.inno.env.impl.BasicEnv;\r
+\r
+public class EnvAccess implements Access {\r
+       private Env env;\r
+\r
+       /**\r
+        * String Property tag for files/resources that may contain properties.  Can be null.\r
+        * Resources of ClassLoader will be checked first, if exist. Can be null.\r
+        * @param env\r
+        * @param tag\r
+        * @param cl\r
+        * @throws IOException\r
+        */\r
+       public EnvAccess(BasicEnv env, ClassLoader cl) throws IOException {\r
+               this.env = env;\r
+               final Symm s = Symm.obtain(this);\r
+               env.set(new Decryptor() {\r
+                               private Symm symm = s;\r
+                               @Override\r
+                               public String decrypt(String encrypted) {\r
+                                       try {\r
+                                               return (encrypted!=null && (encrypted.startsWith(Symm.ENC)))\r
+                                                               ? symm.depass(encrypted)\r
+                                                               : encrypted;\r
+                                       } catch (IOException e) {\r
+                                               return "";\r
+                                       }\r
+                               }\r
+                       }\r
+               );\r
+       }\r
+\r
+       \r
+       /**\r
+        * Construct with the Classloader of Env and CADI_PROP_FILES, if possible\r
+        * \r
+        * @param env\r
+        * @throws IOException\r
+        */\r
+       public EnvAccess(BasicEnv env) throws IOException {\r
+               this(env, env.getClass().getClassLoader());\r
+       }\r
+       \r
+       @Override\r
+       public void log(Level level, Object... elements) {\r
+               switch(level) {\r
+                       case AUDIT:\r
+                               env.audit().log(elements);\r
+                               break;\r
+                       case DEBUG:\r
+                               env.debug().log(elements);\r
+                               break;\r
+                       case ERROR:\r
+                               env.error().log(elements);\r
+                               break;\r
+                       case INFO:\r
+                               env.info().log(elements);\r
+                               break;\r
+                       case INIT:\r
+                               env.init().log(elements);\r
+                               break;\r
+                       case WARN:\r
+                               env.warn().log(elements);\r
+                               break;\r
+                       default:\r
+                               break;\r
+               }\r
+               \r
+       }\r
+\r
+       @Override\r
+       public void log(Exception e, Object... elements) {\r
+               env.error().log(e,elements);\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object... elements) {\r
+               if(willLog(level)) {\r
+                       log(level,String.format(fmt, elements));\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               switch(level) {\r
+                       case AUDIT:\r
+                               return env.audit().isLoggable();\r
+                       case DEBUG:\r
+                               return env.debug().isLoggable();\r
+                       case ERROR:\r
+                               return env.error().isLoggable();\r
+                       case INFO:\r
+                               return env.info().isLoggable();\r
+                       case INIT:\r
+                               return env.init().isLoggable();\r
+                       case WARN:\r
+                               return env.warn().isLoggable();\r
+                       default:\r
+                               return false;\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public void setLogLevel(Level level) {\r
+               // unused\r
+       }\r
+\r
+       @Override\r
+       public ClassLoader classLoader() {\r
+               return env.getClass().getClassLoader();\r
+       }\r
+\r
+       @Override\r
+       public String getProperty(String string, String def) {\r
+               return env.getProperty(string, def);\r
+       }\r
+       \r
+       @Override\r
+       public void load(InputStream is) throws IOException {\r
+               Properties props = new Properties();\r
+               props.load(is);\r
+               for(Entry<Object, Object> es :props.entrySet()) {\r
+                       env.setProperty(es.getKey().toString(), es.getValue().toString());\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return env.decryptor().decrypt(encrypted);\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Future.java b/client/src/main/java/com/att/cadi/client/Future.java
new file mode 100644 (file)
index 0000000..1752907
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import com.att.cadi.CadiException;\r
+\r
+public abstract class Future<T> {\r
+       public T value;\r
+       public abstract boolean get(int timeout) throws CadiException;\r
+       \r
+       public abstract int code();\r
+       public abstract String body();\r
+       public abstract String header(String tag);\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Get.java b/client/src/main/java/com/att/cadi/client/Get.java
new file mode 100644 (file)
index 0000000..d05654d
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public class Get<T> extends AAFClient.Call<T> {\r
+       public Get(AAFClient ac, RosettaDF<T> df) {\r
+               super(ac,df);\r
+       }\r
+       \r
+       public Result<T> read(final String pathInfo) throws Exception {\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<T>>() {\r
+                               @Override\r
+                               public Result<T> code(Rcli<?> client) throws APIException, CadiException {\r
+                                       Future<T> ft = client.read(pathInfo,df); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Holder.java b/client/src/main/java/com/att/cadi/client/Holder.java
new file mode 100644 (file)
index 0000000..93067f9
--- /dev/null
@@ -0,0 +1,45 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+/**\r
+ * Use to set Variables outside of Anonymous classes.\r
+ *\r
+ *\r
+ * @param <T>\r
+ */\r
+public class Holder<T> {\r
+       private T value;\r
+       public Holder(T t) {\r
+               value = t;\r
+       }\r
+       public void set(T t) {\r
+               value = t;\r
+       }\r
+       \r
+       public T get() {\r
+               return value;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Post.java b/client/src/main/java/com/att/cadi/client/Post.java
new file mode 100644 (file)
index 0000000..7cc1b8c
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.LocatorException;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public class Post<T> extends AAFClient.Call<T> {\r
+       public Post(AAFClient ac, RosettaDF<T> df) {\r
+               super(ac,df);\r
+       }\r
+       \r
+       public Result<T> create(final String pathInfo, final T t) throws APIException, CadiException, LocatorException {\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<T>>() {\r
+                               @Override\r
+                               public Result<T> code(Rcli<?> client) throws  APIException, CadiException {\r
+                                       Future<T> ft = client.create(pathInfo,df,t); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/PropertyLocator.java b/client/src/main/java/com/att/cadi/client/PropertyLocator.java
new file mode 100644 (file)
index 0000000..37bc7b6
--- /dev/null
@@ -0,0 +1,144 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.Random;\r
+\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+\r
+public class PropertyLocator implements Locator {\r
+       private final URI [] orig;\r
+       private PLItem[] current;\r
+       private int end;\r
+       private final Random random;\r
+       \r
+       /**\r
+        * comma delimited root url list\r
+        * \r
+        * @param locList\r
+        * @throws LocatorException\r
+        */\r
+       public PropertyLocator(String locList) throws LocatorException {\r
+               if(locList==null)throw new LocatorException("No Location List given for PropertyLocator");\r
+               String[] locarray = locList.split("\\s*,\\s*");\r
+               orig = new URI[locarray.length];\r
+               \r
+               random = new Random();\r
+               \r
+               for(int i=0;i<locarray.length;++i) {\r
+                       try {\r
+                               orig[i] = new URI(locarray[i]);\r
+                       } catch (URISyntaxException e) {\r
+                               throw new LocatorException(e);\r
+                       }\r
+               }\r
+\r
+               current = new PLItem[orig.length];\r
+               refresh();\r
+       }\r
+\r
+       @Override\r
+       public URI get(Item item) throws LocatorException {\r
+               return orig[((PLItem)item).idx];\r
+       }\r
+\r
+       @Override\r
+       public Item first() throws LocatorException {\r
+               return end>0?current[0]:null;\r
+       }\r
+\r
+       @Override\r
+       public boolean hasItems() {\r
+               return end>0;\r
+       }\r
+\r
+       @Override\r
+       public Item next(Item item) throws LocatorException {\r
+               int spot;\r
+               if((spot=(((PLItem)item).order+1))>=end)return null;\r
+               return current[spot];\r
+       }\r
+\r
+       @Override\r
+       public synchronized void invalidate(Item item) throws LocatorException {\r
+               if(--end<=0)return;\r
+               PLItem pli = (PLItem)item;\r
+               int i,order;\r
+               for(i=0;i<end;++i) {\r
+                       if(pli==current[i])break;\r
+               }\r
+               order = current[i].order;\r
+               for(;i<end;++i) {\r
+                       current[i]=current[i+1];\r
+                       current[i].order=order++;\r
+               }\r
+               current[end]=pli;\r
+       }\r
+\r
+       @Override\r
+       public Item best() throws LocatorException {\r
+               switch(current.length) {\r
+                       case 0:\r
+                               return null;\r
+                       case 1:\r
+                               return current[0];\r
+                       default:\r
+                               return current[Math.abs(random.nextInt())%end];\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public synchronized boolean refresh() {\r
+               end = orig.length;\r
+               \r
+               // Build up list\r
+               for(int i = 0; i < end ; ++i) {\r
+                       if(current[i]==null)current[i]=new PLItem(i);\r
+                       else current[i].idx=current[i].order=i;\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       private class PLItem implements Item {\r
+               public int idx,order;\r
+               \r
+               public PLItem(int i) {\r
+                       idx = order =i;\r
+               }\r
+               \r
+               public String toString() {\r
+                       return "Item: " + idx + " order: " + order;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void destroy() {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Put.java b/client/src/main/java/com/att/cadi/client/Put.java
new file mode 100644 (file)
index 0000000..033216b
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.inno.env.APIException;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public class Put<T> extends AAFClient.Call<T> {\r
+       public Put(AAFClient ac, RosettaDF<T> df) {\r
+               super(ac,df);\r
+       }\r
+       \r
+       public Result<T> update(final String pathInfo, final T t) throws Exception {\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<T>>() {\r
+                               @Override\r
+                               public Result<T> code(Rcli<?> client) throws APIException, CadiException {\r
+                                       Future<T> ft = client.update(pathInfo,df,t); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+       \r
+       public Result<Void> update(final String pathInfo) throws Exception {\r
+               return client.hman.best(client.ss, \r
+                        new Retryable<Result<Void>>() {\r
+                               @Override\r
+                               public Result<Void> code(Rcli<?> client) throws APIException, CadiException {\r
+                                       Future<Void> ft = client.update(pathInfo); \r
+                                       if(ft.get(client.readTimeout)) {\r
+                                               return Result.ok(ft.code(),ft.value);\r
+                                       } else {\r
+                                               return Result.err(ft.code(),ft.body());\r
+                                       }\r
+                               }\r
+                       });\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/RawClient.java b/client/src/main/java/com/att/cadi/client/RawClient.java
new file mode 100644 (file)
index 0000000..d1a1fc2
--- /dev/null
@@ -0,0 +1,159 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.PrintStream;\r
+import java.net.URI;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+\r
+public abstract class RawClient {\r
+       protected static String aafid, aafpass, aafurl;\r
+       protected static Symm symm;\r
+       \r
+       protected static boolean init(PrintStream out) {\r
+               try {\r
+                       String propfile = System.getProperty(Config.CADI_PROP_FILES);\r
+                       if(propfile==null) {\r
+                               propfile = "raw.props";\r
+                       }\r
+                       File pfile = new File(propfile);\r
+                       if(!pfile.exists())  {\r
+                               if(propfile.equals("raw.props")) {\r
+                                       out.println("Creating 'raw.props'.  Edit for proper values, then run again.  Alternatively, set "\r
+                                       + Config.CADI_PROP_FILES+" to a cadi properties file");\r
+                                       FileOutputStream fos = new FileOutputStream(pfile);\r
+                                       PrintStream ps = new PrintStream(fos);\r
+                                       try {\r
+                                               ps.println("# Use http://www.bing.com/maps to figure out LAT/LONG of an Address");\r
+                                               ps.println("AFT_LATITUDE=38.432930");\r
+                                               ps.println("AFT_LONGITUDE=-90.432480");\r
+                                               ps.println("AFT_ENVIRONMENT=AFTUAT");\r
+                                               ps.print(Config.AAF_URL);\r
+                                               ps.println("=aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");\r
+                                               ps.print(Config.CADI_KEYFILE);\r
+                                               ps.println("=<keyfile.  use java -jar cadi-core*.jar in lib dir>");\r
+                                               ps.println(Config.AAF_MECHID);\r
+                                               ps.print("=<your id>");\r
+                                               ps.println(Config.AAF_MECHPASS);\r
+                                               ps.print("=<your encrypted password.  use java -jar cadi-core*.jar in lib dir>");\r
+                                       } finally {\r
+                                               ps.close();\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               FileInputStream fis = new FileInputStream(propfile);\r
+                               try {\r
+                                       System.getProperties().load(fis);\r
+                               } finally {\r
+                                       fis.close();\r
+                               }\r
+                               \r
+                               String cadiKeyFile = System.getProperty(Config.CADI_KEYFILE);\r
+                               aafid = System.getProperty(Config.AAF_MECHID);\r
+                               aafpass = System.getProperty(Config.AAF_MECHPASS);\r
+                               aafurl = System.getProperty(Config.AAF_URL);\r
+                               out.println("Contacting: " + aafurl);\r
+\r
+                               if(cadiKeyFile==null || aafid==null || aafpass==null || aafurl==null ) {\r
+                                       out.print(Config.CADI_KEYFILE);\r
+                                       out.print(", ");\r
+                                       out.print(Config.CADI_KEYFILE);\r
+                                       out.print(", ");\r
+                                       out.print(Config.CADI_KEYFILE);\r
+                                       out.print(", ");\r
+                                       out.print(Config.CADI_KEYFILE);\r
+                                       out.print(" need to be set in ");\r
+                                       out.println(propfile);\r
+                               } else {\r
+                                       fis = new FileInputStream(cadiKeyFile);\r
+                                       try {\r
+                                               symm = Symm.obtain(fis);\r
+                                       } finally {\r
+                                               fis.close();\r
+                                       }\r
+                               }\r
+                               return true;\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace(out);\r
+               }\r
+               return false;\r
+\r
+       }\r
+       \r
+       public abstract String call(final PrintStream out, final String meth, final String path) throws Exception;\r
+       \r
+       public static void main(String[] args) {\r
+               // Sonar idiocy\r
+               PrintStream out = System.out;\r
+\r
+               try {\r
+                       if(init(out)) {\r
+                               if(args.length<2) {\r
+                                       System.out.println("Parameters: <Method> <path>");\r
+                               } else {\r
+                                       RawClient client = new DME2();\r
+                                       out.println(client.call(out,args[0],args[1]));\r
+                               }\r
+                       }               \r
+               } catch (Exception e) {\r
+                       e.printStackTrace(out);\r
+               }\r
+       }\r
+       \r
+       protected static class DME2 extends RawClient {\r
+\r
+               public String call(final PrintStream out, final String meth, final String path) {\r
+                       try {\r
+                               DME2Client client = new DME2Client(new URI(aafurl),10000);\r
+                               client.setCredentials(aafid, symm.depass(aafpass));\r
+                               client.setMethod(meth);\r
+                               client.setContext(path);\r
+                               \r
+                               if("GET".equalsIgnoreCase(meth) ||\r
+                                  "DELETE".equalsIgnoreCase(meth)) {\r
+                                       client.setPayload("");\r
+                               } else if("POST".equalsIgnoreCase(meth) ||\r
+                                                 "PUT".equalsIgnoreCase(meth)) {\r
+                                       int c;\r
+                                       StringBuilder sb = new StringBuilder();\r
+                                       while((c=System.in.read()) >=0) {\r
+                                               sb.append((char)c);\r
+                                       }\r
+                                       client.setPayload(sb.toString());\r
+                               }\r
+                               return client.sendAndWait(10000);\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace(out);\r
+                               return "";\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Rcli.java b/client/src/main/java/com/att/cadi/client/Rcli.java
new file mode 100644 (file)
index 0000000..f14645e
--- /dev/null
@@ -0,0 +1,697 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.net.URI;\r
+import java.util.Enumeration;\r
+\r
+import javax.servlet.ServletInputStream;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.util.Pool;\r
+import com.att.inno.env.util.Pool.Pooled;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public abstract class Rcli<CT> {\r
+       public static final String BLANK = "";\r
+       public static final String CONTENT_TYPE = "Content-Type";\r
+       public static final String ACCEPT = "Accept";\r
+\r
+       protected static final String POST = "POST";\r
+       protected static final String GET = "GET";\r
+       protected static final String PUT = "PUT";\r
+       protected static final String DELETE = "DELETE";\r
+       protected TYPE type;\r
+       protected String apiVersion;\r
+       protected int readTimeout = 5000;\r
+       protected int connectionTimeout = 3000;\r
+       protected URI uri;\r
+       private String queryParams, fragment;\r
+       public static Pool<byte[]> buffPool = new Pool<byte[]>(new Pool.Creator<byte[]>() {\r
+               @Override\r
+               public byte[] create() throws APIException {\r
+                       return new byte[1024];\r
+               }\r
+\r
+               @Override\r
+               public void destroy(byte[] t) {\r
+               }\r
+\r
+               @Override\r
+               public boolean isValid(byte[] t) {\r
+                       return true;\r
+               }\r
+\r
+               @Override\r
+               public void reuse(byte[] t) {\r
+               }\r
+       });\r
+\r
+\r
+       public Rcli() {\r
+               super();\r
+       }\r
+\r
+       public abstract void setSecuritySetter(SecuritySetter<CT> ss);\r
+       public abstract SecuritySetter<CT> getSecuritySetter();\r
+\r
+\r
+       public Rcli<CT> forUser(SecuritySetter<CT> ss) {\r
+               Rcli<CT> rv = clone(uri==null?this.uri:uri,ss);\r
+               setSecuritySetter(ss);\r
+               rv.type = type;\r
+               rv.apiVersion = apiVersion;\r
+               return rv;\r
+       }\r
+       \r
+       protected abstract Rcli<CT> clone(URI uri, SecuritySetter<CT> ss);\r
+       \r
+       public abstract void invalidate() throws CadiException;\r
+\r
+       public Rcli<CT> readTimeout(int millis) {\r
+               readTimeout = millis;\r
+               return this;\r
+       }\r
+\r
+       public Rcli<CT> connectionTimeout(int millis) {\r
+               connectionTimeout = millis;\r
+               return this;\r
+       }\r
+\r
+       public Rcli<CT> type(TYPE type) {\r
+               this.type=type;\r
+               return this;\r
+       }\r
+\r
+       public Rcli<CT> apiVersion(String apiVersion) {\r
+               this.apiVersion = apiVersion;\r
+               return this;\r
+       }\r
+       \r
+       public boolean isApiVersion(String prospective) {\r
+               return apiVersion.equals(prospective);\r
+       }\r
+\r
+\r
+       public String typeString(Class<?> cls) {\r
+               return "application/"+cls.getSimpleName()+"+"+type.name().toLowerCase()+\r
+                               (apiVersion==null?BLANK:";version="+apiVersion);\r
+       }\r
+\r
+       protected abstract EClient<CT> client() throws CadiException;\r
+\r
+\r
+       public<T> Future<T> create(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+               EClient<CT> client = client();\r
+               client.setMethod(POST);\r
+               client.addHeader(CONTENT_TYPE,contentType);\r
+               client.setPathInfo(pathinfo);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureCreate(df.getTypeClass());\r
+       }\r
+\r
+       public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+               EClient<CT> client = client();\r
+               client.setMethod(POST);\r
+               client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));\r
+               client.setPathInfo(pathinfo);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureCreate(df.getTypeClass());\r
+       }\r
+\r
+       public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(POST);\r
+               client.addHeader(CONTENT_TYPE,typeString(cls));\r
+               client.setPathInfo(pathinfo);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureCreate(df.getTypeClass());\r
+       }\r
+\r
+       public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(POST);\r
+               client.addHeader(CONTENT_TYPE,typeString(cls));\r
+               client.setPathInfo(pathinfo);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureCreate(cls);\r
+       }\r
+\r
+       public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(POST);\r
+               client.addHeader(CONTENT_TYPE,contentType);\r
+               client.setPathInfo(pathinfo);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureCreate(Void.class);\r
+       }\r
+\r
+\r
+       public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(GET);\r
+               client.addHeader(ACCEPT, accept);\r
+               \r
+               for(int i=1;i<headers.length;i=i+2) {\r
+                       client.addHeader(headers[i-1],headers[i]);\r
+               }\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+\r
+               client.setPathInfo(pathinfo);\r
+               \r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureReadString();\r
+       }\r
+\r
+       public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(GET);\r
+               client.addHeader(ACCEPT, accept);\r
+               for(int i=1;i<headers.length;i=i+2) {\r
+                       client.addHeader(headers[i-1],headers[i]);\r
+               }\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               \r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureRead(df,type);\r
+       }\r
+\r
+       public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(GET);\r
+               client.addHeader(ACCEPT, typeString(df.getTypeClass()));\r
+               for(int i=1;i<headers.length;i=i+2) {\r
+                       client.addHeader(headers[i-1],headers[i]);\r
+               }\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               \r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureRead(df,type);\r
+       }\r
+\r
+       public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(GET);\r
+               client.addHeader(ACCEPT, typeString(cls));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               \r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureRead(df,type);\r
+       }\r
+\r
+       public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(PUT);\r
+               client.addHeader(CONTENT_TYPE,contentType);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+       \r
+       public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(PUT);\r
+               client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.futureReadString();\r
+       }\r
+\r
+\r
+       public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(PUT);\r
+               client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+       \r
+       public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(PUT);\r
+               client.addHeader(CONTENT_TYPE, typeString(cls));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+\r
+       /**\r
+        * A method to update with a VOID\r
+        * @param pathinfo\r
+        * @param resp\r
+        * @param expected\r
+        * @return\r
+        * @throws APIException\r
+        * @throws CadiException\r
+        */\r
+       public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(PUT);\r
+               client.addHeader(CONTENT_TYPE, typeString(Void.class));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+//             client.setPayload(new EClient.Transfer() {\r
+//                     @Override\r
+//                     public void transfer(OutputStream os) throws IOException, APIException {\r
+//                     }\r
+//             });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(null);\r
+       }\r
+\r
+       public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(DELETE);\r
+               client.addHeader(CONTENT_TYPE, contentType);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+\r
+       public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(DELETE);\r
+               client.addHeader(CONTENT_TYPE, typeString(cls));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+\r
+       public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(DELETE);\r
+               client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(new EClient.Transfer() {\r
+                       @Override\r
+                       public void transfer(OutputStream os) throws IOException, APIException {\r
+                               df.newData().out(type).direct(t,os);\r
+                       }\r
+               });\r
+\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(t);\r
+       }\r
+\r
+\r
+       public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(DELETE);\r
+               client.addHeader(CONTENT_TYPE, typeString(cls));\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future((T)null);\r
+       }\r
+\r
+       public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {\r
+               final int idx = pathinfo.indexOf('?');\r
+               final String qp; \r
+               if(idx>=0) {\r
+                       qp=pathinfo.substring(idx+1);\r
+                       pathinfo=pathinfo.substring(0,idx);\r
+               } else {\r
+                       qp=queryParams;\r
+               }\r
+\r
+               EClient<CT> client = client();\r
+               client.setMethod(DELETE);\r
+               client.addHeader(CONTENT_TYPE, contentType);\r
+               client.setQueryParams(qp);\r
+               client.setFragment(fragment);\r
+               client.setPathInfo(pathinfo);\r
+               client.setPayload(null);\r
+               client.send();\r
+               queryParams = fragment = null;\r
+               return client.future(null);\r
+       }\r
+\r
+       public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {\r
+               EClient<CT> client = client();\r
+               URI uri;\r
+               try {\r
+                       uri = new URI(req.getRequestURI());\r
+               } catch (Exception e) {\r
+                       throw new CadiException("Invalid incoming URI",e);\r
+               }\r
+               String name;\r
+               for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {\r
+                       name = en.nextElement();\r
+                       client.addHeader(name,req.getHeader(name));\r
+               }\r
+               client.setQueryParams(req.getQueryString());\r
+               client.setFragment(uri.getFragment());\r
+               client.setPathInfo(pathParam);\r
+               String meth = req.getMethod();\r
+               client.setMethod(meth);\r
+               if(!"GET".equals(meth)) {\r
+                       client.setPayload(new EClient.Transfer() {\r
+                               @Override\r
+                               public void transfer(OutputStream os) throws IOException, APIException {\r
+                                       final ServletInputStream is = req.getInputStream();\r
+                                       int read;\r
+                                       // reuse Buffers\r
+                                       Pooled<byte[]> pbuff = buffPool.get();\r
+                                       try { \r
+                                               while((read=is.read(pbuff.content))>=0) {\r
+                                                       os.write(pbuff.content,0,read);\r
+                                               }\r
+                                       } finally {\r
+                                               pbuff.done();\r
+                                       }\r
+                               }\r
+                       });\r
+               }\r
+               client.send();\r
+               return client.future(resp, expected);\r
+       }\r
+\r
+       public String toString() {\r
+               return uri.toString();\r
+       }\r
+\r
+       /**\r
+        * @param queryParams the queryParams to set\r
+        * @return \r
+        */\r
+       public Rcli<CT> setQueryParams(String queryParams) {\r
+               this.queryParams = queryParams;\r
+               return this;\r
+       }\r
+       \r
+\r
+       /**\r
+        * @param fragment the fragment to set\r
+        * @return \r
+        */\r
+       public Rcli<CT> setFragment(String fragment) {\r
+               this.fragment = fragment;\r
+               return this;\r
+       }\r
+\r
+       public URI getURI() {\r
+               return uri;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Result.java b/client/src/main/java/com/att/cadi/client/Result.java
new file mode 100644 (file)
index 0000000..1e4909e
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+public class Result<T> {\r
+       public final int code;\r
+       public final T value;\r
+       public final String error;\r
+\r
+       private Result(int code, T value, String error) {\r
+               this.code = code;\r
+               this.value = value;\r
+               this.error = error;\r
+       }\r
+\r
+       public static<T> Result<T> ok(int code,T t) {\r
+               return new Result<T>(code,t,null);\r
+       }\r
+       \r
+       public static<T> Result<T> err(int code,String body) {\r
+               return new Result<T>(code,null,body);\r
+       }\r
+       \r
+       public boolean isOK() {\r
+               return error==null;\r
+       }\r
+       \r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder("Code: ");\r
+               sb.append(code);\r
+               if(error!=null) {\r
+                       sb.append(" = ");\r
+                       sb.append(error);\r
+               }\r
+               return sb.toString();\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/client/Retryable.java b/client/src/main/java/com/att/cadi/client/Retryable.java
new file mode 100644 (file)
index 0000000..e276837
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.client;\r
+\r
+import java.net.ConnectException;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.inno.env.APIException;\r
+\r
+/**\r
+ * \r
+ *\r
+ * @param <RT>\r
+ * @param <RET>\r
+ */\r
+public abstract class Retryable<RET> {\r
+       // be able to hold state for consistent Connections.  Not required for all connection types.\r
+       public Rcli<?> lastClient;\r
+       private Locator.Item item;\r
+       \r
+       public Retryable() {\r
+               lastClient = null;\r
+               item = null;\r
+       }\r
+\r
+       public Retryable(Retryable<?> ret) {\r
+               lastClient = ret.lastClient;\r
+               item = ret.item;\r
+       }\r
+\r
+       public Locator.Item item(Locator.Item item) {\r
+               lastClient = null;\r
+               this.item = item;\r
+               return item;\r
+       }\r
+       public Locator.Item item() {\r
+               return item;\r
+       }\r
+       \r
+       public abstract RET code(Rcli<?> client) throws CadiException, ConnectException, APIException;\r
+\r
+       /**\r
+        * Note, Retryable is tightly coupled to the Client Utilizing.  It will not be the wrong type.\r
+        * @return\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public <CLIENT> Rcli<CLIENT> lastClient() {\r
+               return (Rcli<CLIENT>)lastClient;\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DEClient.java b/client/src/main/java/com/att/cadi/dme2/DEClient.java
new file mode 100644 (file)
index 0000000..6810916
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.net.URI;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.aft.dme2.handler.DME2RestfulHandler;\r
+import com.att.aft.dme2.handler.DME2RestfulHandler.ResponseInfo;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.EClient;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+public class DEClient implements EClient<DME2Client> {\r
+       private DME2Client client;\r
+       private DME2RestfulHandler replyHandler;\r
+       private EClient.Transfer payload;\r
+       private boolean isProxy;\r
+       private SecuritySetter<DME2Client> ss;\r
+       \r
+       public DEClient(DME2Manager manager, SecuritySetter<DME2Client> ss, URI uri, long timeout) throws DME2Exception, CadiException {\r
+               client = new DME2Client(manager,uri,timeout);\r
+               client.setAllowAllHttpReturnCodes(true);\r
+               this.ss = ss;\r
+               ss.setSecurity(client);\r
+               replyHandler = new DME2RestfulHandler(Rcli.BLANK);\r
+               client.setReplyHandler(replyHandler);\r
+       }\r
+\r
+       @Override\r
+       public void setMethod(String meth) {\r
+               client.setMethod(meth);\r
+       }\r
+\r
+       /**\r
+        * DME2 can't handle having QueryParams on the URL line, but it is the most natural way, so...\r
+        * \r
+        * Also, DME2 can't handle "/proxy" as part of Context in the main URI line, so we add it when we see authz-gw to "isProxy"\r
+        */\r
+       public void setPathInfo(String pathinfo) {\r
+               int qp = pathinfo.indexOf('?');\r
+               if(qp<0) {\r
+                       client.setContext(isProxy?("/proxy"+pathinfo):pathinfo);\r
+               } else {\r
+                       client.setContext(isProxy?("/proxy"+pathinfo.substring(0,qp)):pathinfo.substring(0,qp));\r
+                       client.setQueryParams(pathinfo.substring(qp+1));\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setPayload(EClient.Transfer transfer) {\r
+               payload = transfer;\r
+       }\r
+\r
+       @Override\r
+       public void addHeader(String tag, String value) {\r
+               client.addHeader(tag, value);\r
+       }\r
+\r
+\r
+       @Override\r
+       public void setQueryParams(String q) {\r
+               client.setQueryParams(q);\r
+       }\r
+\r
+       @Override\r
+       public void setFragment(String f) {\r
+               // DME2 does not implement this\r
+       }\r
+\r
+       @Override\r
+       public void send() throws APIException {\r
+               try {\r
+                       if(payload!=null) {\r
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+                               payload.transfer(baos);\r
+                               client.setPayload(new String(baos.toByteArray()));\r
+                       } else {\r
+                               client.setPayload("");\r
+                       }\r
+                       client.send();\r
+               } catch (DME2Exception e) {\r
+                       throw new APIException(e);\r
+               } catch (IOException e) {\r
+                       throw new APIException(e);\r
+               }\r
+       }\r
+\r
+       \r
+       public class DFuture<T> extends Future<T> {\r
+               protected final DME2RestfulHandler reply;\r
+               protected ResponseInfo info;\r
+               \r
+               public DFuture(DME2RestfulHandler reply) {\r
+                       this.reply = reply;\r
+               }\r
+               \r
+               protected boolean evalInfo() throws APIException{\r
+                       //return info.getCode()==200;\r
+                       return true;\r
+               };\r
+               \r
+               public final boolean get(int timeout) throws CadiException {\r
+                       try {\r
+                               info = reply.getResponse(timeout);\r
+                               ss.setLastResponse(info.getCode());\r
+                               return evalInfo();\r
+                       } catch (Exception e) {\r
+                               throw new CadiException(e);\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               public int code() {\r
+                       return info.getCode();\r
+               }\r
+\r
+               @Override\r
+               public String body() {\r
+                       return info.getBody();\r
+               }\r
+\r
+               @Override\r
+               public String header(String tag) {\r
+                       return info.header(tag);\r
+               }\r
+\r
+       }\r
+\r
+       @Override\r
+       public <T> Future<T> futureCreate(Class<T> t) {\r
+               return new DFuture<T>(replyHandler) {\r
+                       public boolean evalInfo() throws APIException {\r
+                               \r
+                               return info.getCode()==201;\r
+                       }\r
+               };\r
+       }\r
+       \r
+\r
+       @Override\r
+       public Future<String> futureReadString() {\r
+               return new DFuture<String>(replyHandler) {\r
+                       public boolean evalInfo() throws APIException {\r
+                               if(info.getCode()==200) {\r
+                                       value = info.getBody();\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+               };\r
+       }\r
+       \r
+       @Override\r
+       public<T> Future<T> futureRead(final RosettaDF<T> df, final Data.TYPE type) {\r
+               return new DFuture<T>(replyHandler) {\r
+                       public boolean evalInfo() throws APIException {\r
+                               if(info.getCode()==200) {\r
+                                       value = df.newData().in(type).load(info.getBody()).asObject();\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public <T> Future<T> future(final T t) {\r
+               return new DFuture<T>(replyHandler) {\r
+                       public boolean evalInfo() {\r
+                               if(info.getCode()==200) {\r
+                                       value = t;\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public Future<Void> future(HttpServletResponse resp,int expected) throws APIException {\r
+               // TODO Auto-generated method stub\r
+               return null;\r
+       }\r
+\r
+       public void setProxy(boolean isProxy) {\r
+               this.isProxy=isProxy;\r
+       }\r
+\r
+       \r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java b/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java
new file mode 100644 (file)
index 0000000..988c92f
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.io.IOException;\r
+import java.security.GeneralSecurityException;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.client.AbsBasicAuth;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+\r
+public class DME2BasicAuth extends AbsBasicAuth<DME2Client> {\r
+       public DME2BasicAuth(String user, String pass, SecurityInfoC<DME2Client> si) throws IOException {\r
+               super(user,pass,si);\r
+       }\r
+\r
+       public DME2BasicAuth(Access access, SecurityInfoC<DME2Client> si) throws IOException {\r
+               super(access.getProperty(Config.AAF_MECHID, null),\r
+                               access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),\r
+                               si);\r
+       }\r
+\r
+       public DME2BasicAuth(BasicPrincipal bp,SecurityInfoC<DME2Client> si) throws IOException {\r
+               super(bp.getName(),new String(bp.getCred()),si);\r
+       }\r
+\r
+       public DME2BasicAuth(Access access) throws IOException, GeneralSecurityException {\r
+               super(access.getProperty(Config.AAF_MECHID, null),\r
+                               access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),\r
+                               new SecurityInfoC<DME2Client>(access));\r
+       }\r
+\r
+       public void setSecurity(DME2Client client) throws CadiException {\r
+               if(isDenied()) {\r
+                       throw new CadiException(REPEAT_OFFENDER);\r
+               }\r
+               client.addHeader("Authorization", headValue);\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java b/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java
new file mode 100644 (file)
index 0000000..f64367b
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.io.IOException;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.SecuritySetter;\r
+\r
+public class DME2ClientSS implements SecuritySetter<DME2Client> {\r
+       private Access access;\r
+       private String user,crd;\r
+       \r
+       public DME2ClientSS(Access access, String user, String pass) throws IOException {\r
+               this.access = access;\r
+               this.user = user;\r
+               this.crd = pass;\r
+       }\r
+       \r
+       @Override\r
+       public void setSecurity(DME2Client client) {\r
+               try {\r
+                       client.setCredentials(user, access.decrypt(crd, false));\r
+               } catch (IOException e) {\r
+                       access.log(Level.ERROR,e,"Error decrypting DME2 Password");\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.SecuritySetter#getID()\r
+        */\r
+       @Override\r
+       public String getID() {\r
+               return user;\r
+       }\r
+\r
+       @Override\r
+       public int setLastResponse(int respCode) {\r
+               // TODO Auto-generated method stub\r
+               return 0;\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2Locator.java b/client/src/main/java/com/att/cadi/dme2/DME2Locator.java
new file mode 100644 (file)
index 0000000..b81cf4a
--- /dev/null
@@ -0,0 +1,349 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.UnknownHostException;\r
+import java.util.Arrays;\r
+import java.util.Comparator;\r
+import java.util.Random;\r
+\r
+//\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.aft.dme2.api.DME2Server;\r
+import com.att.aft.dme2.manager.registry.DME2Endpoint;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+\r
+public class DME2Locator implements Locator {\r
+       private DME2Manager dm;\r
+       private DME2Endpoint[] endpoints;\r
+       private Access access;\r
+       private String service;\r
+       private String version;\r
+       private String routeOffer;\r
+       private String envContext;\r
+       private String thisMachine;\r
+       private String pathInfo;\r
+       private int thisPort;\r
+       private boolean removeSelf;\r
+       private final static Random random = new Random();\r
+\r
+       // Default is to not bother trying to remove self\r
+       public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this(access,dm,service,version,envContext,routeOffer,false);\r
+       }\r
+       \r
+       public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this.access = access;\r
+               if(dm==null) {\r
+                       this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());\r
+               } else {\r
+                       this.dm = dm;\r
+               }\r
+               this.service = service;\r
+               this.version = version;\r
+               this.envContext = envContext;\r
+               this.routeOffer = routeOffer;\r
+               refresh();\r
+               DME2Server server = dm.getServer(); \r
+               if(server == null) {\r
+                       thisMachine = InetAddress.getLocalHost().getHostName();\r
+                       thisPort = 0;\r
+               } else {\r
+                       try {\r
+                               thisMachine = server.getServerProperties().getHostname();\r
+                               //thisPort = server.getPort();\r
+                               thisPort = server.getServerProperties().getPort();\r
+                       } catch(NullPointerException np) { // BAD BOY, DME2...\r
+                               access.log(Level.ERROR, "WARNING: DME2 threw a NullPointer Exception getting Server Machine and Port");\r
+                               thisMachine = InetAddress.getLocalHost().getHostName();\r
+                               thisPort = 0;\r
+                       }\r
+               }\r
+               this.removeSelf = removeSelf;\r
+       }\r
+\r
+       // Default is to not bother trying to remove self\r
+       public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this(access,dm,aafurl,false);\r
+       }\r
+       \r
+       public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
+               if(aafurl==null) throw new LocatorException("URL is null");\r
+               this.access = access;\r
+               if(dm==null) {\r
+                       dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());\r
+               } else {\r
+                       this.dm = dm;\r
+               }\r
+               String[] split = aafurl.split("/");\r
+               StringBuilder sb = new StringBuilder();\r
+               boolean dme2Entered = false;\r
+               for(String s : split) {\r
+                       if(s.startsWith(     "service=")) this.service = s.substring(8);\r
+                       else if(s.startsWith("version=")) this.version = s.substring(8);\r
+                       else if(s.startsWith("envContext=")) this.envContext = s.substring(11);\r
+                       else if(s.startsWith("routeOffer=")) {\r
+                               this.routeOffer = s.substring(11);\r
+                               dme2Entered = true;\r
+                       }\r
+                       else if(dme2Entered) {\r
+                               sb.append('/');\r
+                               sb.append(s);\r
+                       }\r
+                       pathInfo = sb.toString();\r
+               }\r
+               DME2Server server = dm.getServer(); \r
+               if(server == null) {\r
+                       thisMachine = InetAddress.getLocalHost().getHostName();\r
+                       thisPort = 0;\r
+               } else {\r
+                       thisMachine = server.getServerProperties().getHostname();\r
+                       if(thisMachine==null) { // even if server !=null, apparently, it can be uninitialized\r
+                               thisMachine = InetAddress.getLocalHost().getHostName();\r
+                               thisPort = 0;\r
+                       } else {\r
+                               try {\r
+                                       thisPort = server.getServerProperties().getPort();\r
+                               } catch (Exception e) {\r
+                                       thisPort = 0;\r
+                               }\r
+                       }                       \r
+               }\r
+               this.removeSelf=removeSelf;\r
+               refresh();\r
+       }\r
+       \r
+       @Override\r
+       public boolean refresh() {\r
+               try {\r
+                       dm.refresh();\r
+                       endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);\r
+                       if(removeSelf) {\r
+                               for(int i=0;i<endpoints.length;++i) {\r
+                                       if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))\r
+                                               endpoints[i]=null;\r
+                               }\r
+                       }\r
+                       return endpoints.length!=0;\r
+               } catch (Exception e) {\r
+                       access.log(Level.ERROR, e.getMessage());\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private String noEndpointsString() {\r
+               StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");\r
+               sb.append(service);\r
+               sb.append('/');\r
+               sb.append(version);\r
+               sb.append('/');\r
+               sb.append(envContext);\r
+               sb.append('/');\r
+               sb.append(routeOffer);\r
+               return sb.toString();\r
+       }\r
+\r
+       @Override\r
+       public URI get(Locator.Item item) throws LocatorException {\r
+               if(!hasItems()) \r
+                       throw new LocatorException(noEndpointsString());\r
+               if(item == null) \r
+                       return null;\r
+\r
+               Item li = ((Item)item);\r
+               // if URI has been created, use it\r
+               if(li.uri!=null)return li.uri;\r
+       \r
+               // URI not created, create it\r
+               if(li.idx<endpoints.length) {\r
+                       DME2Endpoint de = endpoints[li.idx];\r
+                       if(de!=null) {\r
+                               try {\r
+                                       return li.uri=new URI(de.getProtocol(),null,de.getHost(),de.getPort(),pathInfo,null,null);\r
+                               } catch (URISyntaxException e) {\r
+                                       throw new LocatorException(e);\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public boolean hasItems() {\r
+               return endpoints!=null && endpoints.length>0;\r
+       }\r
+\r
+       @Override\r
+       public void invalidate(Locator.Item item) throws LocatorException {\r
+               if(item instanceof Item) {\r
+                       int idx = ((Item)item).idx;\r
+                       if(idx<endpoints.length) {\r
+                               DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.\r
+                               endpoints[idx]=null;\r
+                               boolean noneLeft=true;\r
+                               for(int i=0;i<endpoints.length && noneLeft;++i) {\r
+                                       noneLeft = endpoints[i]==null;\r
+                               }\r
+                               if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...\r
+                                       for(int i=0;i<endpoints.length && noneLeft;++i) {\r
+                                               DME2Endpoint ep = endpoints[i];\r
+                                               if(ep != null && \r
+                                                  ep.getHost().equals(uhoh.getHost()) &&\r
+                                                  ep.getPort()==uhoh.getPort()) {\r
+                                                        endpoints[i]=null;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                       }\r
+               }\r
+       }\r
+\r
+       public class Item implements Locator.Item {\r
+               private final int idx;\r
+               private URI uri;\r
+               private Item(int i) {\r
+                       idx = i;\r
+                       uri = null;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public Item best() throws LocatorException {\r
+               if(!hasItems()) // checks endpoints\r
+                       if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");\r
+               \r
+               // Some endpoints in Array are null.  Need sub array of usable endpoints\r
+               int usable[] = new int[endpoints.length];\r
+               int count=0;\r
+               for(int i=0;i<endpoints.length;++i) {\r
+                       if(endpoints[i]!=null) {\r
+                               usable[count++] = i;\r
+                       }\r
+               }\r
+               switch(count) {\r
+                       case 0: refresh(); return null;\r
+                       case 1: return new Item(usable[0]);\r
+                       default:\r
+                               int samemach[] = new int[count];\r
+                               int samecount = 0,closecount=0;\r
+                               // has to be sortable\r
+                               Integer closemach[] = new Integer[count];\r
+                               \r
+                               // Analyze for Same Machine or Remote machines\r
+                               for(int i=0;i<count;++i) {\r
+                                       DME2Endpoint ep = endpoints[usable[i]];\r
+                                       String host = ep.getHost();\r
+                                       if(thisMachine.equalsIgnoreCase(host)) {\r
+                                               samemach[samecount++] = usable[i];\r
+                                       } else {\r
+                                               closemach[closecount++] = usable[i];\r
+                                       }\r
+                               }\r
+                               \r
+                               switch(samecount) {\r
+                                       case 0: break;\r
+                                       case 1: return new Item(samemach[0]);\r
+                                       default: // return randomized is multiple Endpoints on local machine.\r
+                                               int i = random.nextInt();\r
+                                               return new Item(usable[Math.abs(i%samecount)]);\r
+                               }\r
+                               \r
+                               // Analyze for closest remote\r
+                               switch(closecount) {\r
+                                       case 0: return null;\r
+                                       case 1: return new Item(closemach[0]);\r
+                                       default: // return closest machine\r
+                                               DoubIndex remote[] = new DoubIndex[closecount];\r
+                                               int remotecount = 0;\r
+                                               for(int i=0;i<closecount;++i) {\r
+                                                       DME2Endpoint de = endpoints[usable[i]];\r
+                                                       remote[remotecount++] = new DoubIndex(de.getDistance(),i);\r
+                                               }\r
+                                               Arrays.sort(remote,new Comparator<DoubIndex> () {\r
+                                                       @Override\r
+                                                       public int compare(DoubIndex a, DoubIndex b) {\r
+                                                               if(a.d<b.d) return -1;\r
+                                                               if(a.d>b.d) return 1;\r
+                                                               return (random.nextInt()%1)==0?1:0;// randomize if the same\r
+                                                       }\r
+                                                       \r
+                                               });\r
+                                               return new Item(remote[0].idx);\r
+                               }\r
+               }\r
+       }\r
+       \r
+       private class DoubIndex {\r
+               public final double d;\r
+               public final int idx;\r
+               \r
+               public DoubIndex(double doub, int i) {\r
+                       d = doub;\r
+                       idx = i;\r
+               }\r
+       }\r
+       @Override\r
+       public Item first() {\r
+               if(endpoints==null)return null;\r
+               for(int i=0;i<endpoints.length;++i) {\r
+                       if(endpoints[i]!=null)\r
+                               return new Item(i); \r
+               }\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public Item next(Locator.Item item) throws LocatorException {\r
+               if(endpoints==null || endpoints.length==0 || !(item instanceof Item))return null;\r
+               int idx = ((Item)item).idx +1;\r
+               for(int i=idx;i<endpoints.length;++i) {\r
+                       if(endpoints[i]!=null)\r
+                               return new Item(i); \r
+               }\r
+// This is a mistake..  will start infinite loops\r
+//             // Did not have any at end... try beginning\r
+//             for(int i=0;i<idx-1;++i) {\r
+//                     if(endpoints[i]!=null)\r
+//                             return new Item(i); \r
+//             }\r
+//             // If still nothing, refresh\r
+//             refresh();\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public void destroy() {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java b/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java
new file mode 100644 (file)
index 0000000..d4612f1
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.client.AbsTransferSS;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+\r
+public class DME2TransferSS extends AbsTransferSS<DME2Client> {\r
+\r
+       public DME2TransferSS(Principal principal, String app, SecurityInfoC<DME2Client> si) throws IOException {\r
+               super(principal, app, si);\r
+       }\r
+\r
+       @Override\r
+       public void setSecurity(DME2Client client) throws CadiException {\r
+               if(value!=null) {\r
+                       if(defSS==null) {\r
+                               throw new CadiException("Need App Credentials to send message");\r
+                       }\r
+                       defSS.setSecurity(client);\r
+                       client.addHeader(Config.CADI_USER_CHAIN, value);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public int setLastResponse(int respCode) {\r
+               return 0;\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java b/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java
new file mode 100644 (file)
index 0000000..f60f791
--- /dev/null
@@ -0,0 +1,68 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.io.IOException;\r
+import java.security.cert.CertificateEncodingException;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.inno.env.APIException;\r
+\r
+\r
+public class DME2x509SS implements SecuritySetter<DME2Client> {\r
+       private String alias;\r
+\r
+       public DME2x509SS(final String sendAlias, SecurityInfoC<DME2Client> si) throws APIException, IOException, CertificateEncodingException {\r
+               if((alias=sendAlias) == null) {\r
+                       if(si.default_alias == null) {\r
+                               throw new APIException("JKS Alias is required to use X509SS Security.  Use " + Config.CADI_ALIAS +" to set default alias");\r
+                       } else {\r
+                               alias = si.default_alias;\r
+                       }\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setSecurity(DME2Client dme2) throws CadiException {\r
+               // DME2Client has to have properties set before creation to work.\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.SecuritySetter#getID()\r
+        */\r
+       @Override\r
+       public String getID() {\r
+               return alias;\r
+       }\r
+\r
+       @Override\r
+       public int setLastResponse(int respCode) {\r
+               return 0;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dme2/DRcli.java b/client/src/main/java/com/att/cadi/dme2/DRcli.java
new file mode 100644 (file)
index 0000000..9ff56ca
--- /dev/null
@@ -0,0 +1,142 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dme2;\r
+\r
+import java.net.MalformedURLException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.aft.dme2.manager.registry.DME2Endpoint;\r
+import com.att.aft.dme2.request.DmeUniformResource;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.EClient;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+\r
+/**\r
+ * DME2 Rosetta Client\r
+ * \r
+ * JAXB defined JSON or XML over DME2 middleware\r
+ * \r
+ *\r
+ * @param <T>\r
+ */\r
+public class DRcli extends Rcli<DME2Client> {\r
+       // Can be more efficient if tied to manager, apparently.  Can pass in null.\r
+       DME2Manager manager=null;\r
+       private SecuritySetter<DME2Client> ss;\r
+       private boolean isProxy;\r
+       \r
+       public DRcli(URI uri, SecuritySetter<DME2Client> secSet) {\r
+               this.uri = uri;\r
+               type = TYPE.JSON;\r
+               apiVersion = null;\r
+               ss=secSet;\r
+       }\r
+       \r
+       @Override\r
+       protected DRcli clone(URI uri, SecuritySetter<DME2Client> ss) {\r
+               return new DRcli(uri,ss);\r
+       }\r
+\r
+\r
+\r
+       /**\r
+        * Note from Thaniga on 11/5.  DME2Client is not expected to be reused... need a fresh one\r
+        * on each transaction, which is expected to cover the Async aspects.\r
+        * \r
+        * @return\r
+        * @throws APIException \r
+        * @throws DME2Exception \r
+        */\r
+       protected EClient<DME2Client> client() throws CadiException {\r
+               try {\r
+                       DEClient dc = new DEClient(manager,getSecuritySetter(),uri,readTimeout);\r
+                       dc.setProxy(isProxy);\r
+                       return dc;\r
+               } catch (DME2Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+       public DRcli setManager(DME2Manager dme2Manager) {\r
+               manager = dme2Manager;\r
+               return this;\r
+       }\r
+\r
+       public List<DRcli> all() throws DME2Exception, APIException {\r
+               ArrayList<DRcli> al = new ArrayList<DRcli>();\r
+               \r
+               if(manager == null) {\r
+                       manager = DME2Manager.getDefaultInstance();\r
+               }\r
+               try {\r
+                       DME2Endpoint[] endp = manager.getEndpoints(new DmeUniformResource(manager.getConfig(),uri));\r
+                       // Convert Searchable Endpoints to Direct Endpoints\r
+                       for(DME2Endpoint de : endp) {\r
+                               al.add(new DRcli(\r
+                                               new URI(uri.getScheme(),null,de.getHost(),de.getPort(),null,null,null),ss)\r
+//                                             new URI(uri.getScheme(),null,de.getHost(),de.getPort(),uri.getPath(),null,null),ss)\r
+                               .setManager(manager)\r
+                               );\r
+                       }\r
+               } catch (MalformedURLException e) {\r
+                       throw new APIException("Invalid URL",e);\r
+               } catch (URISyntaxException e) {\r
+                       throw new APIException("Invalid URI",e);\r
+               }\r
+               return al;\r
+       }\r
+\r
+       @Override\r
+       public void invalidate() throws CadiException {\r
+               try {\r
+                       manager.refresh();\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setSecuritySetter(SecuritySetter<DME2Client> ss) {\r
+               this.ss = ss;\r
+       }\r
+\r
+       @Override\r
+       public SecuritySetter<DME2Client> getSecuritySetter() {\r
+               return ss;\r
+       }\r
+\r
+       public void setProxy(boolean isProxy) {\r
+               this.isProxy = isProxy;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java b/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java
new file mode 100644 (file)
index 0000000..498b013
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.dnsloc;\r
+\r
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+\r
+public class DNSLocator implements Locator {\r
+       private static enum Status {UNTRIED, OK, INVALID, SLOW};\r
+       private static final int CHECK_TIME = 3000;\r
+       \r
+       private String host, protocol;\r
+       private Access access;\r
+       private Host[] hosts;\r
+       private int startPort, endPort;\r
+       private String suffix;\r
+       \r
+       public DNSLocator(Access access, String protocol, String host, String range) {\r
+               this.host = host;\r
+               this.protocol = protocol;\r
+               this.access = access;\r
+               int dash = range.indexOf('-');\r
+               if(dash<0) {\r
+                       startPort = endPort = Integer.parseInt(range);\r
+               } else {\r
+                       startPort = Integer.parseInt(range.substring(0,dash));\r
+                       endPort = Integer.parseInt(range.substring(dash + 1));\r
+               }\r
+               refresh();\r
+       }\r
+\r
+       @Override\r
+       public URI get(Item item) throws LocatorException {\r
+               return hosts[((DLItem)item).cnt].uri;\r
+       }\r
+\r
+       @Override\r
+       public boolean hasItems() {\r
+               for(Host h : hosts) {\r
+                       if(h.status==Status.OK) {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public void invalidate(Item item) {\r
+               DLItem di = (DLItem)item;\r
+               hosts[di.cnt].status = Status.INVALID;\r
+       }\r
+\r
+       @Override\r
+       public Item best() throws LocatorException {\r
+               // not a good "best"\r
+               for(int i=0;i<hosts.length;++i) {\r
+                       switch(hosts[i].status) {\r
+                               case OK:\r
+                                       return new DLItem(i);\r
+                               case INVALID:\r
+                                       break;\r
+                               case SLOW:\r
+                                       break;\r
+                               case UNTRIED:\r
+                                       try {\r
+                                               if(hosts[i].ia.isReachable(CHECK_TIME)) {\r
+                                                       hosts[i].status = Status.OK;\r
+                                                       return new DLItem(i);\r
+                                               }\r
+                                       } catch (IOException e) {\r
+                                               throw new LocatorException(e);\r
+                                       }\r
+                                       break;\r
+                               default:\r
+                                       break;\r
+                       }\r
+               }\r
+               throw new LocatorException("No Available URIs for " + host);\r
+       }\r
+\r
+       @Override\r
+       public Item first() throws LocatorException {\r
+               return new DLItem(0);\r
+       }\r
+\r
+       @Override\r
+       public Item next(Item item) throws LocatorException {\r
+               DLItem di = (DLItem)item;\r
+               if(++di.cnt<hosts.length) {\r
+                       return di;\r
+               } else {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public boolean refresh() {\r
+               try {\r
+                       InetAddress[] ias = InetAddress.getAllByName(host);\r
+                       Host[] temp = new Host[ias.length * (1 + endPort - startPort)];\r
+                       int cnt = -1;\r
+                       for(int j=startPort; j<=endPort; ++j) {\r
+                               for(int i=0;i<ias.length;++i) {\r
+                                       temp[++cnt] = new Host(ias[i], j, suffix);\r
+                               }\r
+                       }\r
+                       hosts = temp;\r
+                       return true;\r
+               } catch (Exception e) {\r
+                       access.log(Level.ERROR, e);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private class Host {\r
+               private URI uri;\r
+               private InetAddress ia;\r
+               private Status status;\r
+               \r
+               public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {\r
+                       ia = inetAddress;\r
+                       uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);\r
+                       status = Status.UNTRIED;\r
+               }\r
+       }\r
+       \r
+       private class DLItem implements Item {\r
+               public DLItem(int i) {\r
+                       cnt = i;\r
+               }\r
+\r
+               private int cnt;\r
+       }\r
+\r
+       @Override\r
+       public void destroy() {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java b/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java
new file mode 100644 (file)
index 0000000..8d8826e
--- /dev/null
@@ -0,0 +1,77 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+\r
+import javax.net.ssl.HttpsURLConnection;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.client.AbsBasicAuth;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+\r
+public class HBasicAuthSS extends AbsBasicAuth<HttpURLConnection> {\r
+       public HBasicAuthSS(Access access, SecurityInfoC<HttpURLConnection> si) throws IOException {\r
+               super(access.getProperty(Config.AAF_MECHID, null),\r
+                               access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),\r
+                               si);\r
+       }\r
+\r
+       public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si) throws IOException {\r
+               super(user,pass,si);\r
+       }\r
+\r
+       public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {\r
+               super(user,pass,si);\r
+               if(asDefault) {\r
+                       si.set(this);\r
+               }\r
+       }\r
+       \r
+       public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si) throws IOException {\r
+               super(bp.getName(),new String(bp.getCred()),si);\r
+       }\r
+       \r
+       public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {\r
+               super(bp.getName(),new String(bp.getCred()),si);\r
+               if(asDefault) {\r
+                       si.set(this);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setSecurity(HttpURLConnection huc) throws CadiException {\r
+               if(isDenied()) {\r
+                       throw new CadiException(REPEAT_OFFENDER);\r
+               }\r
+               huc.addRequestProperty("Authorization" , headValue);\r
+               if(securityInfo!=null && huc instanceof HttpsURLConnection) {\r
+                       securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);\r
+               }\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HClient.java b/client/src/main/java/com/att/cadi/http/HClient.java
new file mode 100644 (file)
index 0000000..d17dcc7
--- /dev/null
@@ -0,0 +1,434 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.OutputStream;\r
+import java.io.Reader;\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.EClient;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data;\r
+import com.att.inno.env.Data.TYPE;\r
+import com.att.inno.env.util.Pool.Pooled;\r
+import com.att.rosetta.env.RosettaDF;\r
+\r
+/**\r
+ * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"\r
+ * for Rosetta Object Translation\r
+ * \r
+ *\r
+ */\r
+public class HClient implements EClient<HttpURLConnection> {\r
+       private URI uri;\r
+       private ArrayList<Header> headers;\r
+       private String meth;\r
+       private String pathinfo;\r
+       private String query;\r
+       private String fragment;\r
+       private Transfer transfer;\r
+       private SecuritySetter<HttpURLConnection> ss;\r
+       private HttpURLConnection huc;\r
+       private int connectTimeout;\r
+\r
+       public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {\r
+               if (uri == null) {\r
+                       throw new LocatorException("No Service available to call");\r
+               }\r
+               this.uri = uri;\r
+               this.ss = ss;\r
+               this.connectTimeout = connectTimeout;\r
+               pathinfo = query = fragment = ""; \r
+       }\r
+\r
+       @Override\r
+       public void setMethod(String meth) {\r
+               this.meth = meth;\r
+       }\r
+\r
+       @Override\r
+       public void setPathInfo(String pathinfo) {\r
+               this.pathinfo = pathinfo;\r
+       }\r
+\r
+       @Override\r
+       public void setPayload(Transfer transfer) {\r
+               this.transfer = transfer;\r
+       }\r
+       \r
+       @Override\r
+       public void addHeader(String tag, String value) {\r
+               if (headers == null)\r
+                       headers = new ArrayList<Header>();\r
+               headers.add(new Header(tag, value));\r
+       }\r
+\r
+       @Override\r
+       public void setQueryParams(String q) {\r
+               query = q;\r
+       }\r
+\r
+       @Override\r
+       public void setFragment(String f) {\r
+               fragment = f;\r
+       }\r
+\r
+       @Override\r
+       public void send() throws APIException {\r
+               try {\r
+                       // Build URL from given URI plus current Settings\r
+                       if(uri.getPath()==null) {\r
+                               throw new APIException("Invalid URL entered for HClient");\r
+                       }\r
+                       StringBuilder pi = new StringBuilder(uri.getPath());\r
+                       if(!pathinfo.startsWith("/")) {\r
+                               pi.append('/');\r
+                       }\r
+                       pi.append(pathinfo);\r
+                       URL url = new URI(\r
+                                       uri.getScheme(), \r
+                                       uri.getUserInfo(),\r
+                                       uri.getHost(), \r
+                                       uri.getPort(), \r
+                                       pi.toString(), \r
+                                       query,\r
+                                       fragment).toURL();\r
+                       pathinfo=null;\r
+                       query=null;\r
+                       fragment=null;\r
+                       huc = (HttpURLConnection) url.openConnection();\r
+                       if(ss!=null) {\r
+                               ss.setSecurity(huc); \r
+                       }\r
+                       huc.setRequestMethod(meth);\r
+                       if (headers != null)\r
+                               for (Header d : headers) {\r
+                                       huc.addRequestProperty(d.tag, d.value);\r
+                               }\r
+                       huc.setDoInput(true);\r
+                       huc.setDoOutput(true);\r
+                       huc.setUseCaches(false);\r
+                       huc.setConnectTimeout(connectTimeout);\r
+                       huc.connect();\r
+                       if (transfer != null) {\r
+                               transfer.transfer(huc.getOutputStream());\r
+                       }\r
+                       // TODO other settings? There's a bunch here.\r
+               } catch (Exception e) {\r
+                       throw new APIException(e);\r
+               } finally { // ensure all these are reset after sends\r
+                       meth=pathinfo=null;\r
+                       if(headers!=null) {\r
+                               headers.clear();\r
+                       }\r
+                       pathinfo = query = fragment = "";\r
+               }\r
+       }\r
+\r
+       public abstract class HFuture<T> extends Future<T> {\r
+               protected HttpURLConnection huc;\r
+               protected int respCode;\r
+               protected String respMessage;\r
+               protected IOException exception;\r
+               protected StringBuilder errContent;\r
+       \r
+               public HFuture(final HttpURLConnection huc) {\r
+                       this.huc = huc;\r
+               }\r
+       \r
+               protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{\r
+                       return respCode == 200;\r
+               };\r
+       \r
+               @Override\r
+               public final boolean get(int timeout) throws CadiException {\r
+                       try {\r
+                               huc.setReadTimeout(timeout);\r
+                               respCode = huc.getResponseCode();\r
+                               ss.setLastResponse(respCode);\r
+                               if(evalInfo(huc)) {\r
+                                       return true;\r
+                               } else {\r
+                                       extractError();\r
+                                       return false;\r
+                               }\r
+                       } catch (IOException | APIException e) {\r
+                               throw new CadiException(e);\r
+                       } finally {\r
+                               close();\r
+                       }\r
+               }\r
+       \r
+               private void extractError() {\r
+                       InputStream is = huc.getErrorStream();\r
+                       try {\r
+                               if(is==null) {\r
+                                       is = huc.getInputStream();\r
+                               }\r
+                               if(is!=null) {\r
+                               errContent = new StringBuilder();\r
+                               int c;\r
+                                       while((c=is.read())>=0) {\r
+                                               errContent.append((char)c);\r
+                                       }\r
+                               }\r
+                       } catch (IOException e) {\r
+                               exception = e;\r
+                       }\r
+               }\r
+       \r
+               // Typically only used by Read\r
+               public StringBuilder inputStreamToString(InputStream is) {\r
+                       // Avoids Carriage returns, and is reasonably efficient, given\r
+                       // the buffer reads.\r
+                       try {\r
+                               StringBuilder sb = new StringBuilder();\r
+                               Reader rdr = new InputStreamReader(is);\r
+                               try {\r
+                                       char[] buf = new char[256];\r
+                                       int read;\r
+                                       while ((read = rdr.read(buf)) >= 0) {\r
+                                               sb.append(buf, 0, read);\r
+                                       }\r
+                               } finally {\r
+                                       rdr.close();\r
+                               }\r
+                               return sb;\r
+                       } catch (IOException e) {\r
+                               exception = e;\r
+                               return null;\r
+                       }\r
+               }\r
+       \r
+       \r
+               @Override\r
+               public int code() {\r
+                       return respCode;\r
+               }\r
+       \r
+               public HttpURLConnection huc() {\r
+                       return huc;\r
+               }\r
+       \r
+               public IOException exception() {\r
+                       return exception;\r
+               }\r
+       \r
+               public String respMessage() {\r
+                       return respMessage;\r
+               }\r
+       \r
+               @Override\r
+               public String header(String tag) {\r
+                       return huc.getHeaderField(tag);\r
+               }\r
+       \r
+               public void close() {\r
+                       if(huc!=null) {\r
+                               huc.disconnect();\r
+                       }\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public <T> Future<T> futureCreate(Class<T> t) {\r
+               return new HFuture<T>(huc) {\r
+                       public boolean evalInfo(HttpURLConnection huc) {\r
+                               return respCode==201;\r
+                       }\r
+\r
+                       @Override\r
+                       public String body() {\r
+                               if (errContent != null) {\r
+                                       return errContent.toString();\r
+       \r
+                               } else if (respMessage != null) {\r
+                                       return respMessage;\r
+                               }\r
+                               return "";\r
+                       }\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public Future<String> futureReadString() {\r
+               return new HFuture<String>(huc) {\r
+                       public boolean evalInfo(HttpURLConnection huc) throws IOException {\r
+                               if (respCode == 200) {\r
+                                       StringBuilder sb = inputStreamToString(huc.getInputStream());\r
+                                       if (sb != null) {\r
+                                               value = sb.toString();\r
+                                       }\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+\r
+                       @Override\r
+                       public String body() {\r
+                               if (value != null) {\r
+                                       return value;\r
+                               } else if (errContent != null) {\r
+                                       return errContent.toString();\r
+                               } else if (respMessage != null) {\r
+                                       return respMessage;\r
+                               }\r
+                               return "";\r
+                       }\r
+\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {\r
+               return new HFuture<T>(huc) {\r
+                       private Data<T> data;\r
+\r
+                       public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {\r
+                               if (respCode == 200) {\r
+                                       data = df.newData().in(type).load(huc.getInputStream());\r
+                                       value = data.asObject();\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+\r
+                       @Override\r
+                       public String body() {\r
+                               if (data != null) {\r
+                                       try {\r
+                                               return data.asString();\r
+                                       } catch (APIException e) {\r
+                                       }\r
+                               } else if (errContent != null) {\r
+                                       return errContent.toString();\r
+                               } else if (respMessage != null) {\r
+                                       return respMessage;\r
+                               }\r
+                               return "";\r
+                       }\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public <T> Future<T> future(final T t) {\r
+               return new HFuture<T>(huc) {\r
+                       public boolean evalInfo(HttpURLConnection huc) {\r
+                               if (respCode == 200) {\r
+                                       value = t;\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+\r
+                       @Override\r
+                       public String body() {\r
+                               if (errContent != null) {\r
+                                       return errContent.toString();\r
+                               } else if (respMessage != null) {\r
+                                       return respMessage;\r
+                               }\r
+                               return Integer.toString(respCode);\r
+                       }\r
+               };\r
+       }\r
+\r
+       @Override\r
+       public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {\r
+               return new HFuture<Void>(huc) {\r
+                       public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {\r
+                               resp.setStatus(respCode);\r
+                               int read;\r
+                               InputStream is;\r
+                               OutputStream os = resp.getOutputStream();\r
+                               if(respCode==expected) {\r
+                                       is = huc.getInputStream();\r
+                                       // reuse Buffers\r
+                                       Pooled<byte[]> pbuff = Rcli.buffPool.get();\r
+                                       try { \r
+                                               while((read=is.read(pbuff.content))>=0) {\r
+                                                       os.write(pbuff.content,0,read);\r
+                                               }\r
+                                       } finally {\r
+                                               pbuff.done();\r
+                                       }\r
+                                       return true;\r
+                               } else {\r
+                                       is = huc.getErrorStream();\r
+                                       if(is==null) {\r
+                                               is = huc.getInputStream();\r
+                                       }\r
+                                       if(is!=null) {\r
+                                               errContent = new StringBuilder();\r
+                                               Pooled<byte[]> pbuff = Rcli.buffPool.get();\r
+                                               try { \r
+                                                       while((read=is.read(pbuff.content))>=0) {\r
+                                                               os.write(pbuff.content,0,read);\r
+                                                       }\r
+                                               } finally {\r
+                                                       pbuff.done();\r
+                                               }\r
+                                       }\r
+                               }\r
+                               return false;\r
+                       }\r
+\r
+                       @Override\r
+                       public String body() {\r
+                               return errContent==null?respMessage:errContent.toString();\r
+                       }\r
+               };\r
+       }\r
+\r
+       private static class Header {\r
+               public final String tag;\r
+               public final String value;\r
+\r
+               public Header(String t, String v) {\r
+                       this.tag = t;\r
+                       this.value = v;\r
+               }\r
+               \r
+               public String toString() {\r
+                       return tag + '=' + value;\r
+               }\r
+       }\r
+       \r
+       public String toString() {\r
+               return "HttpURLConnection Client configured to " + uri.toString();\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HMangr.java b/client/src/main/java/com/att/cadi/http/HMangr.java
new file mode 100644 (file)
index 0000000..78aff4e
--- /dev/null
@@ -0,0 +1,236 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.net.ConnectException;\r
+import java.net.HttpURLConnection;\r
+import java.net.SocketException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import javax.net.ssl.SSLHandshakeException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.inno.env.APIException;\r
+\r
+public class HMangr {\r
+       private String apiVersion;\r
+       private int readTimeout, connectionTimeout;\r
+       public final Locator<URI> loc;\r
+       private Access access;\r
+       \r
+       public HMangr(Access access, Locator<URI> loc) {\r
+               readTimeout = 10000;\r
+               connectionTimeout=3000;\r
+               this.loc = loc;\r
+               this.access = access;\r
+       }\r
+\r
+       /**\r
+        * Reuse the same service.  This is helpful for multiple calls that change service side cached data so that \r
+        * there is not a speed issue.\r
+        * \r
+        * If the service goes down, another service will be substituted, if available.\r
+        * \r
+        * @param access\r
+        * @param loc\r
+        * @param ss\r
+        * @param item\r
+        * @param retryable\r
+        * @return\r
+        * @throws URISyntaxException \r
+        * @throws Exception\r
+        */\r
+       public<RET> RET same(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws APIException, CadiException, LocatorException {\r
+               RET ret = null;\r
+               boolean retry = true;\r
+               int retries = 0;\r
+               Rcli<HttpURLConnection> client = retryable.lastClient();\r
+               try {\r
+                       do {\r
+                               // if no previous state, get the best\r
+                               if(retryable.item()==null) {\r
+                                       retryable.item(loc.best());\r
+                                       retryable.lastClient = null;\r
+                               }\r
+                               if(client==null) {\r
+                                       Item item = retryable.item();\r
+                                       URI uri=loc.get(item);\r
+                                       if(uri==null) {\r
+                                               loc.invalidate(retryable.item());\r
+                                               if(loc.hasItems()) {\r
+                                                       retryable.item(loc.next(retryable.item()));\r
+                                                       continue;\r
+                                               } else {\r
+                                                       throw new LocatorException("No clients available for " + loc.toString());\r
+                                               }\r
+                                       }\r
+                                       client = new HRcli(this, uri,item,ss)\r
+                                               .connectionTimeout(connectionTimeout)\r
+                                               .readTimeout(readTimeout)\r
+                                               .apiVersion(apiVersion);\r
+                               } else {\r
+                                       client.setSecuritySetter(ss);\r
+                               }\r
+                               \r
+                               retry = false;\r
+                               try {\r
+                                       ret = retryable.code(client);\r
+                               } catch (APIException | CadiException e) {\r
+                                       Item item = retryable.item();\r
+                                       loc.invalidate(item);\r
+                                       retryable.item(loc.next(item));\r
+                                       try {\r
+                                               Throwable ec = e.getCause();\r
+                                               if(ec instanceof java.net.ConnectException) {\r
+                                                       if(client!=null && ++retries<2) { \r
+                                                               access.log(Level.WARN,"Connection refused, trying next available service");\r
+                                                               retry = true;\r
+                                                       } else {\r
+                                                               throw new CadiException("Connection refused, no more available connections to try");\r
+                                                       }\r
+                                               } else if(ec instanceof SSLHandshakeException) {\r
+                                                       retryable.item(null);\r
+                                                       throw e;\r
+                                               } else if(ec instanceof SocketException) {\r
+                                                       if("java.net.SocketException: Connection reset".equals(ec.getMessage())) {\r
+                                                               access.log(Level.ERROR, ec.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");\r
+                                                       }\r
+                                                       retryable.item(null);\r
+                                                       throw e;\r
+                                               } else {\r
+                                                       retryable.item(null);\r
+                                                       throw e;\r
+                                               }\r
+                                       } finally {\r
+                                               client = null;\r
+                                       }\r
+                               } catch (ConnectException e) {\r
+                                       Item item = retryable.item();\r
+                                       loc.invalidate(item);\r
+                                       retryable.item(loc.next(item));\r
+                               }\r
+                       } while(retry);\r
+               } finally {\r
+                       retryable.lastClient = client;\r
+               }\r
+               return ret;\r
+       }\r
+       \r
+       \r
+       public<RET> RET best(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               if(loc==null) {\r
+                       throw new LocatorException("No Locator Configured");\r
+               }\r
+               retryable.item(loc.best());\r
+               return same(ss,retryable);\r
+       }\r
+       public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {\r
+               return oneOf(ss,retryable,true,null);\r
+       }\r
+\r
+       public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify) throws LocatorException, CadiException, APIException {\r
+               return oneOf(ss,retryable,notify,null);\r
+       }\r
+       \r
+       public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify,String host) throws LocatorException, CadiException, APIException {\r
+               RET ret = null;\r
+               // make sure we have all current references:\r
+               loc.refresh();\r
+               for(Item li=loc.first();li!=null;li=loc.next(li)) {\r
+                       URI uri=loc.get(li);\r
+                       if(host!=null && !host.equals(uri.getHost())) {\r
+                               break;\r
+                       }\r
+                       try {\r
+                               ret = retryable.code(new HRcli(this,uri,li,ss));\r
+                               access.log(Level.DEBUG,"Success calling",uri,"during call to all services");\r
+                       } catch (APIException | CadiException e) {\r
+                               Throwable t = e.getCause();\r
+                               if(t!=null && t instanceof ConnectException) {\r
+                                       loc.invalidate(li);\r
+                                       access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");\r
+                               } else if(t instanceof SSLHandshakeException) {\r
+                                       access.log(Level.ERROR,t.getMessage());\r
+                                       loc.invalidate(li);\r
+                               } else if(t instanceof SocketException) {\r
+                                       if("java.net.SocketException: Connection reset".equals(t.getMessage())) {\r
+                                               access.log(Level.ERROR, t.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");\r
+                                       }\r
+                                       retryable.item(null);\r
+                                       throw e;\r
+                               } else {\r
+                                       throw e;\r
+                               }\r
+                       } catch (ConnectException e) {\r
+                               loc.invalidate(li);\r
+                               access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");\r
+                       }\r
+               }\r
+                       \r
+               if(ret == null && notify) \r
+                       throw new LocatorException("No available clients to call");\r
+               return ret;\r
+       }\r
+       \r
+\r
+       public void close() {\r
+               // TODO Anything here?\r
+       }\r
+\r
+       public HMangr readTimeout(int timeout) {\r
+               this.readTimeout = timeout;\r
+               return this;\r
+       }\r
+\r
+       public int readTimeout() {\r
+               return readTimeout;\r
+       }\r
+       \r
+       public void connectionTimeout(int t) {\r
+               connectionTimeout = t;\r
+       }\r
+\r
+       public int connectionTimout() {\r
+               return connectionTimeout;\r
+       }\r
+\r
+       public HMangr apiVersion(String version) {\r
+               apiVersion = version;\r
+               return this;\r
+       }\r
+\r
+       public String apiVersion() {\r
+               return apiVersion;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HRcli.java b/client/src/main/java/com/att/cadi/http/HRcli.java
new file mode 100644 (file)
index 0000000..a55b55a
--- /dev/null
@@ -0,0 +1,134 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.client.EClient;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.Data.TYPE;\r
+\r
+/**\r
+ * DME2 Rosetta Client\r
+ * \r
+ * JAXB defined JSON or XML over DME2 middleware\r
+ * \r
+ *\r
+ * @param <T>\r
+ */\r
+public class HRcli extends Rcli<HttpURLConnection> {\r
+       private HMangr hman;\r
+       private Item item;\r
+       private SecuritySetter<HttpURLConnection> ss;\r
+\r
+       public HRcli(HMangr hman, Item locItem, SecuritySetter<HttpURLConnection> secSet) throws URISyntaxException, LocatorException {\r
+               item=locItem;\r
+               uri=hman.loc.get(locItem);\r
+               this.hman = hman;\r
+               ss=secSet;\r
+               type = TYPE.JSON;\r
+               apiVersion = hman.apiVersion();\r
+       }\r
+\r
+       public HRcli(HMangr hman, URI uri, Item locItem, SecuritySetter<HttpURLConnection> secSet) {\r
+               locItem=item;\r
+               this.uri = uri;\r
+               this.hman = hman;\r
+               ss=secSet;\r
+               type = TYPE.JSON;\r
+               apiVersion = hman.apiVersion();\r
+       }\r
+\r
+       @Override\r
+       protected HRcli clone(URI uri, SecuritySetter<HttpURLConnection> ss) {\r
+               return new HRcli(hman,uri,item,ss);\r
+       }\r
+\r
+\r
+\r
+       /**\r
+        * Note from Thaniga on 11/5.  DME2Client is not expected to be reused... need a fresh one\r
+        * on each transaction, which is expected to cover the Async aspects.\r
+        * \r
+        * @return\r
+        * @throws APIException \r
+        * @throws DME2Exception \r
+        */\r
+       protected EClient<HttpURLConnection> client() throws CadiException {\r
+               try {\r
+                       if(uri==null) {\r
+                               Item item = hman.loc.best();\r
+                               if(item==null) {\r
+                                       throw new CadiException("No service available for " + hman.loc.toString());\r
+                               }\r
+                               uri = hman.loc.get(item);\r
+                       }\r
+                       return new HClient(ss,uri,connectionTimeout);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.client.Rcli#setSecuritySetter(com.att.cadi.SecuritySetter)\r
+        */\r
+       @Override\r
+       public void setSecuritySetter(SecuritySetter<HttpURLConnection> ss) {\r
+               this.ss = ss;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.client.Rcli#getSecuritySetter()\r
+        */\r
+       @Override\r
+       public SecuritySetter<HttpURLConnection> getSecuritySetter() {\r
+               return ss;\r
+       }\r
+\r
+       public void invalidate() throws CadiException {\r
+               try {\r
+                       hman.loc.invalidate(item);\r
+               } catch (Exception e) {\r
+                       throw new CadiException(e);\r
+               }\r
+       }\r
+       \r
+       public HRcli setManager(HMangr hman) {\r
+               this.hman = hman;\r
+               return this;\r
+       }\r
+\r
+       public String toString() {\r
+               return uri.toString();\r
+       }\r
+       \r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HTransferSS.java b/client/src/main/java/com/att/cadi/http/HTransferSS.java
new file mode 100644 (file)
index 0000000..180a341
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.security.Principal;\r
+\r
+import javax.net.ssl.HttpsURLConnection;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.client.AbsTransferSS;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+\r
+\r
+public class HTransferSS extends AbsTransferSS<HttpURLConnection> {\r
+       public HTransferSS(Principal principal, String app) throws IOException {\r
+               super(principal, app);\r
+       }\r
+       \r
+       public HTransferSS(Principal principal, String app, SecurityInfoC<HttpURLConnection> si) {\r
+               super(principal, app, si);\r
+       }\r
+\r
+       @Override\r
+       public void setSecurity(HttpURLConnection huc) throws CadiException {\r
+               if(value!=null) {\r
+                               if(defSS==null) {\r
+                                       throw new CadiException("Need App Credentials to send message");\r
+                               }\r
+                               defSS.setSecurity(huc);\r
+                               huc.addRequestProperty(Config.CADI_USER_CHAIN, value);\r
+               }\r
+               if(securityInfo!=null) {\r
+                       securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public int setLastResponse(int respCode) {\r
+               return 0;\r
+       }\r
+\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/http/HX509SS.java b/client/src/main/java/com/att/cadi/http/HX509SS.java
new file mode 100644 (file)
index 0000000..3022c0f
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.http;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.security.PrivateKey;\r
+import java.security.SecureRandom;\r
+import java.security.Signature;\r
+import java.security.cert.CertificateEncodingException;\r
+import java.security.cert.X509Certificate;\r
+\r
+import javax.net.ssl.HttpsURLConnection;\r
+import javax.net.ssl.X509KeyManager;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.inno.env.APIException;\r
+import com.att.inno.env.util.Chrono;\r
+\r
+\r
+public class HX509SS implements SecuritySetter<HttpURLConnection> {\r
+       private static final byte[] X509 = "x509 ".getBytes();\r
+       private PrivateKey priv;\r
+       private byte[] pub;\r
+       private String cert;\r
+       private SecurityInfoC<HttpURLConnection> securityInfo;\r
+       private String algo;\r
+       private String alias;\r
+       private static int count = new SecureRandom().nextInt();\r
+\r
+       public HX509SS(SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {\r
+               this(null,si,false);\r
+       }\r
+       \r
+       public HX509SS(SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {\r
+               this(null,si,asDefault);\r
+       }\r
+       \r
+       public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {\r
+               this(sendAlias, si, false);\r
+       }\r
+\r
+       public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {\r
+               securityInfo = si;\r
+               if((alias=sendAlias) == null) {\r
+                       if(si.default_alias == null) {\r
+                               throw new APIException("JKS Alias is required to use X509SS Security.  Use " + Config.CADI_ALIAS +" to set default alias");\r
+                       } else {\r
+                               alias = si.default_alias;\r
+                       }\r
+               }\r
+               \r
+               priv=null;\r
+               X509KeyManager[] xkms = si.getKeyManagers();\r
+               if(xkms==null || xkms.length==0) {\r
+                       throw new APIException("There are no valid keys available in given Keystores.  Wrong Keypass?  Expired?");\r
+               }\r
+               for(int i=0;priv==null&&i<xkms.length;++i) {\r
+                       priv = xkms[i].getPrivateKey(alias);\r
+               }\r
+               for(int i=0;cert==null&&i<xkms.length;++i) {\r
+                       X509Certificate[] chain = xkms[i].getCertificateChain(alias);\r
+                       if(chain!=null&&chain.length>0) {\r
+                               algo = chain[0].getSigAlgName(); \r
+                               pub = chain[0].getEncoded();\r
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream(pub.length*2); \r
+                               ByteArrayInputStream bais = new ByteArrayInputStream(pub);\r
+                               Symm.base64noSplit.encode(bais,baos,X509);\r
+                               cert = baos.toString();\r
+                               \r
+                               /*\r
+                               // Inner Test code, uncomment if fix needed\r
+                               bais = new ByteArrayInputStream(baos.toByteArray());\r
+                               baos = new ByteArrayOutputStream(input.length*2);\r
+                               Symm.base64noSplit().decode(bais,baos,5);\r
+                               byte[] output = baos.toByteArray();\r
+                               String reconstitute = output.toString();\r
+                               System.out.println("ok");\r
+                               CertificateFactory certFactory;\r
+                               try {\r
+                                       bais = new ByteArrayInputStream(output);\r
+                                       certFactory = CertificateFactory.getInstance("X.509");\r
+                                       X509Certificate x509 = (X509Certificate)certFactory.generateCertificate(bais);\r
+                                       System.out.println(x509.toString());\r
+                               } catch (CertificateException e) {\r
+                                       e.printStackTrace();\r
+                               }\r
+                               */\r
+                       }\r
+               }\r
+               if(algo==null) {\r
+                       throw new APIException("X509 Security Setter not configured");\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setSecurity(HttpURLConnection huc) throws CadiException {\r
+               if(huc instanceof HttpsURLConnection) {\r
+                       securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);\r
+               }\r
+               if(alias==null) { // must be a one-way\r
+                       huc.setRequestProperty("Authorization", cert);\r
+                       \r
+                       // Test Signed content\r
+                       try {\r
+                               String data = "SignedContent["+ inc() + ']' + Chrono.dateTime();\r
+                               huc.setRequestProperty("Data", data);\r
+                               \r
+                               Signature sig = Signature.getInstance(algo);\r
+                               sig.initSign(priv);\r
+                               sig.update(data.getBytes());\r
+                               byte[] signature = sig.sign();\r
+                               \r
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(signature.length*1.3));\r
+                               ByteArrayInputStream bais = new ByteArrayInputStream(signature);\r
+                               Symm.base64noSplit.encode(bais, baos);\r
+                               huc.setRequestProperty("Signature", new String(baos.toByteArray()));\r
+                               \r
+                       } catch (Exception e) {\r
+                               throw new CadiException(e);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private synchronized int inc() {\r
+               return ++count;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.SecuritySetter#getID()\r
+        */\r
+       @Override\r
+       public String getID() {\r
+               return alias;\r
+       }\r
+       \r
+       @Override\r
+       public int setLastResponse(int respCode) {\r
+               return 0;\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/locator/DME2Locator.java b/client/src/main/java/com/att/cadi/locator/DME2Locator.java
new file mode 100644 (file)
index 0000000..72a5f73
--- /dev/null
@@ -0,0 +1,346 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.locator;\r
+\r
+\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.UnknownHostException;\r
+import java.util.Arrays;\r
+import java.util.Comparator;\r
+import java.util.Properties;\r
+import java.util.Random;\r
+import java.security.SecureRandom;\r
+\r
+//import com.att.aft.dme2.api.DME2Endpoint;\r
+import com.att.aft.dme2.api.DME2Exception;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.aft.dme2.api.DME2Server;\r
+import com.att.aft.dme2.manager.registry.DME2Endpoint;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.PropAccess;\r
+\r
+public class DME2Locator implements Locator<URI> {\r
+       private DME2Manager dm;\r
+       private DME2Endpoint[] endpoints;\r
+       private Access access;\r
+       private String service;\r
+       private String version;\r
+       private String routeOffer;\r
+       private String envContext;\r
+       private String thisMachine;\r
+       private String pathInfo;\r
+       private int thisPort;\r
+       private boolean removeSelf;\r
+       private final static SecureRandom random = new SecureRandom();\r
+\r
+       // Default is to not bother trying to remove self\r
+       public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this(access,dm,service,version,envContext,routeOffer,false);\r
+       }\r
+       \r
+       public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this.access = access;\r
+               if(dm==null) {\r
+                       this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());\r
+               } else {\r
+                       this.dm = dm;\r
+               }\r
+               this.service = service;\r
+               this.version = version;\r
+               this.envContext = envContext;\r
+               this.routeOffer = routeOffer;\r
+               refresh();\r
+               if(thisMachine==null) {\r
+                       // Can't get from dm... \r
+                       thisMachine = InetAddress.getLocalHost().getHostName();\r
+                       thisPort = 0;\r
+               } else {\r
+                       thisPort = dm.getPort();\r
+               }\r
+\r
+               this.removeSelf = removeSelf;\r
+       }\r
+\r
+       // Default is to not bother trying to remove self\r
+       public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {\r
+               this(access,dm,aafurl,false);\r
+       }\r
+       \r
+       public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {\r
+               if(aafurl==null) {\r
+                       throw new LocatorException("URL is null");\r
+               }\r
+               this.access = access;\r
+               if(dm==null) {\r
+                       Properties dprops;\r
+                       if(access instanceof PropAccess) {\r
+                               dprops = ((PropAccess)access).getDME2Properties();\r
+                       } else {\r
+                               dprops = System.getProperties();\r
+                       }\r
+                       dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",dprops);\r
+               } else {\r
+                       this.dm = dm;\r
+               }\r
+               String[] split = aafurl.split("/");\r
+               StringBuilder sb = new StringBuilder();\r
+               boolean dme2Entered = false;\r
+               for(String s : split) {\r
+                       if(s.startsWith("service=")) {\r
+                               this.service = s.substring(8);\r
+                       } else if(s.startsWith("version=")) {\r
+                               this.version = s.substring(8);\r
+                       } else if(s.startsWith("envContext=")) {\r
+                               this.envContext = s.substring(11);\r
+                       } else if(s.startsWith("routeOffer=")) {\r
+                               this.routeOffer = s.substring(11);\r
+                               dme2Entered = true;\r
+                       } else if(dme2Entered) {\r
+                               sb.append('/');\r
+                               sb.append(s);\r
+                       }\r
+               }\r
+               pathInfo = sb.toString();\r
+               thisMachine = dm.getHostname();\r
+               if(thisMachine==null) {\r
+                       // Can't get from dm... \r
+                       thisMachine = InetAddress.getLocalHost().getHostName();\r
+                       thisPort = 0;\r
+               } else {\r
+                       thisPort = dm.getPort();\r
+               }\r
+               this.removeSelf=removeSelf;\r
+               refresh();\r
+       }\r
+       \r
+       @Override\r
+       public boolean refresh() {\r
+               try {\r
+                       dm.refresh();\r
+                       //endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);\r
+                       if(removeSelf) {\r
+//                             for(int i=0;i<endpoints.length;++i) {\r
+//                                     if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))\r
+//                                             endpoints[i]=null;\r
+                               }\r
+                       //}\r
+                       //return endpoints.length!=0;\r
+               } catch (Exception e) {\r
+                       access.log(Level.ERROR, e.getMessage());\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private String noEndpointsString() {\r
+               StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");\r
+               sb.append(service);\r
+               sb.append('/');\r
+               sb.append(version);\r
+               sb.append('/');\r
+               sb.append(envContext);\r
+               sb.append('/');\r
+               sb.append(routeOffer);\r
+               return sb.toString();\r
+       }\r
+\r
+       @Override\r
+       public URI get(Locator.Item item) throws LocatorException {\r
+               if(!hasItems()) \r
+                       throw new LocatorException(noEndpointsString());\r
+               if(item == null) \r
+                       return null;\r
+\r
+               DME2Item li = ((DME2Item)item);\r
+               // if URI has been created, use it\r
+               if(li.uri!=null)return li.uri;\r
+       \r
+               // URI not created, create it\r
+//             if(li.idx<endpoints.length) {\r
+//                     DME2Endpoint de = endpoints[li.idx];\r
+//                     if(de!=null) {\r
+//                             try {\r
+//                                     return li.uri=new URI(de.getProtocol().toLowerCase(),null,de.getHost(),de.getPort(),pathInfo,null,null);\r
+//                             } catch (URISyntaxException e) {\r
+//                                     throw new LocatorException(e);\r
+//                             }\r
+//                     }\r
+//             }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public boolean hasItems() {\r
+               //return endpoints!=null && endpoints.length>0;\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public void invalidate(Locator.Item item) throws LocatorException {\r
+               if(item instanceof DME2Item) {\r
+                       int idx = ((DME2Item)item).idx;\r
+//                     if(idx<endpoints.length) {\r
+//                             DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.\r
+//                             endpoints[idx]=null;\r
+//                             boolean noneLeft=true;\r
+//                             for(int i=0;i<endpoints.length && noneLeft;++i) {\r
+//                                     noneLeft = endpoints[i]==null;\r
+//                             }\r
+//                             if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...\r
+//                                     for(int i=0;i<endpoints.length && noneLeft;++i) {\r
+//                                             DME2Endpoint ep = endpoints[i];\r
+//                                             if(ep != null && \r
+//                                                ep.getHost().equals(uhoh.getHost()) &&\r
+//                                                ep.getPort()==uhoh.getPort()) {\r
+//                                                      endpoints[i]=null;\r
+//                                             }\r
+//                                     }\r
+//                             }\r
+//                             \r
+//                     }\r
+               }\r
+       }\r
+\r
+       public class DME2Item implements Locator.Item {\r
+               private final int idx;\r
+               private URI uri;\r
+               private DME2Item(int i) {\r
+                       idx = i;\r
+                       uri = null;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public DME2Item best() throws LocatorException {\r
+               if(!hasItems()) // checks endpoints\r
+                       if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");\r
+               \r
+               // Some endpoints in Array are null.  Need sub array of usable endpoints\r
+               //int usable[] = new int[endpoints.length];\r
+               int count=0;\r
+int[] usable = null;\r
+               //              for(int i=0;i<endpoints.length;++i) {\r
+//                     if(endpoints[i]!=null) {\r
+//                             usable[count++] = i;\r
+//                     }\r
+//             }\r
+               switch(count) {\r
+                       case 0: refresh(); return null;\r
+                       case 1: return new DME2Item(usable[0]);\r
+                       default:\r
+                               int samemach[] = new int[count];\r
+                               int samecount = 0,closecount=0;\r
+                               // has to be sortable\r
+                               Integer closemach[] = new Integer[count];\r
+                               \r
+                               // Analyze for Same Machine or Remote machines\r
+//                             for(int i=0;i<count;++i) {\r
+//                                     DME2Endpoint ep = endpoints[usable[i]];\r
+//                                     String host = ep.getHost();\r
+//                                     if(thisMachine.equalsIgnoreCase(host)) {\r
+//                                             samemach[samecount++] = usable[i];\r
+//                                     } else {\r
+//                                             closemach[closecount++] = usable[i];\r
+//                                     }\r
+//                             }\r
+                               \r
+                               switch(samecount) {\r
+                                       case 0: break;\r
+                                       case 1: return new DME2Item(samemach[0]);\r
+                                       default: // return randomized is multiple Endpoints on local machine.\r
+                                               int i = random.nextInt();\r
+                                               return new DME2Item(usable[Math.abs(i%samecount)]);\r
+                               }\r
+                               \r
+                               // Analyze for closest remote\r
+                               switch(closecount) {\r
+                                       case 0: return null;\r
+                                       case 1: return new DME2Item(closemach[0]);\r
+                                       default: // return closest machine\r
+                                               DoubIndex remote[] = new DoubIndex[closecount];\r
+                                               int remotecount = 0;\r
+                                               for(int i=0;i<closecount;++i) {\r
+                                                       //DME2Endpoint de = endpoints[usable[i]];\r
+                                               //      remote[remotecount++] = new DoubIndex(de.getDistance(),i);\r
+                                               }\r
+                                               Arrays.sort(remote,new Comparator<DoubIndex> () {\r
+                                                       @Override\r
+                                                       public int compare(DoubIndex a, DoubIndex b) {\r
+                                                               if(a.d<b.d) return -1;\r
+                                                               if(a.d>b.d) return 1;\r
+                                                               return (random.nextInt()%1)==0?1:0;// randomize if the same\r
+                                                       }\r
+                                                       \r
+                                               });\r
+                                               return new DME2Item(remote[0].idx);\r
+                               }\r
+               }\r
+       }\r
+       \r
+       private static class DoubIndex {\r
+               public final double d;\r
+               public final int idx;\r
+               \r
+               public DoubIndex(double doub, int i) {\r
+                       d = doub;\r
+                       idx = i;\r
+               }\r
+       }\r
+       @Override\r
+       public DME2Item first() {\r
+//             if(endpoints==null)return null;\r
+//             for(int i=0;i<endpoints.length;++i) {\r
+//                     if(endpoints[i]!=null)\r
+//                             return new DME2Item(i); \r
+//             }\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public DME2Item next(Locator.Item item) throws LocatorException {\r
+               //if(endpoints==null || endpoints.length==0 || !(item instanceof DME2Item))return null;\r
+               int idx = ((DME2Item)item).idx +1;\r
+//             for(int i=idx;i<endpoints.length;++i) {\r
+//                     if(endpoints[i]!=null)\r
+//                             return new DME2Item(i); \r
+//             }\r
+// This is a mistake..  will start infinite loops\r
+//             // Did not have any at end... try beginning\r
+//             for(int i=0;i<idx-1;++i) {\r
+//                     if(endpoints[i]!=null)\r
+//                             return new Item(i); \r
+//             }\r
+//             // If still nothing, refresh\r
+//             refresh();\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public void destroy() {\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/locator/DNSLocator.java b/client/src/main/java/com/att/cadi/locator/DNSLocator.java
new file mode 100644 (file)
index 0000000..9fbf2d4
--- /dev/null
@@ -0,0 +1,164 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.locator;\r
+\r
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.Access.Level;\r
+\r
+public class DNSLocator implements Locator<URI> {\r
+       private static enum Status {UNTRIED, OK, INVALID, SLOW};\r
+       private static final int CHECK_TIME = 3000;\r
+       \r
+       private String host, protocol;\r
+       private Access access;\r
+       private Host[] hosts;\r
+       private int startPort, endPort;\r
+       private String suffix;\r
+       \r
+       public DNSLocator(Access access, String protocol, String host, String range) {\r
+               this.host = host;\r
+               this.protocol = protocol;\r
+               this.access = access;\r
+               int dash = range.indexOf('-');\r
+               if(dash<0) {\r
+                       startPort = endPort = Integer.parseInt(range);\r
+               } else {\r
+                       startPort = Integer.parseInt(range.substring(0,dash));\r
+                       endPort = Integer.parseInt(range.substring(dash + 1));\r
+               }\r
+               refresh();\r
+       }\r
+\r
+       @Override\r
+       public URI get(Item item) throws LocatorException {\r
+               return hosts[((DLItem)item).cnt].uri;\r
+       }\r
+\r
+       @Override\r
+       public boolean hasItems() {\r
+               for(Host h : hosts) {\r
+                       if(h.status==Status.OK) {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public void invalidate(Item item) {\r
+               DLItem di = (DLItem)item;\r
+               hosts[di.cnt].status = Status.INVALID;\r
+       }\r
+\r
+       @Override\r
+       public Item best() throws LocatorException {\r
+               // not a good "best"\r
+               for(int i=0;i<hosts.length;++i) {\r
+                       switch(hosts[i].status) {\r
+                               case OK:\r
+                                       return new DLItem(i);\r
+                               case INVALID:\r
+                                       break;\r
+                               case SLOW:\r
+                                       break;\r
+                               case UNTRIED:\r
+                                       try {\r
+                                               if(hosts[i].ia.isReachable(CHECK_TIME)) {\r
+                                                       hosts[i].status = Status.OK;\r
+                                                       return new DLItem(i);\r
+                                               }\r
+                                       } catch (IOException e) {\r
+                                               throw new LocatorException(e);\r
+                                       }\r
+                                       break;\r
+                               default:\r
+                                       break;\r
+                       }\r
+               }\r
+               throw new LocatorException("No Available URIs for " + host);\r
+       }\r
+\r
+       @Override\r
+       public Item first() throws LocatorException {\r
+               return new DLItem(0);\r
+       }\r
+\r
+       @Override\r
+       public Item next(Item item) throws LocatorException {\r
+               DLItem di = (DLItem)item;\r
+               if(++di.cnt<hosts.length) {\r
+                       return di;\r
+               } else {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public boolean refresh() {\r
+               try {\r
+                       InetAddress[] ias = InetAddress.getAllByName(host);\r
+                       Host[] temp = new Host[ias.length * (1 + endPort - startPort)];\r
+                       int cnt = -1;\r
+                       for(int j=startPort; j<=endPort; ++j) {\r
+                               for(int i=0;i<ias.length;++i) {\r
+                                       temp[++cnt] = new Host(ias[i], j, suffix);\r
+                               }\r
+                       }\r
+                       hosts = temp;\r
+                       return true;\r
+               } catch (Exception e) {\r
+                       access.log(Level.ERROR, e);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private class Host {\r
+               private URI uri;\r
+               private InetAddress ia;\r
+               private Status status;\r
+               \r
+               public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {\r
+                       ia = inetAddress;\r
+                       uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);\r
+                       status = Status.UNTRIED;\r
+               }\r
+       }\r
+       \r
+       private class DLItem implements Item {\r
+               public DLItem(int i) {\r
+                       cnt = i;\r
+               }\r
+\r
+               private int cnt;\r
+       }\r
+       \r
+       public void destroy() {}\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java b/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java
new file mode 100644 (file)
index 0000000..ecbdfaa
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.locator;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.http.HClient;\r
+import com.att.cadi.http.HX509SS;\r
+\r
+public class HClientHotPeerLocator extends HotPeerLocator<HClient> {\r
+       private final HX509SS ss;\r
+\r
+       public HClientHotPeerLocator(Access access, String urlstr, long invalidateTime, String localLatitude,\r
+                       String localLongitude, HX509SS ss) throws LocatorException {\r
+               super(access, urlstr, invalidateTime, localLatitude, localLongitude);\r
+               \r
+               this.ss = ss;\r
+       }\r
+\r
+       @Override\r
+       protected HClient _newClient(String clientInfo) throws LocatorException {\r
+               try {\r
+                       int idx = clientInfo.indexOf('/');\r
+                       return new HClient(ss,new URI("https://"+(idx<0?clientInfo:clientInfo.substring(0, idx))),3000);\r
+               } catch (URISyntaxException e) {\r
+                       throw new LocatorException(e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected HClient _invalidate(HClient client) {\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       protected void _destroy(HClient client) {\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java b/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java
new file mode 100644 (file)
index 0000000..f8a1546
--- /dev/null
@@ -0,0 +1,304 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.locator;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.cadi.routing.GreatCircle;\r
+import com.att.inno.env.util.Split;\r
+\r
+/**\r
+ * This Locator is to handle Hot Peer load protection, when the Servers are \r
+ *     1) Static\r
+ *     2) Well known client URL\r
+ * \r
+ * The intention is to change traffic over to the Hot Peer, if a server goes down, and reinstate\r
+ * when it is back up.\r
+ * \r
+ * Example of this kind of Service is a MS Certificate Server\r
+ * \r
+ *\r
+ *\r
+ * @param <CLIENT>\r
+ */\r
+public abstract class HotPeerLocator<CLIENT> implements Locator<CLIENT> {\r
+               private final String[] urlstrs;\r
+               private final CLIENT[] clients;\r
+               private final long[] failures;\r
+               private final double[] distances;\r
+               private int preferred;\r
+               private long invalidateTime;\r
+               private Thread refreshThread;\r
+               protected Access access;\r
+\r
+               /**\r
+                * Construct:  Expect one or more Strings in the form:\r
+                *              192.555.112.223:39/38.88087/-77.30122\r
+                *    separated by commas\r
+                * \r
+                * @param trans\r
+                * @param urlstr\r
+                * @param invalidateTime\r
+                * @param localLatitude\r
+                * @param localLongitude\r
+                * @throws LocatorException\r
+                */\r
+               @SuppressWarnings("unchecked")\r
+               protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException {\r
+                       this.access = access;\r
+                       urlstrs = Split.split(',', urlstr);\r
+                       clients = (CLIENT[])new Object[urlstrs.length];\r
+                       failures = new long[urlstrs.length];\r
+                       distances= new double[urlstrs.length];\r
+                       this.invalidateTime = invalidateTime;\r
+                       \r
+                       double distance = Double.MAX_VALUE;\r
+                       for(int i=0;i<urlstrs.length;++i) {\r
+                               String[] info = Split.split('/', urlstrs[i]);\r
+                               if(info.length<3) {\r
+                                       throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long");\r
+                               }\r
+                               try {\r
+                                       clients[i] = _newClient(urlstrs[i]);\r
+                                       failures[i] = 0L;\r
+                               } catch(LocatorException le) {\r
+                                       failures[i] = System.currentTimeMillis()+invalidateTime;\r
+                               }\r
+                               \r
+                               double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude);\r
+                               distances[i]=d;\r
+                               \r
+                               // find preferred server\r
+                               if(d<distance) {\r
+                                       preferred = i;\r
+                                       distance=d;\r
+                               }\r
+                       }\r
+                       \r
+                       access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]);\r
+                       for(int i=0;i<urlstrs.length;++i) {\r
+                               if(i!=preferred) {\r
+                                       access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               protected abstract CLIENT _newClient(String hostInfo) throws LocatorException;\r
+               /**\r
+                * If client can reconnect, then return.  Otherwise, destroy and return null;\r
+                * @param client\r
+                * @return\r
+                * @throws LocatorException\r
+                */\r
+               protected abstract CLIENT _invalidate(CLIENT client);\r
+               \r
+               protected abstract void _destroy(CLIENT client);\r
+               \r
+               @Override\r
+               public Item best() throws LocatorException {\r
+                       if(failures[preferred]==0L) {\r
+                               return new HPItem(preferred);\r
+                       } else {\r
+                               long now = System.currentTimeMillis();\r
+                               double d = Double.MAX_VALUE;\r
+                               int best = -1;\r
+                               boolean tickle = false;\r
+                               // try for best existing client\r
+                               for(int i=0;i<urlstrs.length;++i) {\r
+                                       if(failures[i]<now && distances[i]<d) {\r
+                                               if(clients[i]!=null) {\r
+                                                       best = i;\r
+                                                       break;\r
+                                               } else {\r
+                                                       tickle = true; // There's some failed clients which can be restored\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if(best<0 && tickle) {\r
+                                       tickle=false;\r
+                                       if(refresh()) {\r
+                                               // try again\r
+                                               for(int i=0;i<urlstrs.length;++i) {\r
+                                                       if(failures[i]==0L && distances[i]<d) {\r
+                                                               if(clients[i]!=null) {\r
+                                                                       best = i;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       \r
+                               /*\r
+                                * If a valid client is available, but there are some that can refresh, return the client immediately\r
+                                * but start a Thread to do the background Client setup.\r
+                                */\r
+                               if(tickle) {\r
+                                       synchronized(clients) {\r
+                                               if(refreshThread==null) {\r
+                                                       refreshThread = new Thread(new Runnable(){\r
+                                                               @Override\r
+                                                               public void run() {\r
+                                                                       refresh();\r
+                                                                       refreshThread = null;\r
+                                                               }\r
+                                                       });\r
+                                                       refreshThread.setDaemon(true);\r
+                                                       refreshThread.start();\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               if(best<0) {\r
+                                       throw new LocatorException("No Clients available");\r
+                               }\r
+\r
+                               \r
+                               return new HPItem(best);\r
+                       }\r
+               }\r
+               \r
+\r
+               @Override\r
+               public CLIENT get(Item item) throws LocatorException {\r
+                       HPItem hpi = (HPItem)item;\r
+                       CLIENT c = clients[hpi.idx];\r
+                       if(c==null) {\r
+                               if(failures[hpi.idx]>System.currentTimeMillis()) {\r
+                                       throw new LocatorException("Client requested is invalid");      \r
+                               } else {\r
+                                       synchronized(clients) {\r
+                                               c = _newClient(urlstrs[hpi.idx]);\r
+                                               failures[hpi.idx]=0L;\r
+                                       }\r
+                               }\r
+                       } else if(failures[hpi.idx]>0){\r
+                               throw new LocatorException("Client requested is invalid");\r
+                       }\r
+                       return c;\r
+               }\r
+               \r
+               public String info(Item item) {\r
+                       HPItem hpi = (HPItem)item;\r
+                       if(hpi!=null && hpi.idx<urlstrs.length) {\r
+                               return urlstrs[hpi.idx];\r
+                       } else {\r
+                               return "Invalid Item";\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               public boolean hasItems() {\r
+                       for(int i=0;i<clients.length;++i) {\r
+                               if(clients[i]!=null && failures[i]==0L) {\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+               \r
+               @Override\r
+               public synchronized void invalidate(Item item) throws LocatorException {\r
+                       HPItem hpi = (HPItem)item;\r
+                       failures[hpi.idx] = System.currentTimeMillis() + invalidateTime;\r
+                       CLIENT c = clients[hpi.idx];\r
+                       clients[hpi.idx] = _invalidate(c);\r
+               }\r
+               \r
+               @Override\r
+               public Item first() throws LocatorException {\r
+                       return new HPItem(0);\r
+               }\r
+               \r
+               @Override\r
+               public Item next(Item item) throws LocatorException {\r
+                       HPItem hpi = (HPItem)item;\r
+                       if(++hpi.idx>=clients.length) {\r
+                               return null;\r
+                       }\r
+                       return hpi;\r
+               }\r
+               \r
+               @Override\r
+               public boolean refresh() {\r
+                       boolean force = !hasItems(); // If no Items at all, reset\r
+                       boolean rv = true;\r
+                       long now = System.currentTimeMillis();\r
+                       for(int i=0;i<clients.length;++i) {\r
+                               if(failures[i]>0L && (failures[i]<now || force)) { // retry\r
+                                       try {\r
+                                               synchronized(clients) {\r
+                                                       if(clients[i]==null) {\r
+                                                               clients[i]=_newClient(urlstrs[i]);\r
+                                                       }\r
+                                                       failures[i]=0L;\r
+                                               }\r
+                                       } catch (LocatorException e) {\r
+                                               failures[i]=now+invalidateTime;\r
+                                               rv = false;\r
+                                       }\r
+                               }\r
+                       }\r
+                       return rv;\r
+               }\r
+               \r
+               @Override\r
+               public void destroy() {\r
+                       for(int i=0;i<clients.length;++i) {\r
+                               if(clients[i]!=null) {\r
+                                       _destroy(clients[i]);\r
+                                       clients[i] = null;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               private static class HPItem implements Item {\r
+                       private int idx;\r
+\r
+                       public HPItem(int i) {\r
+                               idx = i;\r
+                       }\r
+               }\r
+               \r
+\r
+               /*\r
+                * Convenience Functions\r
+                */\r
+               public CLIENT bestClient() throws LocatorException {\r
+                       return get(best());\r
+               }\r
+\r
+               public boolean invalidate(CLIENT client) throws LocatorException {\r
+                       for(int i=0;i<clients.length;++i) {\r
+                               if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference\r
+                                       invalidate(new HPItem(i));\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+\r
+       }\r
diff --git a/client/src/main/java/com/att/cadi/locator/PropertyLocator.java b/client/src/main/java/com/att/cadi/locator/PropertyLocator.java
new file mode 100644 (file)
index 0000000..011e42c
--- /dev/null
@@ -0,0 +1,282 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.locator;\r
+\r
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.InetSocketAddress;\r
+import java.net.Socket;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.UnknownHostException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.security.SecureRandom;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.LocatorException;\r
+import com.att.inno.env.util.Split;\r
+\r
+public class PropertyLocator implements Locator<URI> {\r
+       private final URI [] orig;\r
+       private PLItem[] current;\r
+       private int end;\r
+       private final SecureRandom random;\r
+       private URI[] resolved;\r
+       private long lastRefreshed=0L;\r
+       private long minRefresh;\r
+       private long backgroundRefresh;\r
+\r
+       public PropertyLocator(String locList) throws LocatorException {\r
+               this(locList,10000L, 1000*60*20); // defaults, do not refresh more than once in 10 seconds, Refresh Locator every 20 mins.\r
+       }\r
+       /**\r
+        * comma delimited root url list\r
+        * \r
+        * @param locList\r
+        * @throws LocatorException\r
+        */\r
+       public PropertyLocator(String locList, long minRefreshMillis, long backgroundRefreshMillis) throws LocatorException {\r
+               minRefresh = minRefreshMillis;\r
+               backgroundRefresh = backgroundRefreshMillis;\r
+               if(locList==null) {\r
+                       throw new LocatorException("No Location List given for PropertyLocator");\r
+               }\r
+               String[] locarray = Split.split(',',locList);\r
+               List<URI> uriList = new ArrayList<URI>();\r
+               \r
+               random = new SecureRandom();\r
+               \r
+               for(int i=0;i<locarray.length;++i) {\r
+                       try {\r
+                               int range = locarray[i].indexOf(":[");\r
+                               if(range<0) {\r
+                                       uriList.add(new URI(locarray[i]));\r
+                               } else {\r
+                                       int dash = locarray[i].indexOf('-',range+2);\r
+                                       int brac = locarray[i].indexOf(']',dash+1);\r
+                                       int start = Integer.parseInt(locarray[i].substring(range+2, dash));\r
+                                       int end = Integer.parseInt(locarray[i].substring(dash+1, brac));\r
+                                       for(int port=start;port<=end;++port) {\r
+                                               uriList.add(new URI(locarray[i].substring(0, range+1)+port));\r
+                                       }\r
+                               }\r
+                       } catch (NumberFormatException nf) {\r
+                               throw new LocatorException("Invalid URI format: " + locarray[i]);\r
+                       } catch (URISyntaxException e) {\r
+                               throw new LocatorException(e);\r
+                       }\r
+               }\r
+               orig = new URI[uriList.size()];\r
+               uriList.toArray(orig);\r
+\r
+               refresh();\r
+               new Timer("PropertyLocator Refresh Timer",true).scheduleAtFixedRate(new TimerTask() {\r
+                       @Override\r
+                       public void run() {\r
+                               refresh();\r
+                       }\r
+               }, backgroundRefresh,backgroundRefresh);\r
+\r
+       }\r
+\r
+       @Override\r
+       public URI get(Item item) throws LocatorException {\r
+               synchronized(orig) {\r
+                       if(item==null) {\r
+                               return null;\r
+                       } else {\r
+                               return resolved[((PLItem)item).idx];\r
+                       }\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public Item first() throws LocatorException {\r
+               return end>0?current[0]:null;\r
+       }\r
+\r
+       @Override\r
+       public boolean hasItems() {\r
+               return end>0;\r
+       }\r
+\r
+       @Override\r
+       public Item next(Item item) throws LocatorException {\r
+               if(item==null) {\r
+                       return null;\r
+               } else {\r
+                       int spot;\r
+                       if((spot=(((PLItem)item).order+1))>=end)return null;\r
+                       return current[spot];\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public synchronized void invalidate(Item item) throws LocatorException {\r
+               if(--end<=0) {\r
+                       refresh();\r
+                       return;\r
+               }\r
+               PLItem pli = (PLItem)item;\r
+               int i,order;\r
+               for(i=0;i<end;++i) {\r
+                       if(pli==current[i])break;\r
+               }\r
+               order = current[i].order;\r
+               for(;i<end;++i) {\r
+                       current[i]=current[i+1];\r
+                       current[i].order=order++;\r
+               }\r
+               current[end]=pli;\r
+       }\r
+\r
+       @Override\r
+       public Item best() throws LocatorException {\r
+               if(current.length==0) {\r
+                       refresh();\r
+               }\r
+               switch(current.length) {\r
+                       case 0:\r
+                               return null;\r
+                       case 1:\r
+                               return current[0];\r
+                       default:\r
+                               return current[Math.abs(random.nextInt())%current.length];\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public synchronized boolean refresh() {\r
+               if(System.currentTimeMillis()>lastRefreshed) {\r
+                       // Build up list\r
+                       List<URI> resolve = new ArrayList<URI>();\r
+                       String realname;\r
+                       for(int i = 0; i < orig.length ; ++i) {\r
+                               try {\r
+                                       InetAddress ia[] = InetAddress.getAllByName(orig[i].getHost());\r
+\r
+                                       URI o,n;\r
+                                       for(int j=0;j<ia.length;++j) {\r
+                                               o = orig[i];\r
+                                               Socket socket = new Socket();\r
+                                               try {\r
+                                                       realname=ia[j].getCanonicalHostName();\r
+                                                       socket.connect(new InetSocketAddress(realname,o.getPort()),3000);\r
+                                                       if(socket.isConnected()) {\r
+                                                               n = new URI(\r
+                                                                               o.getScheme(),\r
+                                                                               o.getUserInfo(),\r
+                                                                               realname,\r
+                                                                               o.getPort(),\r
+                                                                               o.getPath(),\r
+                                                                               o.getQuery(),\r
+                                                                               o.getFragment()\r
+                                                                               );\r
+                                                               resolve.add(n);\r
+                                                       }\r
+                                               } catch (IOException e) {\r
+                                               } finally {\r
+                                                       if(!socket.isClosed()) {\r
+                                                               try {\r
+                                                                       socket.close();\r
+                                                               } catch (IOException e) {\r
+                                                                       // nothing to do.\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } catch (UnknownHostException | URISyntaxException e) {\r
+                                       // Note: Orig Name already known as valid, based on constructor\r
+                               }\r
+                       }\r
+                       end=resolve.size();\r
+                       PLItem[] newCurrent;\r
+                       if(current==null || current.length!=end) {\r
+                               newCurrent = new PLItem[end];\r
+                       } else {\r
+                               newCurrent = current;\r
+                       }\r
+       \r
+                       for(int i=0; i< end; ++i) {\r
+                               if(newCurrent[i]==null){\r
+                                       newCurrent[i]=new PLItem(i);\r
+                               } else {\r
+                                       newCurrent[i].idx=newCurrent[i].order=i;\r
+                               }\r
+                       }\r
+                       synchronized(orig) {\r
+                               resolved = new URI[end];\r
+                               resolve.toArray(resolved);\r
+                               current = newCurrent;\r
+                       }\r
+                       lastRefreshed = System.currentTimeMillis()+minRefresh;\r
+                       return !resolve.isEmpty();\r
+               } else {\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       private class PLItem implements Item {\r
+               public int idx,order;\r
+               \r
+               public PLItem(int i) {\r
+                       idx = order =i;\r
+               }\r
+               \r
+               public String toString() {\r
+                       return "Item: " + idx + " order: " + order;\r
+               }\r
+       }\r
+\r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder();\r
+               boolean first = true;\r
+               for(URI uri : orig) {\r
+                       boolean isResolved=false;\r
+                       if(uri!=null) {\r
+                               if(first) {\r
+                                       first = false;\r
+                               } else {\r
+                                       sb.append(", ");\r
+                               }\r
+                               sb.append(uri.toString());\r
+                               sb.append(" [");\r
+                               for(URI u2 : resolved) {\r
+                                       if(uri.equals(u2)) {\r
+                                               isResolved = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               sb.append(isResolved?"X]\n":" ]");\r
+                       }\r
+               }\r
+               return sb.toString();\r
+       }\r
+       \r
+       public void destroy() {\r
+       }\r
+}\r
diff --git a/client/src/main/java/com/att/cadi/routing/GreatCircle.java b/client/src/main/java/com/att/cadi/routing/GreatCircle.java
new file mode 100644 (file)
index 0000000..5a58920
--- /dev/null
@@ -0,0 +1,190 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.routing;\r
+\r
+import com.att.inno.env.util.Split;\r
+\r
+public class GreatCircle {\r
+       // Note: multiplying by this constant is faster than calling Math equivalent function \r
+       private static final double DEGREES_2_RADIANS = Math.PI/180.0;\r
+       \r
+       public static final double DEGREES_2_NM = 60;\r
+       public static final double DEGREES_2_KM = DEGREES_2_NM * 1.852; // 1.852 is exact ratio per 1929 Standard Treaty, adopted US 1954\r
+       public static final double DEGREES_2_MI = DEGREES_2_NM * 1.1507795; \r
+       \r
+       /**\r
+        * \r
+        * Calculate the length of an arc on a perfect sphere based on Latitude and Longitudes of two points\r
+        *    Parameters are in Degrees (i.e. the coordinate system you get from GPS, Mapping WebSites, Phones, etc)\r
+        *    \r
+        *              L1 = Latitude of point A\r
+        *      G1 = Longitude of point A\r
+        *          L2 = Latitude of point B\r
+        *      G2 = Longitude of point B\r
+        *      \r
+        *      d  = acos (sin(L1)*sin(L2) + cos(L1)*cos(L2)*cos(G1 - G2))\r
+        * \r
+        * Returns answer in Degrees\r
+        * \r
+        * Since there are 60 degrees per nautical miles, you can convert to NM by multiplying by 60\r
+        * \r
+        * Essential formula from a Princeton website, the "Law of Cosines" method.  \r
+        * \r
+        * Refactored cleaned up for speed  3/8/2013\r
+        * \r
+        * @param latA\r
+        * @param lonA\r
+        * @param latB\r
+        * @param lonB\r
+        * @return\r
+        */\r
+       public static double calc(double latA, double lonA, double latB, double lonB) {\r
+               // Formula requires Radians.  Expect Params to be Coordinates (Degrees)\r
+               // Simple ratio, quicker than calling Math.toRadians()\r
+               latA *= DEGREES_2_RADIANS;\r
+               lonA *= DEGREES_2_RADIANS;\r
+               latB *= DEGREES_2_RADIANS;\r
+               lonB *= DEGREES_2_RADIANS;\r
+\r
+               return Math.acos(\r
+                               Math.sin(latA) * Math.sin(latB) + \r
+                               Math.cos(latA) * Math.cos(latB) * Math.cos(lonA-lonB)\r
+                       )\r
+                       / DEGREES_2_RADIANS;\r
+       }\r
+       \r
+       /** \r
+        * Convert from "Lat,Long Lat,Long" String format\r
+        *              "Lat,Long,Lat,Long" Format\r
+        *           or all four entries "Lat Long Lat Long"\r
+        * \r
+        * (Convenience function)\r
+        * \r
+        * Since Distance is positive, a "-1" indicates an error in String formatting\r
+        */\r
+       public static double calc(String ... coords) {\r
+               try {\r
+                       String [] array;\r
+                       switch(coords.length) {\r
+                       case 1:\r
+                               array = Split.split(',',coords[0]);\r
+                               if(array.length!=4)return -1;\r
+                               return calc(\r
+                                       Double.parseDouble(array[0]),\r
+                                       Double.parseDouble(array[1]),\r
+                                       Double.parseDouble(array[2]),\r
+                                       Double.parseDouble(array[3])\r
+                                       );\r
+                       case 2:\r
+                               array = Split.split(',',coords[0]);\r
+                               String [] array2 = Split.split(',',coords[1]);\r
+                               if(array.length!=2 || array2.length!=2)return -1;\r
+                               return calc(\r
+                                       Double.parseDouble(array[0]),\r
+                                       Double.parseDouble(array[1]),\r
+                                       Double.parseDouble(array2[0]),\r
+                                       Double.parseDouble(array2[1])\r
+                                       );\r
+                       case 4:\r
+                               return calc(\r
+                                       Double.parseDouble(coords[0]),\r
+                                       Double.parseDouble(coords[1]),\r
+                                       Double.parseDouble(coords[2]),\r
+                                       Double.parseDouble(coords[3])\r
+                                       );\r
+                               \r
+                       default:\r
+                               return -1;\r
+                       }\r
+               } catch (NumberFormatException e) {\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+}\r
+\r
+///**\r
+//* Haverside method, from Princeton\r
+//* \r
+//* @param alat\r
+//* @param alon\r
+//* @param blat\r
+//* @param blon\r
+//* @return\r
+//*/\r
+//public static double calc3(double alat, double alon, double blat, double blon) {\r
+//     alat *= DEGREES_2_RADIANS;\r
+//     alon *= DEGREES_2_RADIANS;\r
+//     blat *= DEGREES_2_RADIANS;\r
+//     blon *= DEGREES_2_RADIANS;\r
+//     return 2 * Math.asin(\r
+//                     Math.min(1, Math.sqrt(\r
+//                             Math.pow(Math.sin((blat-alat)/2), 2) +\r
+//                             (Math.cos(alat)*Math.cos(blat)*\r
+//                                     Math.pow(\r
+//                                             Math.sin((blon-alon)/2),2)\r
+//                                     )\r
+//                             )\r
+//                     )\r
+//             )\r
+//     / DEGREES_2_RADIANS;\r
+//}\r
+//\r
+\r
+\r
+\r
+//This is a MEAN radius.  The Earth is not perfectly spherical\r
+//     public static final double EARTH_RADIUS_KM = 6371.0;\r
+//     public static final double EARTH_RADIUS_NM = 3440.07;\r
+//     public static final double KM_2_MILES_RATIO = 0.621371192;\r
+///**\r
+//* Code on Internet based on Unknown book.  Lat/Long is in Degrees\r
+//* @param alat\r
+//* @param alon\r
+//* @param blat\r
+//* @param blon\r
+//* @return\r
+//*/\r
+//public static double calc1(double alat, double alon, double blat, double blon) {\r
+//     alat *= DEGREES_2_RADIANS;\r
+//     alon *= DEGREES_2_RADIANS;\r
+//     blat *= DEGREES_2_RADIANS;\r
+//     blon *= DEGREES_2_RADIANS;\r
+//     \r
+//     // Reused values\r
+//     double cosAlat,cosBlat;\r
+//     \r
+//     return Math.acos(\r
+//             ((cosAlat=Math.cos(alat))*Math.cos(alon)*(cosBlat=Math.cos(blat))*Math.cos(blon)) +\r
+//             (cosAlat*Math.sin(alon)*cosBlat*Math.sin(blon)) +\r
+//             (Math.sin(alat)*Math.sin(blat))\r
+//             )/DEGREES_2_RADIANS;\r
+//     \r
+//}\r
+\r
+/*\r
+*  This method was 50% faster than calculation 1, and 75% than the Haverside method\r
+*  Also, since it's based off of Agree standard Degrees of the Earth, etc, the calculations are more exact,\r
+*    at least for Nautical Miles and Kilometers\r
+*/\r
diff --git a/client/src/test/java/com/client/test/BasicDME2Client.java b/client/src/test/java/com/client/test/BasicDME2Client.java
new file mode 100644 (file)
index 0000000..a7b2f41
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.net.URI;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+\r
+public class BasicDME2Client {\r
+       public static void main(String[] args) {\r
+               try {\r
+                       Properties props = System.getProperties();\r
+                       \r
+                       DME2Manager dm = new DME2Manager("DME2Manager TestBasicDME2Client",props);\r
+                       URI uri = new URI(System.getProperty("aaf_url"));\r
+                       DME2Client client = new DME2Client(dm,uri,3000);\r
+\r
+                       System.out.println(props.getProperty("aaf_id"));\r
+                       client.setCredentials(props.getProperty("aaf_id"),props.getProperty("aaf_password"));\r
+                       \r
+                       String path = String.format("/authz/perms/user/%s@csp.att.com",args.length>0?args[0]:"xx9999");\r
+                       System.out.printf("Path: %s\n",path);\r
+                       client.addHeader("Accept", "application/Perms+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*");\r
+                       client.setMethod("GET");\r
+                       client.setContext(path);\r
+                       client.setPayload("");// Note: Even on "GET", you need a String in DME2\r
+                       \r
+                       String o = client.sendAndWait(5000); // There are other Asynchronous call options, see DME2 Docs\r
+                       if(o==null) {\r
+                               System.out.println('[' + o + ']' + " (blank is good)");\r
+                       }\r
+                       \r
+                       \r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/client/src/test/java/com/client/test/JU_DNSLocator.java b/client/src/test/java/com/client/test/JU_DNSLocator.java
new file mode 100644 (file)
index 0000000..fcd14c8
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.net.URI;\r
+import java.net.URL;\r
+import java.net.URLConnection;\r
+\r
+import org.junit.AfterClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.locator.DNSLocator;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Locator.Item;\r
+\r
+public class JU_DNSLocator {\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() {\r
+               \r
+               DNSLocator dl = new DNSLocator(new PropAccess(), "https", "aaf.it.att.com","8150-8152");\r
+               try {\r
+                       Item item = dl.best();\r
+                       URI uri = dl.get(item);\r
+                       URL url = uri.toURL();\r
+                       URLConnection conn = url.openConnection();\r
+                       conn.connect();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/client/src/test/java/com/client/test/JU_PropertyLocator.java b/client/src/test/java/com/client/test/JU_PropertyLocator.java
new file mode 100644 (file)
index 0000000..be8e587
--- /dev/null
@@ -0,0 +1,99 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.net.URI;\r
+\r
+import org.junit.AfterClass;\r
+import org.junit.Test;\r
+\r
+import static org.junit.Assert.*;\r
+\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.locator.PropertyLocator;\r
+\r
+public class JU_PropertyLocator {\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() throws Exception {\r
+               PropertyLocator pl = new PropertyLocator("https://localhost:2345,https://fred.wilma.com:26444,https://tom.jerry.com:534");\r
+               \r
+               Item i;\r
+               int count;\r
+               boolean print = false;\r
+               for(int j=0;j<900000;++j) {\r
+                       count = 0;\r
+                       for(i = pl.first();i!=null;i=pl.next(i)) {\r
+                               URI loc = pl.get(i);\r
+                               if(print)System.out.println(loc.toString());\r
+                               ++count;\r
+                       }\r
+                       assertEquals(3,count);\r
+                       assertTrue(pl.hasItems());\r
+                       if(print)System.out.println("---");\r
+                       pl.invalidate(pl.best());\r
+                       \r
+                       count = 0;\r
+                       for(i = pl.first();i!=null;i=pl.next(i)) {\r
+                               URI loc = pl.get(i);\r
+                               if(print)System.out.println(loc.toString());\r
+                               ++count;\r
+                       }\r
+       \r
+                       assertEquals(2,count);\r
+                       assertTrue(pl.hasItems());\r
+                       if(print)System.out.println("---");\r
+                       pl.invalidate(pl.best());\r
+                       \r
+                       count = 0;\r
+                       for(i = pl.first();i!=null;i=pl.next(i)) {\r
+                               URI loc = pl.get(i);\r
+                               if(print)System.out.println(loc.toString());\r
+                               ++count;\r
+                       }\r
+       \r
+                       assertEquals(1,count);\r
+                       assertTrue(pl.hasItems());\r
+                       if(print)System.out.println("---");\r
+                       pl.invalidate(pl.best());\r
+                       \r
+                       count = 0;\r
+                       for(i = pl.first();i!=null;i=pl.next(i)) {\r
+                               URI loc = pl.get(i);\r
+                               if(print)System.out.println(loc.toString());\r
+                               ++count;\r
+                       }\r
+       \r
+                       assertEquals(0,count);\r
+                       assertFalse(pl.hasItems());\r
+                       \r
+                       pl.refresh();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/client/src/test/java/com/client/test/PaulUzee.java b/client/src/test/java/com/client/test/PaulUzee.java
new file mode 100644 (file)
index 0000000..6f82146
--- /dev/null
@@ -0,0 +1,146 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+import java.net.URI;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.dme2.DME2Locator;\r
+\r
+public class PaulUzee {\r
+       public static void main(String[] args) {\r
+               try {\r
+                       // You'll want to put this on Command line "-D" probably\r
+                       Properties props = System.getProperties();\r
+                       props.put("AFT_LATITUDE","32.780140");\r
+                       props.put("AFT_LONGITUDE","-96.800451");\r
+                       props.put("AFT_ENVIRONMENT","AFTPRD");\r
+\r
+                       //\r
+                       // Use an "Access" class to hook up logging, properties, etc.\r
+                       // Make one that ties into your code's logging, property mechanism, etc.\r
+                       //\r
+                       Access access = new PaulAccess();\r
+                       \r
+                       DME2Manager dm = new DME2Manager("Paul Uzee's Test",props);\r
+                       Locator loc = new DME2Locator(access ,dm,"com.att.authz.AuthorizationService","2.0","PROD","DEFAULT");\r
+\r
+                       \r
+                       for(Item item = loc.first(); item!=null; item=loc.next(item)) {\r
+                               URI location = (URI) loc.get(item);\r
+                               access.log(Level.INFO,location);\r
+                               access.log(Level.INFO,location.getScheme());\r
+                               access.log(Level.INFO,location.getHost());\r
+                               access.log(Level.INFO, location.getPort());\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+                       \r
+       }\r
+\r
+       private static class PaulAccess implements Access {\r
+               private Level willWrite = Level.INFO;\r
+\r
+               @Override\r
+               public ClassLoader classLoader() {\r
+                       return getClass().getClassLoader();\r
+               }\r
+\r
+               @Override\r
+               public String decrypt(String data, boolean def) throws IOException {\r
+                       return data;\r
+               }\r
+\r
+               @Override\r
+               public String getProperty(String tag, String def) {\r
+                       return System.getProperty(tag, def);\r
+               }\r
+\r
+               @Override\r
+               public void load(InputStream is) throws IOException {\r
+                       System.getProperties().load(is);\r
+               }\r
+\r
+               @Override\r
+               public void log(Level level, Object... obj) {\r
+                       if(level.compareTo(willWrite)<0) return;\r
+                       PrintStream ps;\r
+                       switch(level) {\r
+                               case DEBUG:\r
+                               case AUDIT:\r
+                               case ERROR:\r
+                               case WARN:\r
+                                       ps = System.err;\r
+                                       break;\r
+                               case INFO:\r
+                               case INIT:\r
+                               default:\r
+                                       ps = System.out;\r
+                       }\r
+                       boolean first = true;\r
+                       for(Object o : obj) {\r
+                               if(first)first=false;\r
+                               else ps.print(' ');\r
+                               ps.print(o.toString());\r
+                       }\r
+                       ps.println();\r
+               }\r
+\r
+               @Override\r
+               public void log(Exception e, Object... obj) {\r
+                       Object[] objs = new Object[obj.length+1];\r
+                       objs[0]=e.getMessage();\r
+                       System.arraycopy(objs, 1, obj, 0, obj.length);\r
+                       log(Level.ERROR,e,objs);\r
+               }\r
+\r
+               @Override\r
+               public void setLogLevel(Level l) {\r
+                       willWrite = l;\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)\r
+                */\r
+               @Override\r
+               public boolean willLog(Level level) {\r
+                       return true;\r
+               }\r
+\r
+               @Override\r
+               public void printf(Level level, String fmt, Object... elements) {\r
+                       // TODO Auto-generated method stub\r
+                       \r
+               }\r
+       };\r
+}\r
diff --git a/client/src/test/java/com/client/test/TestAccess.java b/client/src/test/java/com/client/test/TestAccess.java
new file mode 100644 (file)
index 0000000..3724f1b
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+\r
+public class TestAccess implements Access {\r
+       private Symm symm;\r
+\r
+       public TestAccess() {\r
+               symm = Symm.obtain(this);\r
+       }\r
+       \r
+       public void log(Level level, Object... elements) {\r
+               boolean first = true;\r
+               for(int i=0;i<elements.length;++i) {\r
+                       if(first)first = false;\r
+                       else System.out.print(' ');\r
+                       System.out.print(elements[i].toString());\r
+               }\r
+               System.out.println();\r
+       }\r
+\r
+       public void log(Exception e, Object... elements) {\r
+               e.printStackTrace();\r
+               log(Level.ERROR,elements);\r
+       }\r
+\r
+       public void setLogLevel(Level level) {\r
+               \r
+       }\r
+\r
+       public ClassLoader classLoader() {\r
+               return ClassLoader.getSystemClassLoader();\r
+       }\r
+\r
+       public String getProperty(String string, String def) {\r
+               String rv = System.getProperty(string);\r
+               return rv==null?def:rv;\r
+       }\r
+\r
+       public void load(InputStream is) throws IOException {\r
+               \r
+       }\r
+\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)\r
+        */\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object... elements) {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/client/src/test/java/com/client/test/TestDME2Client.java b/client/src/test/java/com/client/test/TestDME2Client.java
new file mode 100644 (file)
index 0000000..5e5e822
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.io.FileInputStream;\r
+import java.net.URI;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Client;\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.Symm;\r
+\r
+public class TestDME2Client {\r
+       public static void main(String[] args) {\r
+               try {\r
+                       Properties props = System.getProperties();\r
+                       props.put("AFT_LATITUDE","32.780140");\r
+                       props.put("AFT_LONGITUDE","-96.800451");\r
+                       props.put("AFT_ENVIRONMENT","AFTUAT");\r
+                       \r
+                       //props.put("keyStore","/Volumes/Data/src/authz/common/aaf.att.jks");\r
+                       props.put("AFT_DME2_KEYSTORE","/Volumes/Data/src/authz/common/aaf.att.jks");\r
+                       props.put("AFT_DME2_KEYSTORE_PASSWORD","enc:???");\r
+                       props.put("AFT_DME2_TRUSTSTORE","/Volumes/Data/src/authz/common/truststore.jks");\r
+                       props.put("AFT_DME2_TRUSTSTORE_PASSWORD","enc:???");\r
+                       \r
+                       // Local Testing on dynamic IP PC ***ONLY***\r
+//                     props.put("DME2_EP_REGISTRY_CLASS","DME2FS");\r
+//                     props.put("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");\r
+//                     props.put("AFT_DME2_SSL_TRUST_ALL", "true");\r
+\r
+                       Symm symm;\r
+                       FileInputStream keyfile=new FileInputStream("/Volumes/Data/src/authz/common/keyfile");\r
+                       try {\r
+                               symm=Symm.obtain(keyfile);\r
+                       } finally {\r
+                               keyfile.close();\r
+                       }\r
+\r
+                       DME2Manager dm = new DME2Manager("DME2Manager TestHClient",props);\r
+                                         // Standard RESOLVE format\r
+                       String prefix;\r
+                       URI uri = \r
+//                                     new URI(\r
+//                                       "https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE"\r
+//                                     );\r
+//                             prefix = "";\r
+//                                Direct Format\r
+//                                new URI("https://mithrilcsp.sbc.com:8100/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");\r
+//                                prefix = "";\r
+//                                Go through PROXY\r
+//                                new URI("https://mithrilcsp.sbc.com:8095");\r
+//                                prefix = "/proxy";\r
+                                       \r
+//                                     new URI("https://mithrilcsp.sbc.com:8095");\r
+                                       new URI("https://DME2RESOLVE/service=com.att.authz.authz-gw/version=2.0/envContext=UAT/routeOffer=BAU_SE");\r
+//                                prefix = "";\r
+                                  prefix = "/proxy";\r
+                       DME2Client client = new DME2Client(dm,uri,3000);\r
+\r
+                       client.setCredentials("XX@NS", symm.depass("enc:???"));\r
+                       \r
+                       client.addHeader("Accept", "text/plain");\r
+                       client.setMethod("GET");\r
+                       client.setContext(prefix+"/authn/basicAuth");\r
+                       client.setPayload("");// Note: Even on "GET", you need a String in DME2\r
+                       \r
+                       String o = client.sendAndWait(5000); // There are other Asynchronous call options, see DME2 Docs\r
+                       \r
+                       System.out.println('[' + o + ']' + " (blank is good)");\r
+                       \r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/client/src/test/java/com/client/test/TestDME2RcliClient.java b/client/src/test/java/com/client/test/TestDME2RcliClient.java
new file mode 100644 (file)
index 0000000..61bc76a
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.net.URI;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.dme2.DME2ClientSS;\r
+import com.att.cadi.dme2.DRcli;\r
+\r
+public class TestDME2RcliClient {\r
+       public static void main(String[] args) {\r
+               try {\r
+                       Properties props = System.getProperties();\r
+                       props.put("AFT_LATITUDE","32.780140");\r
+                       props.put("AFT_LONGITUDE","-96.800451");\r
+                       props.put("AFT_ENVIRONMENT","AFTUAT");\r
+//                     props.put("DME2_EP_REGISTRY_CLASS","DME2FS");\r
+//                     props.put("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");\r
+\r
+                       props.put("cadi_keystore","/Volumes/Data/src/authz/common/aaf.att.jks");\r
+                       props.put("cadi_keystore_password","enc:???");\r
+                       props.put("cadi_truststore","/Volumes/Data/src/authz/common/truststore.jks");\r
+                       props.put("cadi_truststore_password","enc:???");\r
+                       props.put("cadi_keyfile", "/Volumes/Data/src/authz/common/keyfile");\r
+                       \r
+                       // Local Testing on dynamic IP PC ***ONLY***\r
+//                     props.put("cadi_trust_all_x509", "true");               \r
+                       \r
+                       \r
+                       \r
+                       URI uri = new URI("https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");\r
+                                \r
+                       Access access = new TestAccess();\r
+                       DME2Manager dm = new DME2Manager("DME2Manager TestHClient",props);\r
+                       DRcli client = new DRcli(\r
+                                       uri, \r
+                                       new DME2ClientSS(access,"XX@NS","enc:???"));\r
+                       \r
+                       client.setManager(dm)\r
+                                 .apiVersion("2.0")\r
+                                 .readTimeout(3000);\r
+                       \r
+                       Future<String> ft = client.read("/authz/nss/com.att.aaf","text/json");  \r
+                       if(ft.get(10000)) {\r
+                               System.out.println("Hurray,\n"+ft.body());\r
+                       } else {\r
+                               System.out.println("not quite: " + ft.code());\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/client/src/test/java/com/client/test/TestHClient.java b/client/src/test/java/com/client/test/TestHClient.java
new file mode 100644 (file)
index 0000000..0c6a162
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.client.test;\r
+\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.util.Properties;\r
+\r
+import com.att.aft.dme2.api.DME2Manager;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Locator.Item;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.SecuritySetter;\r
+import com.att.cadi.client.Future;\r
+import com.att.cadi.client.Rcli;\r
+import com.att.cadi.client.Retryable;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.http.HBasicAuthSS;\r
+import com.att.cadi.http.HMangr;\r
+import com.att.cadi.locator.DME2Locator;\r
+import com.att.inno.env.APIException;\r
+\r
+public class TestHClient {\r
+       public static void main(String[] args) {\r
+               try {\r
+                       PropAccess access = new PropAccess();\r
+                       DME2Manager dm = new DME2Manager("DME2Manager TestHClient",access.getProperties());\r
+                       Locator<URI> loc = new DME2Locator(access,dm,"com.att.authz.AuthorizationService","2.0","DEV","BAU_SE");\r
+\r
+                       for(Item item = loc.first(); item!=null; item=loc.next(item)) {\r
+                               System.out.println(loc.get(item));\r
+                       }\r
+                       \r
+                       \r
+                       SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);\r
+                       SecuritySetter<HttpURLConnection> ss = new HBasicAuthSS("m12345@aaf.att.com", \r
+                                       access.decrypt("enc:7K6yjLQqha_S9yApkIul2K_by5Moemcos1HRAVnhMXu",false), si);\r
+//                     SecuritySetter<HttpURLConnection> ss = new X509SS(si, "aaf");\r
+                       \r
+                       HMangr hman = new HMangr(access,loc);\r
+                       try {\r
+                               hman.best(ss, new Retryable<Void>() {\r
+                                       @Override\r
+                                       public Void code(Rcli<?> cli) throws APIException, CadiException {\r
+                                               Future<String> ft = cli.read("/authz/nss/com.att.aaf","text/json");  \r
+                                               if(ft.get(10000)) {\r
+                                                       System.out.println("Hurray,\n"+ft.body());\r
+                                               } else {\r
+                                                       System.out.println("not quite: " + ft.code());\r
+                                               }\r
+                                               return null;\r
+                                       }});\r
+                       } finally {\r
+                               hman.close();\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/core/.gitignore b/core/.gitignore
new file mode 100644 (file)
index 0000000..cf85207
--- /dev/null
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/core/conf/cadi.properties b/core/conf/cadi.properties
new file mode 100644 (file)
index 0000000..d60fc23
--- /dev/null
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------------\r
+# ============LICENSE_START====================================================\r
+# * org.onap.aai\r
+# * ===========================================================================\r
+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+# * Copyright © 2017 Amdocs\r
+# * ===========================================================================\r
+# * Licensed under the Apache License, Version 2.0 (the "License");\r
+# * you may not use this file except in compliance with the License.\r
+# * You may obtain a copy of the License at\r
+# * \r
+#  *      http://www.apache.org/licenses/LICENSE-2.0\r
+# * \r
+#  * Unless required by applicable law or agreed to in writing, software\r
+# * distributed under the License is distributed on an "AS IS" BASIS,\r
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# * See the License for the specific language governing permissions and\r
+# * limitations under the License.\r
+# * ============LICENSE_END====================================================\r
+# *\r
+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+# *\r
+#-------------------------------------------------------------------------------\r
+###############################################################################\r
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.\r
+###############################################################################\r
+# This is a normal Java Properties File\r
+# Comments are with Pound Signs at beginning of lines,\r
+# and multi-line expression of properties can be obtained by backslash at end of line\r
+\r
+# Certain machines have several possible machine names, and\r
+# the right one may not be reported.  This is especially\r
+# important for CSP Authorization, which will only \r
+# function on official AT&T domains.\r
+hostname=veeger.mo.sbc.com \r
+\r
+port=2533\r
+\r
+# CSP has Production mode (active users) or DEVL mode (for \r
+# Testing purposes... Bogus users)\r
+#csp_domain=DEVL\r
+csp_domain=PROD\r
+\r
+# Report all AUTHN and AUTHZ activity\r
+loglevel=AUDIT\r
+\r
+#\r
+# BasicAuth and other User/Password support\r
+#\r
+# The realm reported on BasicAuth callbacks\r
+basic_realm=spiderman.agile.att.com\r
+users=ks%xiVUs_25_1jqGdJ24hqy43Gi;\r
+groups=aaf:Jd8bb3jslg88b@spiderman.agile.att.com%7sZCPBZ_8iWbslqdjWFIDLgTZlm9ung0ym-G,\\r
+               jg1555,lg2384,rd8227,tp007s,pe3617;\r
+       \r
+\r
+# Keyfile (with relative path) for encryption.  This file\r
+# should be marked as ReadOnly by Only the running process\r
+# for security's sake\r
+keyfile=conf/keyfile\r
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644 (file)
index 0000000..15c7e63
--- /dev/null
@@ -0,0 +1,131 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<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">\r
+       <parent>\r
+               <groupId>com.att.cadi</groupId>\r
+               <artifactId>parent</artifactId>\r
+               <relativePath>..</relativePath>\r
+               <version>1.3.2</version>\r
+       </parent>\r
+       \r
+       <modelVersion>4.0.0</modelVersion>\r
+       <name>CADI Core Framework (Code, Access, Data, Identity)</name>\r
+       <artifactId>cadi-core</artifactId>\r
+       <packaging>jar</packaging>\r
+       <url>https://github.com/att/AAF</url>\r
+       <description>CADI</description>\r
+       \r
+       <dependencies>\r
+\r
+               <dependency>\r
+                       <groupId>javax.servlet</groupId>\r
+                       <artifactId>servlet-api</artifactId>\r
+                       <scope>provided</scope>\r
+               </dependency>\r
+               \r
+               <dependency>\r
+                       <groupId>org.slf4j</groupId>\r
+                       <artifactId>slf4j-api</artifactId>\r
+                       <scope>provided</scope>\r
+               </dependency>\r
+               \r
+       </dependencies>\r
+       <build>\r
+               <plugins>\r
+                       <plugin>\r
+                               <!-- Must put this in to turn on Signing, but Configuration itself is \r
+                                       in Parent -->\r
+                               <groupId>org.apache.maven.plugins</groupId>\r
+                               <artifactId>maven-jarsigner-plugin</artifactId>\r
+                       </plugin>\r
+                       <plugin>\r
+                       <groupId>org.apache.maven.plugins</groupId>\r
+                       <artifactId>maven-jar-plugin</artifactId>\r
+                       <configuration>\r
+                               <archive>\r
+                                       <manifest>\r
+                                               <mainClass>com.att.cadi.CmdLine</mainClass>\r
+                                       </manifest>\r
+                                       <manifestEntries>\r
+                                               <Sealed>true</Sealed>\r
+                                       </manifestEntries>\r
+                               </archive>\r
+                       </configuration>\r
+                       <executions>\r
+                               <execution>\r
+                                       <id>test-jar</id>\r
+                                       <phase>package</phase>\r
+                                       <goals>\r
+                                               <goal>test-jar</goal>\r
+                                       </goals>\r
+                               </execution>\r
+                       </executions>\r
+               </plugin>\r
+               \r
+               <plugin>\r
+                       <groupId>org.apache.maven.plugins</groupId>\r
+                       <artifactId>maven-javadoc-plugin</artifactId>\r
+                                       <configuration>\r
+                       <failOnError>false</failOnError>\r
+                       </configuration>\r
+                       <executions>\r
+                               <execution>\r
+                                       <id>attach-javadocs</id>\r
+                                       <goals>\r
+                                               <goal>jar</goal>\r
+                                       </goals>\r
+                               </execution>\r
+                       </executions>\r
+               </plugin> \r
+          \r
+          \r
+              <plugin>\r
+                     <groupId>org.apache.maven.plugins</groupId>\r
+                     <artifactId>maven-source-plugin</artifactId>\r
+                     <version>2.2.1</version>\r
+                     <executions>\r
+                       <execution>\r
+                         <id>attach-sources</id>\r
+                         <goals>\r
+                           <goal>jar-no-fork</goal>\r
+                         </goals>\r
+                       </execution>\r
+                     </executions>\r
+                   </plugin>\r
+       \r
+               <plugin>\r
+                       <groupId>org.sonatype.plugins</groupId>\r
+                       <artifactId>nexus-staging-maven-plugin</artifactId>\r
+                       <version>1.6.7</version>\r
+                       <extensions>true</extensions>\r
+                       <configuration>\r
+                       <serverId>ossrhdme</serverId>\r
+                       <nexusUrl>https://oss.sonatype.org/</nexusUrl>\r
+                       <autoReleaseAfterClose>true</autoReleaseAfterClose>\r
+                       </configuration>\r
+               </plugin>\r
+               </plugins>\r
+       </build>\r
+\r
+</project>\r
diff --git a/core/src/assemble/cadi.xml b/core/src/assemble/cadi.xml
new file mode 100644 (file)
index 0000000..0bbb8e8
--- /dev/null
@@ -0,0 +1,47 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly>\r
+  <id>test</id>\r
+  <formats>\r
+    <format>jar</format>\r
+  </formats>\r
+  <includeBaseDirectory>false</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <outputDirectory></outputDirectory>\r
+      <outputFileNameMapping></outputFileNameMapping>\r
+      <unpack>true</unpack>\r
+      <scope>runtime</scope>\r
+      <!--  includes>\r
+        <include>com.att.cssa:env*</include>\r
+      </includes -->\r
+    </dependencySet>\r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>target/classes</directory>\r
+      <outputDirectory></outputDirectory>\r
+    </fileSet>\r
+   </fileSets>\r
+</assembly>\r
diff --git a/core/src/assemble/poll.xml b/core/src/assemble/poll.xml
new file mode 100644 (file)
index 0000000..c33dd83
--- /dev/null
@@ -0,0 +1,47 @@
+<!--\r
+  ============LICENSE_START====================================================\r
+  * org.onap.aai\r
+  * ===========================================================================\r
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+  * Copyright © 2017 Amdocs\r
+  * ===========================================================================\r
+  * Licensed under the Apache License, Version 2.0 (the "License");\r
+  * you may not use this file except in compliance with the License.\r
+  * You may obtain a copy of the License at\r
+  * \r
+   *      http://www.apache.org/licenses/LICENSE-2.0\r
+  * \r
+   * Unless required by applicable law or agreed to in writing, software\r
+  * distributed under the License is distributed on an "AS IS" BASIS,\r
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  * See the License for the specific language governing permissions and\r
+  * limitations under the License.\r
+  * ============LICENSE_END====================================================\r
+  *\r
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+  *\r
+-->\r
+<assembly>\r
+  <id>app</id>\r
+  <formats>\r
+    <format>jar</format>\r
+  </formats>\r
+  <includeBaseDirectory>false</includeBaseDirectory>\r
+  <dependencySets>\r
+    <dependencySet>\r
+      <outputDirectory></outputDirectory>\r
+      <outputFileNameMapping></outputFileNameMapping>\r
+      <unpack>true</unpack>\r
+      <scope>runtime</scope>\r
+      <!--  includes>\r
+        <include>web</include>\r
+      </includes -->\r
+    </dependencySet>\r
+  </dependencySets>\r
+  <fileSets>\r
+    <fileSet>\r
+      <directory>target/classes</directory>\r
+      <outputDirectory></outputDirectory>\r
+    </fileSet>\r
+   </fileSets>\r
+</assembly>\r
diff --git a/core/src/main/java/com/att/cadi/AES.java b/core/src/main/java/com/att/cadi/AES.java
new file mode 100644 (file)
index 0000000..4041ae5
--- /dev/null
@@ -0,0 +1,128 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.security.InvalidKeyException;\r
+import java.security.NoSuchAlgorithmException;\r
+\r
+import javax.crypto.BadPaddingException;\r
+import javax.crypto.Cipher;\r
+import javax.crypto.CipherInputStream;\r
+import javax.crypto.CipherOutputStream;\r
+import javax.crypto.IllegalBlockSizeException;\r
+import javax.crypto.KeyGenerator;\r
+import javax.crypto.NoSuchPaddingException;\r
+import javax.crypto.SecretKey;\r
+import javax.crypto.spec.SecretKeySpec;\r
+\r
+import com.att.cadi.util.Chmod;\r
+\r
+public class AES {\r
+       public static final String AES = AES.class.getSimpleName();\r
+       public static final int AES_KEY_SIZE = 128; // 256 isn't supported on all JDKs.\r
+       \r
+       private Cipher aesCipher;\r
+       private SecretKeySpec aeskeySpec;\r
+\r
+       public AES() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {\r
+               aesCipher = Cipher.getInstance(AES);\r
+           aeskeySpec = new SecretKeySpec(newKey().getEncoded(), AES);\r
+       }\r
+       \r
+       public static SecretKey newKey() throws NoSuchAlgorithmException {\r
+               KeyGenerator kgen = KeyGenerator.getInstance(AES);\r
+           kgen.init(AES_KEY_SIZE);\r
+           return kgen.generateKey();\r
+       }\r
+\r
+       public AES(File keyfile) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {\r
+               aesCipher = Cipher.getInstance(AES);\r
+               byte[] aesKey = new byte[AES_KEY_SIZE/8];\r
+               FileInputStream fis = new FileInputStream(keyfile);\r
+               try {\r
+                       fis.read(aesKey);\r
+               } finally {\r
+                       fis.close();\r
+               }\r
+               aeskeySpec = new SecretKeySpec(aesKey,AES);\r
+       }\r
+\r
+       public AES(byte[] aeskey, int offset, int len) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {\r
+               aesCipher = Cipher.getInstance(AES);\r
+               aeskeySpec = new SecretKeySpec(aeskey,offset,len,AES);\r
+       }\r
+       \r
+       public byte[] encrypt(byte[] in) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {\r
+               aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);\r
+               return aesCipher.doFinal(in);\r
+       }\r
+       \r
+       public byte[] decrypt(byte[] in) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {\r
+               aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec); \r
+               return aesCipher.doFinal(in);\r
+       }\r
+       \r
+       public void save(File keyfile) throws IOException {\r
+               FileOutputStream fis = new FileOutputStream(keyfile);\r
+               try {\r
+                       fis.write(aeskeySpec.getEncoded());\r
+               } finally {\r
+                       fis.close();\r
+               }\r
+               Chmod.to400.chmod(keyfile);\r
+       }\r
+\r
+       public CipherOutputStream outputStream(OutputStream os, boolean encrypt) {\r
+               try {\r
+                       if(encrypt) {\r
+                               aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);\r
+                       } else {\r
+                               aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec);\r
+                       }\r
+               } catch (InvalidKeyException e) {\r
+                       // KeySpec created earlier... no chance being wrong.\r
+               } \r
+               return new CipherOutputStream(os,aesCipher);\r
+       }\r
+       \r
+       public CipherInputStream inputStream(InputStream is, boolean encrypt) {\r
+               try {\r
+                       if(encrypt) {\r
+                               aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);\r
+                       } else {\r
+                               aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec);\r
+                       }\r
+               } catch (InvalidKeyException e) {\r
+                       // KeySpec created earlier... no chance being wrong.\r
+               } \r
+               \r
+               return new CipherInputStream(is,aesCipher);\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/AbsCachedPrincipal.java b/core/src/main/java/com/att/cadi/AbsCachedPrincipal.java
new file mode 100644 (file)
index 0000000..bb76e3d
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+public abstract class AbsCachedPrincipal<TAF> implements CachedPrincipal {\r
+       protected TAF taf;\r
+\r
+       protected AbsCachedPrincipal(TAF taf) {\r
+               this.taf = taf;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/AbsUserCache.java b/core/src/main/java/com/att/cadi/AbsUserCache.java
new file mode 100644 (file)
index 0000000..0229a71
--- /dev/null
@@ -0,0 +1,409 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+import java.util.TreeMap;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+\r
+/**\r
+ * Implement Fast lookup and Cache for Local User Info\r
+ * \r
+ * Include ability to add and remove Users\r
+ * \r
+ * Also includes a Timer Thread (when necessary) to invoke cleanup on expiring Credentials\r
+ * \r
+ *\r
+ */\r
+public abstract class AbsUserCache<PERM extends Permission> {\r
+       static final int MIN_INTERVAL = 15000;\r
+       static final int MAX_INTERVAL = 1000*60*5; // 5 mins\r
+       private static Timer timer;\r
+       // Map of userName to User\r
+       private final Map<String, User<PERM>> userMap;\r
+       private final Map<String, Miss> missMap;\r
+       private Clean clean;\r
+       protected Access access;\r
+//     private final static Permission teaser = new LocalPermission("***NoPERM****");\r
+       \r
+       protected AbsUserCache(Access access, long cleanInterval, int highCount, int usageCount) {\r
+               this.access = access;\r
+               userMap = new ConcurrentHashMap<String, User<PERM>>();\r
+               missMap = new TreeMap<String,Miss>();\r
+               if(cleanInterval>0) {\r
+                       cleanInterval = Math.max(MIN_INTERVAL, cleanInterval);\r
+                       synchronized(AbsUserCache.class) { // Lazy instantiate.. in case there is no cleanup needed\r
+                               if(timer==null) {\r
+                                       timer = new Timer("CADI Cleanup Timer",true);\r
+                               }\r
+                               \r
+                               timer.schedule(clean = new Clean(access, cleanInterval, highCount, usageCount), cleanInterval, cleanInterval);\r
+                               access.log(Access.Level.INIT, "Cleaning Thread initialized with interval of",cleanInterval, "ms and max objects of", highCount);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public AbsUserCache(AbsUserCache<PERM> cache) {\r
+               this.access = cache.access;\r
+               userMap = cache.userMap;\r
+               missMap = cache.missMap;\r
+               synchronized(AbsUserCache.class) {\r
+                       if(cache.clean!=null && cache.clean.lur==null && this instanceof CachingLur) {\r
+                               cache.clean.lur=(CachingLur<PERM>)this;\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected void setLur(CachingLur<PERM> lur) {\r
+               if(clean!=null)clean.lur = lur;\r
+               \r
+       }\r
+       \r
+       protected void addUser(User<PERM> user) {\r
+               userMap.put(user.principal.getName(), user);\r
+       }\r
+\r
+       // Useful for looking up by WebToken, etc.\r
+       protected void addUser(String key, User<PERM> user) {\r
+               userMap.put(key, user);\r
+       }\r
+       \r
+       /**\r
+        * Add miss to missMap.  If Miss exists, or too many tries, returns false.\r
+        * \r
+        * otherwise, returns true to allow another attempt.\r
+        * \r
+        * @param key\r
+        * @param bs\r
+        * @return\r
+        */\r
+       protected boolean addMiss(String key, byte[] bs) {\r
+               Miss miss = missMap.get(key);\r
+               if(miss==null) {\r
+                       synchronized(missMap) {\r
+                               missMap.put(key, new Miss(bs,clean==null?MIN_INTERVAL:clean.timeInterval));\r
+                       }\r
+                       return true;\r
+               }\r
+               return miss.add(bs); \r
+       }\r
+\r
+       protected Miss missed(String key) {\r
+               return missMap.get(key);\r
+       }\r
+\r
+       protected User<PERM> getUser(String userName) {\r
+               User<PERM> u = userMap.get(userName);\r
+               if(u!=null) {\r
+                       u.incCount();\r
+               }\r
+               return u;\r
+       }\r
+       \r
+       protected User<PERM> getUser(Principal principal) {\r
+               return getUser(principal.getName()); \r
+       }\r
+       \r
+       /**\r
+        * Removes User from the Cache\r
+        * @param user\r
+        */\r
+       protected void remove(User<PERM> user) {\r
+               userMap.remove(user.principal.getName());\r
+       }\r
+       \r
+       /**\r
+        * Removes user from the Cache\r
+        * \r
+        * @param user\r
+        */\r
+       public void remove(String user) {\r
+               Object o = userMap.remove(user);\r
+               if(o!=null) {\r
+                       access.log(Level.INFO, user,"removed from Client Cache by Request");\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Clear all users from the Client Cache\r
+        */\r
+       public void clearAll() {\r
+               userMap.clear();\r
+       }\r
+       \r
+       public final List<DumpInfo> dumpInfo() {\r
+               List<DumpInfo> rv = new ArrayList<DumpInfo>();\r
+               for(User<PERM> user : userMap.values()) {\r
+                       rv.add(new DumpInfo(user));\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       /**\r
+        * The default behavior of a LUR is to not handle something exclusively.\r
+        */\r
+       public boolean handlesExclusively(Permission pond) {\r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Container calls when cleaning up... \r
+        * \r
+        * If overloading in Derived class, be sure to call "super.destroy()"\r
+        */\r
+       public void destroy() {\r
+               if(timer!=null) {\r
+                       timer.purge();\r
+                       timer.cancel();\r
+               }\r
+       }\r
+       \r
+       \r
+\r
+       // Simple map of Group name to a set of User Names\r
+       //      private Map<String, Set<String>> groupMap = new HashMap<String, Set<String>>();\r
+\r
+       /**\r
+        * Class to hold a small subset of the data, because we don't want to expose actual Permission or User Objects\r
+        */\r
+       public final class DumpInfo {\r
+               public String user;\r
+               public List<String> perms;\r
+               \r
+               public DumpInfo(User<PERM> user) {\r
+                       this.user = user.principal.getName();\r
+                       perms = new ArrayList<String>(user.perms.keySet());\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Clean will examine resources, and remove those that have expired.\r
+        * \r
+        * If "highs" have been exceeded, then we'll expire 10% more the next time.  This will adjust after each run\r
+        * without checking contents more than once, making a good average "high" in the minimum speed.\r
+        * \r
+        *\r
+        */\r
+       private final class Clean extends TimerTask {\r
+               private final Access access;\r
+               private CachingLur<PERM> lur;\r
+               \r
+               // The idea here is to not be too restrictive on a high, but to Expire more items by \r
+               // shortening the time to expire.  This is done by judiciously incrementing "advance"\r
+               // when the "highs" are exceeded.  This effectively reduces numbers of cached items quickly.\r
+               private final int high;\r
+               private long advance;\r
+               private final long timeInterval;\r
+               private final int usageTriggerCount;\r
+               \r
+               public Clean(Access access, long cleanInterval, int highCount, int usageTriggerCount) {\r
+                       this.access = access;\r
+                       lur = null;\r
+                       high = highCount;\r
+                       timeInterval = cleanInterval;\r
+                       advance = 0;\r
+                       this.usageTriggerCount=usageTriggerCount;\r
+               }\r
+               public void run() {\r
+                       int renewed = 0;\r
+                       int count = 0;\r
+                       int total = 0;\r
+                       try {\r
+                               // look at now.  If we need to expire more by increasing "now" by "advance"\r
+                               ArrayList<User<PERM>> al = new ArrayList<User<PERM>>(userMap.values().size());\r
+                               al.addAll(0, userMap.values());\r
+                               long now = System.currentTimeMillis() + advance;\r
+                               for(User<PERM> user : al) {\r
+                                       ++total;\r
+                                               if(user.count>usageTriggerCount) {\r
+       //                                              access.log(Level.AUDIT, "Checking Thread", new Date(now));\r
+                                                       boolean touched = false, removed=false;\r
+                                                       if(user.principal instanceof CachedPrincipal) {\r
+                                                               CachedPrincipal cp = (CachedPrincipal)user.principal;\r
+                                                               if(cp.expires() < now) {\r
+                                                                       switch(cp.revalidate()) {\r
+                                                                               case INACCESSIBLE:\r
+                                                                                       access.log(Level.AUDIT, "AAF Inaccessible.  Keeping credentials");\r
+                                                                                       break;\r
+                                                                               case REVALIDATED:\r
+                                                                                       user.resetCount();\r
+                       //                                                              access.log(Level.AUDIT, "CACHE revalidated credentials");\r
+                                                                                       touched = true;\r
+                                                                                       break;\r
+                                                                               default:\r
+                                                                                       user.resetCount();\r
+                                                                                       remove(user);\r
+                                                                                       ++count;\r
+                                                                                       removed = true;\r
+                                                                                       break;\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               \r
+       //                                              access.log(Level.AUDIT, "User Perm Expires", new Date(user.permExpires));\r
+                                                       if(!removed && lur!=null && user.permExpires<= now ) {\r
+       //                                                      access.log(Level.AUDIT, "Reloading");\r
+                                                               if(lur.reload(user).equals(Resp.REVALIDATED)) {\r
+                                                                       user.renewPerm();\r
+                                                                       access.log(Level.DEBUG, "Reloaded Perms for",user);\r
+                                                                       touched = true;\r
+                                                               }\r
+                                                       }\r
+                                                       user.resetCount();\r
+                                                       if(touched) {\r
+                                                               ++renewed;\r
+                                                       }\r
+       \r
+                                               } else {\r
+                                                       if(user.permExpired()) {\r
+                                                               remove(user);\r
+                                                               ++count;\r
+                                                       }\r
+                                               }\r
+                               }\r
+                               \r
+                               // Clean out Misses\r
+                               int missTotal = missMap.keySet().size();\r
+                               int miss = 0;\r
+                               if(missTotal>0) {\r
+                                       ArrayList<String> keys = new ArrayList<String>(missTotal);\r
+                                       keys.addAll(missMap.keySet());\r
+                                       for(String key : keys) {\r
+                                               Miss m = missMap.get(key);\r
+                                               if(m!=null && m.timestamp<System.currentTimeMillis()) {\r
+                                                       synchronized(missMap) {\r
+                                                               missMap.remove(key);\r
+                                                       }\r
+                                                       access.log(Level.INFO, key, "has been removed from Missed Credential Map (" + m.tries + " invalid tries)");\r
+                                                       ++miss;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               if(count+renewed+miss>0) {\r
+                                       access.log(Level.INFO, (lur==null?"Cache":lur.getClass().getSimpleName()), "removed",count,\r
+                                               "and renewed",renewed,"expired Permissions out of", total,"and removed", miss, "password misses out of",missTotal);\r
+                               }\r
+       \r
+                               // If High (total) is reached during this period, increase the number of expired services removed for next time.\r
+                               // There's no point doing it again here, as there should have been cleaned items.\r
+                               if(total>high) {\r
+                                       // advance cleanup by 10%, without getting greater than timeInterval.\r
+                                       advance = Math.min(timeInterval, advance+(timeInterval/10));\r
+                               } else {\r
+                                       // reduce advance by 10%, without getting lower than 0.\r
+                                       advance = Math.max(0, advance-(timeInterval/10));\r
+                               }\r
+                       } catch (Exception e) {\r
+                               access.log(Level.ERROR,e.getMessage());\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public static class Miss {\r
+               private static final int MAX_TRIES = 3;\r
+\r
+               long timestamp;\r
+               byte[][] array;\r
+\r
+               private long timetolive;\r
+\r
+               private int tries;\r
+               \r
+               public Miss(byte[] first, long timeInterval) {\r
+                       array = new byte[MAX_TRIES][];\r
+                       array[0]=first;\r
+                       timestamp = System.currentTimeMillis() + timeInterval;\r
+                       this.timetolive = timeInterval;\r
+                       tries = 1;\r
+               }\r
+               \r
+               public boolean mayContinue(byte[] bs) {\r
+                       if(++tries > MAX_TRIES) return false;\r
+                       for(byte[] a : array) {\r
+                               if(a==null)return true;\r
+                               if(equals(a,bs)) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+\r
+               public synchronized boolean add(byte[] bc) {\r
+                       if(++tries>MAX_TRIES)return false;\r
+                       timestamp = System.currentTimeMillis()+timetolive;\r
+                       for(int i=0;i<MAX_TRIES;++i) {\r
+                               if(array[i]==null) {\r
+                                       array[i]=bc;\r
+                                       return true; // add to array, and allow more tries\r
+                               } else if(equals(array[i],bc)) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       return false; // no more tries until cache cleared.\r
+               }\r
+               \r
+               private boolean equals(byte[] src, byte[] target) {\r
+                       if(target.length==src.length) {\r
+                               for(int j=0;j<src.length;++j) {\r
+                                       if(src[j]!=target[j]) return false;\r
+                               }\r
+                               return true; // same length and same chars\r
+                       }\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Report on state\r
+        */\r
+       public String toString() {\r
+               return getClass().getSimpleName() + \r
+                               " Cache:\n  Users Cached: " +\r
+                               userMap.size() +\r
+                               "\n  Misses Saved: " +\r
+                               missMap.size() +\r
+                               '\n';\r
+                               \r
+       }\r
+\r
+       public void clear(Principal p, StringBuilder sb) {\r
+               sb.append(toString());\r
+               userMap.clear();\r
+               missMap.clear();\r
+               access.log(Level.AUDIT, p.getName(),"has cleared User Cache in",getClass().getSimpleName());\r
+               sb.append("Now cleared\n");\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Access.java b/core/src/main/java/com/att/cadi/Access.java
new file mode 100644 (file)
index 0000000..34ae9d4
--- /dev/null
@@ -0,0 +1,173 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+/**\r
+ * Various Environments require different logging mechanisms, or at least allow\r
+ * for different ones. We need the Framework to be able to hook into any particular instance of logging\r
+ * mechanism, whether it be a Logging Object within a Servlet Context, or a direct library like log4j.\r
+ * This interface, therefore, allows maximum pluggability in a variety of different app styles.  \r
+ *  \r
+ *\r
+ */\r
+public interface Access {\r
+       // levels to use\r
+       public enum Level {\r
+               DEBUG(0x1), INFO(0x10), AUDIT(0x100), WARN(0x2000), ERROR(0x4000), INIT(0x8000),NONE(0XFFFF);\r
+               private final int bit;\r
+               \r
+               Level(int ord) {\r
+                       bit = ord;\r
+               }\r
+               \r
+               public boolean inMask(int mask) {\r
+                       return (mask & bit) == bit;\r
+               }\r
+               \r
+               public int addToMask(int mask) {\r
+                       return mask | bit;\r
+               }\r
+\r
+               public int delFromMask(int mask) {\r
+                       return mask & ~bit;\r
+               }\r
+\r
+               public int toggle(int mask) {\r
+                       if(inMask(mask)) {\r
+                               return delFromMask(mask);\r
+                       } else {\r
+                               return addToMask(mask);\r
+                       }\r
+               }\r
+\r
+\r
+               public int maskOf() {\r
+                       int mask=0;\r
+                       for(Level l : values()) {\r
+                               if(ordinal()<l.ordinal()) {\r
+                                       mask|=l.bit;\r
+                               }\r
+                       }\r
+                       return mask;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Write a variable list of Object's text via the toString() method with appropriate space, etc.\r
+        * @param elements\r
+        */\r
+       public void log(Level level, Object ... elements);\r
+\r
+       /**\r
+        * Printf mechanism for Access\r
+        * @param level\r
+        * @param fmt\r
+        * @param elements\r
+        */\r
+       public void printf(Level level, String fmt, Object ... elements);\r
+       \r
+       /** \r
+        * Check if message will log before constructing\r
+        * @param level\r
+        * @return\r
+        */\r
+       public boolean willLog(Level level);\r
+\r
+       /**\r
+        * Write the contents of an exception, followed by a variable list of Object's text via the \r
+        * toString() method with appropriate space, etc.\r
+        * \r
+        * The Loglevel is always "ERROR"\r
+        * \r
+        * @param elements\r
+        */\r
+       public void log(Exception e, Object ... elements);\r
+       \r
+       /**\r
+        * Set the Level to compare logging too\r
+        */\r
+       public void setLogLevel(Level level);\r
+               \r
+       /**\r
+        * It is important in some cases to create a class from within the same Classloader that created\r
+        * Security Objects.  Specifically, it's pretty typical for Web Containers to separate classloaders\r
+        * so as to allow Apps with different dependencies. \r
+        * @return\r
+        */\r
+       public ClassLoader classLoader();\r
+\r
+       public String getProperty(String string, String def);\r
+       \r
+       public void load(InputStream is) throws IOException;\r
+\r
+       /**\r
+        * if "anytext" is true, then decryption will always be attempted.  Otherwise, only if starts with \r
+        * Symm.ENC\r
+        * @param encrypted\r
+        * @param anytext\r
+        * @return\r
+        * @throws IOException\r
+        */\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException;\r
+\r
+       public static final Access NULL = new Access() {\r
+               public void log(Level level, Object... elements) {\r
+               }\r
+\r
+               @Override\r
+               public void printf(Level level, String fmt, Object... elements) {\r
+               }\r
+\r
+               public void log(Exception e, Object... elements) {\r
+               }\r
+\r
+               public ClassLoader classLoader() {\r
+                       return this.classLoader();\r
+               }\r
+\r
+               public String getProperty(String string, String def) {\r
+                       return null;\r
+               }\r
+\r
+               public void load(InputStream is) throws IOException {\r
+               }\r
+\r
+               public void setLogLevel(Level level) {\r
+               }\r
+\r
+               public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+                       return encrypted;\r
+               }\r
+\r
+               @Override\r
+               public boolean willLog(Level level) {\r
+                       return false;\r
+               }\r
+       };\r
+\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/BasicCred.java b/core/src/main/java/com/att/cadi/BasicCred.java
new file mode 100644 (file)
index 0000000..f2411c4
--- /dev/null
@@ -0,0 +1,37 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+/**\r
+ * An Interface for testing on Requests to see if we can get a User and Password\r
+ * It works for CadiWrap, but also, Container Specific Wraps (aka Tomcat) should also\r
+ * implement.\r
+ * \r
+ *\r
+ */\r
+public interface BasicCred extends GetCred {\r
+       public void setUser(String user);\r
+       public void setCred(byte[] passwd);\r
+       public String getUser();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/BufferedCadiWrap.java b/core/src/main/java/com/att/cadi/BufferedCadiWrap.java
new file mode 100644 (file)
index 0000000..cc9b40d
--- /dev/null
@@ -0,0 +1,81 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.IOException;\r
+import java.io.InputStreamReader;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+\r
+/**\r
+ * BufferedCadiWrap exists to additionally wrap the InputStream with a BufferedInputStream to engage the\r
+ * "mark()/release()" API of InputStream.\r
+ * \r
+ * This is a requirement for Re-Reading Content for brain-dead Middleware such as SOAP WS-Security.\r
+ * \r
+ * Framework needs to set the TafResp and Lur (typically) later in the \r
+ * \r
+ *\r
+ */\r
+public class BufferedCadiWrap extends CadiWrap {\r
+       private BufferedServletInputStream sis;\r
+       \r
+       public BufferedCadiWrap(HttpServletRequest request) {\r
+               super(request, null, null); // will need to set TafResp and Lur separately\r
+               sis = null;\r
+       }\r
+\r
+\r
+       // @Override\r
+       public BufferedServletInputStream getInputStream() throws IOException {\r
+//             System.out.println("getInputStream() from Buffered CadiWrap... sis = " + sis);\r
+//             try {\r
+//                     throw new Exception("OK, here's where we are...");\r
+//             } catch (Exception e) {\r
+//                     e.printStackTrace();\r
+//             }\r
+               if(sis==null) {\r
+                       sis = new BufferedServletInputStream(super.getInputStream());\r
+//             } else {\r
+//                     try {\r
+//                     System.out.println("sis has " + sis.buffered() + " buffered bytes, and reports " + sis.available() + " available");\r
+//                     } catch (Exception e) {\r
+//                             e.printStackTrace();\r
+//                     }\r
+               }\r
+               return sis;\r
+       }\r
+\r
+       // @Override\r
+       public BufferedReader getReader() throws IOException {\r
+//             System.out.println("getReader() from Buffered CadiWrap... sis = " + sis);\r
+//             try {\r
+//                     throw new Exception("OK, here's where we are...");\r
+//             } catch (Exception e) {\r
+//                     e.printStackTrace();\r
+//             }\r
+               return new BufferedReader(new InputStreamReader(getInputStream()));\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/BufferedServletInputStream.java b/core/src/main/java/com/att/cadi/BufferedServletInputStream.java
new file mode 100644 (file)
index 0000000..88114b2
--- /dev/null
@@ -0,0 +1,215 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import javax.servlet.ServletInputStream;\r
+\r
+/**\r
+ * BufferedServletInputStream\r
+ * \r
+ * There are cases in brain-dead middleware (SOAP) where they store routing information in the content.\r
+ * \r
+ * In HTTP, this requires reading the content from the InputStream which, of course, cannot be re-read.\r
+ * \r
+ * BufferedInputStream exists to implement the "Mark" protocols for Streaming, which will enable being \r
+ * re-read.  Unfortunately, J2EE chose to require a "ServletInputStream" as an abstract class, rather than\r
+ * an interface, which requires we create a delegating pattern, rather than the preferred inheriting pattern. \r
+ * \r
+ * Unfortunately, the standard "BufferedInputStream" cannot be used, because it simply creates a byte array\r
+ * in the "mark(int)" method of that size.  This is not appropriate for this application, because the Header \r
+ * can be potentially huge, and if a buffer was allocated to accommodate all possibilities, the cost of memory \r
+ * allocation would be too large for high performance transactions.\r
+ *\r
+ * \r
+ *\r
+ */\r
+public class BufferedServletInputStream extends ServletInputStream {\r
+       private static final int NONE = 0;\r
+       private static final int STORE = 1;\r
+       private static final int READ = 2;\r
+       \r
+       private InputStream is;\r
+       private int state = NONE;\r
+       private Capacitor capacitor;\r
+\r
+       public BufferedServletInputStream(InputStream is) {\r
+               this.is = is;\r
+               capacitor = null;\r
+       }\r
+\r
+\r
+       // @Override\r
+       public int read() throws IOException {\r
+               int value=-1;\r
+               if(capacitor==null) {\r
+                       value=is.read();\r
+               } else {\r
+                       switch(state) {\r
+                               case STORE:\r
+                                       value = is.read();\r
+                                       if(value>=0) {\r
+                                               capacitor.put((byte)value);\r
+                                       }\r
+                                       break;\r
+                               case READ:\r
+                                       value = capacitor.read();\r
+                                       if(value<0) {\r
+                                               capacitor.done();\r
+                                               capacitor=null; // all done with buffer\r
+                                               value = is.read();\r
+                                       }\r
+                       }\r
+               } \r
+               return value;\r
+       }\r
+\r
+       // @Override\r
+       public int read(byte[] b) throws IOException {\r
+               return read(b,0,b.length);\r
+       }\r
+\r
+\r
+       // @Override\r
+       public int read(byte[] b, int off, int len) throws IOException {\r
+               int count = -1;\r
+               if(capacitor==null) {\r
+                       count = is.read(b,off,len);\r
+               } else {\r
+                       switch(state) {\r
+                               case STORE:\r
+                                       count = is.read(b, off, len);\r
+                                       if(count>0) {\r
+                                               capacitor.put(b, off, count);\r
+                                       }\r
+                                       break;\r
+                               case READ:\r
+                                       count = capacitor.read(b, off, len);\r
+//                                     System.out.println("Capacitor read " + count);\r
+                                       if(count<=0) {\r
+                                               capacitor.done();\r
+                                               capacitor=null; // all done with buffer\r
+                                       }\r
+                                       if(count<len) {\r
+                                               int temp = is.read(b, count, len-count);\r
+//                                             System.out.println("Capacitor done, stream read " + temp);\r
+                                               if(temp>0) { // watch for -1\r
+                                                       count+=temp;\r
+                                               } else {\r
+                                                       if(count<=0)count = temp; // must account for Stream coming back -1  \r
+                                               }\r
+                                       }\r
+                                       break;\r
+                       }\r
+               }\r
+//             System.out.println("read reports " + count);\r
+               return count;\r
+       }\r
+\r
+       // @Override\r
+       public long skip(long n) throws IOException {\r
+               long skipped = capacitor.skip(n);\r
+               if(skipped<n) {\r
+                       skipped += is.skip(n-skipped);\r
+               }\r
+               return skipped;\r
+       }\r
+\r
+\r
+       // @Override\r
+       public int available() throws IOException {\r
+               int count = is.available();\r
+               if(capacitor!=null)count+=capacitor.available();\r
+               return count;           \r
+       }\r
+       \r
+       /**\r
+        * Return just amount buffered (for debugging purposes, mostly)\r
+        * @return\r
+        */\r
+       public int buffered() {\r
+               return capacitor.available();\r
+       }\r
+\r
+\r
+       // @Override\r
+       public void close() throws IOException {\r
+               if(capacitor!=null) {\r
+                       capacitor.done();\r
+                       capacitor=null;\r
+               }\r
+               is.close();\r
+       }\r
+\r
+\r
+       /**\r
+        * Note: Readlimit is ignored in this implementation, because the need was for unknown buffer size which wouldn't \r
+        * require allocating and dumping huge chunks of memory every use, or risk overflow.\r
+        */\r
+       // @Override\r
+       public synchronized void mark(int readlimit) {\r
+               switch(state) {\r
+                       case NONE:\r
+                               capacitor = new Capacitor();\r
+                               break;\r
+                       case READ:\r
+                               capacitor.done();\r
+                               break;\r
+                       // ignore case STORE:\r
+               }\r
+               state = STORE;\r
+       }\r
+\r
+\r
+       /**\r
+        * Reset Stream\r
+        * \r
+        * Calling this twice is not supported in typical Stream situations, but it is allowed in this service.  The caveat is that it can only reset\r
+        * the data read in since Mark has been called.  The data integrity is only valid if you have not continued to read past what is stored.\r
+        *  \r
+        */\r
+       // @Override\r
+       public synchronized void reset() throws IOException {\r
+               switch(state) {\r
+                       case STORE:\r
+                               capacitor.setForRead();\r
+                               state = READ;\r
+                               break;\r
+                       case READ:\r
+                               capacitor.reset();\r
+                               break;\r
+//                             throw new IOException("InputStream is already in READ state");\r
+                       case NONE: \r
+                               throw new IOException("InputStream has not been marked");\r
+               }\r
+       }\r
+\r
+\r
+       // @Override\r
+       public boolean markSupported() {\r
+               return true;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CachedPrincipal.java b/core/src/main/java/com/att/cadi/CachedPrincipal.java
new file mode 100644 (file)
index 0000000..741d579
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+\r
+/**\r
+ * Cached Principals need to be able to revalidate in the background.\r
+ * \r
+ *\r
+ */\r
+public interface CachedPrincipal extends Principal {\r
+       public enum Resp {NOT_MINE,UNVALIDATED,REVALIDATED,INACCESSIBLE,DENIED};\r
+       \r
+       /**\r
+        * Re-validate with Creator\r
+        * \r
+        * @return\r
+        */\r
+       public abstract Resp revalidate();\r
+       \r
+       /**\r
+        * Store when last updated.\r
+        * @return\r
+        */\r
+       public abstract long expires();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CachingLur.java b/core/src/main/java/com/att/cadi/CachingLur.java
new file mode 100644 (file)
index 0000000..b7a194f
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+\r
+\r
+public interface CachingLur<PERM extends Permission> extends Lur {\r
+       public abstract void remove(String user);\r
+       public abstract Resp reload(User<PERM> user);\r
+       public abstract void setDebug(String commaDelimIDsOrNull);\r
+       public abstract void clear(Principal p, StringBuilder sb);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CadiException.java b/core/src/main/java/com/att/cadi/CadiException.java
new file mode 100644 (file)
index 0000000..123b394
--- /dev/null
@@ -0,0 +1,51 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+/**\r
+ * CADI Specific Exception\r
+ */\r
+public class CadiException extends Exception {\r
+       /**\r
+        *  Generated ID \r
+        */\r
+       private static final long serialVersionUID = -4180145363107742619L;\r
+\r
+       public CadiException() {\r
+               super();\r
+       }\r
+\r
+       public CadiException(String message) {\r
+               super(message);\r
+       }\r
+\r
+       public CadiException(Throwable cause) {\r
+               super(cause);\r
+       }\r
+\r
+       public CadiException(String message, Throwable cause) {\r
+               super(message, cause);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CadiWrap.java b/core/src/main/java/com/att/cadi/CadiWrap.java
new file mode 100644 (file)
index 0000000..1961c6e
--- /dev/null
@@ -0,0 +1,194 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletRequestWrapper;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.filter.NullPermConverter;\r
+import com.att.cadi.filter.PermConverter;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.taf.TafResp;\r
+\r
+\r
+\r
+/**\r
+ * Inherit the HttpServletRequestWrapper, which calls methods of delegate it's created with, but\r
+ * overload the key security mechanisms with CADI mechanisms\r
+ * \r
+ * This works with mechanisms working strictly with HttpServletRequest (i.e. Servlet Filters)\r
+ * \r
+ * Specialty cases, i.e. Tomcat, which for their containers utilize their own mechanisms and Wrappers, you may\r
+ * need something similar.  See AppServer specific code (i.e. tomcat) for these.\r
+ * \r
+ *\r
+ */\r
+public class CadiWrap extends HttpServletRequestWrapper implements HttpServletRequest, BasicCred {\r
+       private Principal principal;\r
+       private Lur lur;\r
+       private String user; // used to set user/pass from brain-dead protocols like WSSE \r
+       private byte[] password;\r
+       private PermConverter pconv;\r
+       private Access access; \r
+       \r
+       /**\r
+        * Standard Wrapper constructor for Delegate pattern\r
+        * @param request\r
+        */\r
+       public CadiWrap(HttpServletRequest request, TafResp tafResp, Lur lur) {\r
+               super(request);\r
+               principal = tafResp.getPrincipal();\r
+               access = tafResp.getAccess();\r
+               this.lur = lur;\r
+               pconv = NullPermConverter.singleton();\r
+       }\r
+\r
+       /**\r
+        * Standard Wrapper constructor for Delegate pattern, with PermConverter\r
+        * @param request\r
+        */\r
+       public CadiWrap(HttpServletRequest request, TafResp tafResp, Lur lur, PermConverter pc) {\r
+               super(request);\r
+               principal = tafResp.getPrincipal();\r
+               access = tafResp.getAccess();\r
+               this.lur = lur;\r
+               pconv = pc;\r
+       }\r
+\r
+\r
+       /**\r
+        * Part of the HTTP Security API.  Declare the User associated with this HTTP Transaction.\r
+        * CADI does this by reporting the name associated with the Principal obtained, if any.\r
+        */\r
+// @Override\r
+       public String getRemoteUser() {\r
+               return principal==null?null:principal.getName();\r
+       }\r
+\r
+       /**\r
+        * Part of the HTTP Security API.  Return the User Principal associated with this HTTP \r
+        * Transaction.\r
+        */\r
+// @Override\r
+       public Principal getUserPrincipal() {\r
+               return principal;\r
+       }\r
+       \r
+       /**\r
+        * This is the key API call for AUTHZ in J2EE.  Given a Role (String passed in), is the user\r
+        * associated with this HTTP Transaction allowed to function in this Role?\r
+        * \r
+        * For CADI, we pass the responsibility for determining this to the "LUR", which may be\r
+        * determined by the Enterprise.\r
+        * \r
+        * Note: Role check is also done in "CadiRealm" in certain cases...\r
+        * \r
+        *\r
+        */\r
+// @Override\r
+       public boolean isUserInRole(String perm) {\r
+               return perm==null?false:checkPerm(access,"(HttpRequest)",principal,pconv,lur,perm);\r
+       }\r
+       \r
+       public static boolean checkPerm(Access access, String caller, Principal principal, PermConverter pconv, Lur lur, String perm) {\r
+               if(principal== null) {\r
+                       access.log(Level.AUDIT,caller, "No Principal in Transaction");\r
+                       return false;\r
+               } else { \r
+                       perm = pconv.convert(perm);\r
+                       if(lur.fish(principal,lur.createPerm(perm))) {\r
+                               access.log(Level.DEBUG,caller, principal.getName(), "has", perm);\r
+                               return true;\r
+                       } else {\r
+                               access.log(Level.DEBUG,caller, principal.getName(), "does not have", perm);\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+       /** \r
+        * CADI Function (Non J2EE standard). GetPermissions will read the Permissions from AAF (if configured) and Roles from Local Lur, etc\r
+        *  as implemented with lur.fishAll\r
+        *  \r
+        *  To utilize, the Request must be a "CadiWrap" object, then call.\r
+        */\r
+       public List<Permission> getPermissions(Principal p) {\r
+               List<Permission> perms = new ArrayList<Permission>();\r
+               lur.fishAll(p, perms);\r
+               return perms;\r
+       }\r
+       /**\r
+        * Allow setting of tafResp and lur after construction\r
+        * \r
+        * This can happen if the CadiWrap is constructed in a Valve other than CadiValve\r
+        */\r
+       public void set(TafResp tafResp, Lur lur) {\r
+               principal = tafResp.getPrincipal();\r
+               access = tafResp.getAccess();\r
+               this.lur = lur;\r
+       }\r
+\r
+       public String getUser() {\r
+               if(user==null && principal!=null) {\r
+                       user = principal.getName();\r
+               }\r
+               return user;\r
+       }\r
+\r
+       public byte[] getCred() {\r
+               return password;\r
+       }\r
+\r
+       public void setUser(String user) {\r
+               this.user = user;\r
+       }\r
+\r
+       public void setCred(byte[] passwd) {\r
+               password = passwd;\r
+       }\r
+       \r
+       public CadiWrap setPermConverter(PermConverter pc) {\r
+               pconv = pc;\r
+               return this;\r
+       }\r
+       \r
+       // Add a feature\r
+       public void invalidate(String id) {\r
+               if(lur instanceof EpiLur) {\r
+                       ((EpiLur)lur).remove(id);\r
+               } else if(lur instanceof CachingLur) {\r
+                       ((CachingLur<?>)lur).remove(id);\r
+               }\r
+       }\r
+       \r
+       public Lur getLur() {\r
+               return lur;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Capacitor.java b/core/src/main/java/com/att/cadi/Capacitor.java
new file mode 100644 (file)
index 0000000..0745875
--- /dev/null
@@ -0,0 +1,241 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.nio.ByteBuffer;\r
+import java.util.ArrayList;\r
+\r
+/**\r
+ * Capacitor\r
+ * \r
+ * Storage mechanism for read data, specifically designed for InputStreams.\r
+ * \r
+ * The Standard BufferedInputStream requires a limit to be set for buffered reading, which is \r
+ * impractical for reading SOAP headers, which can be quite large.\r
+ *\r
+ */\r
+public class Capacitor {\r
+       private static final int DEFAULT_CHUNK = 256;\r
+       private ArrayList<ByteBuffer> bbs = new ArrayList<ByteBuffer>();\r
+       private ByteBuffer curr = null;\r
+       private int idx;\r
+       \r
+       // Maintain a private RingBuffer for Memory, for efficiency\r
+       private static ByteBuffer[] ring = new ByteBuffer[16];\r
+       private static int start, end;\r
+       \r
+       \r
+       public void put(byte b) {\r
+               if(curr == null || curr.remaining()==0) { // ensure we have a "curr" buffer ready for data\r
+                       curr = ringGet();\r
+                       bbs.add(curr);\r
+               }\r
+               curr.put(b); \r
+       }\r
+\r
+       public int read() {\r
+               if(curr!=null) { \r
+                       if(curr.remaining()>0) { // have a buffer, use it!\r
+                               return curr.get();\r
+                       } else if(idx<bbs.size()){ // Buffer not enough, get next one from array\r
+                               if(idx<bbs.size()) {\r
+                                       curr=bbs.get(idx++);\r
+                                       return curr.get();\r
+                               }\r
+                       }\r
+               } // if no curr buffer, treat as end of stream\r
+               return -1;\r
+       }\r
+       \r
+       /**\r
+        * read into an array like Streams\r
+        * \r
+        * @param array\r
+        * @param offset\r
+        * @param length\r
+        * @return\r
+        */\r
+       public int read(byte[] array, int offset, int length) {\r
+               if(curr==null)return -1;\r
+               int len;\r
+               int count=0;\r
+               while(length>0) { // loop through while there's data needed\r
+                       if((len=curr.remaining())>length) { //  if enough data in curr buffer, use this code\r
+                               curr.get(array,offset,length);\r
+                               count+=length;\r
+                               length=0;\r
+                       } else {  // get data from curr, mark how much is needed to fulfil, and loop for next curr.\r
+                               curr.get(array,offset,len);\r
+                               count+=len;\r
+                               offset+=len;\r
+                               length-=len;\r
+                               if(idx<bbs.size()) {\r
+                                       curr=bbs.get(idx++);\r
+                               } else {\r
+                                       length=0; // stop, and return the count of how many we were able to load\r
+                               }\r
+                       }\r
+               }\r
+               return count;\r
+       }\r
+\r
+       /**\r
+        * Put an array of data into Capacitor\r
+        * \r
+        * @param array\r
+        * @param offset\r
+        * @param length\r
+        */\r
+       public void put(byte[] array, int offset, int length) {\r
+               if(curr == null || curr.remaining()==0) {\r
+                       curr = ringGet();\r
+                       bbs.add(curr);\r
+               }\r
+               \r
+               int len;\r
+               while(length>0) {\r
+                       if((len=curr.remaining())>length) {\r
+                               curr.put(array,offset,length);\r
+                               length=0;\r
+                       } else {\r
+//                             System.out.println(new String(array));\r
+                               curr.put(array,offset,len);\r
+                               length-=len;\r
+                               offset+=len;\r
+                               curr = ringGet();\r
+                               bbs.add(curr);\r
+                       }\r
+               }\r
+       }\r
+        \r
+       /**\r
+        * Move state from Storage mode into Read mode, changing all internal buffers to read mode, etc\r
+        */\r
+       public void setForRead() {\r
+               for(ByteBuffer bb : bbs) {\r
+                       bb.flip();\r
+               }\r
+               if(bbs.isEmpty()) {\r
+                       curr = null;\r
+                       idx = 0;\r
+               } else {\r
+                       curr=bbs.get(0);\r
+                       idx=1;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * reuse all the buffers\r
+        */\r
+       public void done() {\r
+               for(ByteBuffer bb : bbs) {\r
+                       ringPut(bb);\r
+               }\r
+               bbs.clear();\r
+               curr = null;\r
+       }\r
+       \r
+       /**\r
+        * Declare amount of data available to be read at once.\r
+        * \r
+        * @return\r
+        */\r
+       public int available() {\r
+               int count = 0;\r
+               for(ByteBuffer bb : bbs) {\r
+                       count+=bb.remaining();\r
+               }\r
+               return count;\r
+       }\r
+       \r
+       /**\r
+        * Returns how many are left that were not skipped\r
+        * @param n\r
+        * @return\r
+        */\r
+       public long skip(long n) {\r
+               long skipped=0L;\r
+               int skip;\r
+               while(n>0) {\r
+                       if(n<(skip=curr.remaining())) {\r
+                               curr.position(curr.position()+(int)n);\r
+                               skipped+=skip;\r
+                               n=0;\r
+                       } else {\r
+                               curr.position(curr.limit());\r
+                               \r
+                               skipped-=skip;\r
+                               if(idx<bbs.size()) {\r
+                                       curr=bbs.get(idx++);\r
+                                       n-=skip;\r
+                               } else {\r
+                                       n=0;\r
+                               }\r
+                       }\r
+               }\r
+               return skipped;\r
+       }\r
+       /**\r
+        * Be able to re-read data that is stored that has already been re-read.  This is not a standard Stream behavior, but can be useful\r
+        * in a standalone mode.\r
+        */\r
+       public void reset() {\r
+               for(ByteBuffer bb : bbs) {\r
+                       bb.position(0);\r
+               }\r
+               if(bbs.isEmpty()) {\r
+                       curr = null;\r
+                       idx = 0;\r
+               } else {\r
+                       curr=bbs.get(0);\r
+                       idx=1;\r
+               }\r
+       }\r
+\r
+       /*\r
+        * Ring Functions.  Reuse allocated memory \r
+        */\r
+       private ByteBuffer ringGet() {\r
+               ByteBuffer bb = null;\r
+               synchronized(ring) {\r
+                       bb=ring[start];\r
+                       ring[start]=null;\r
+                       if(bb!=null && ++start>15)start=0;\r
+               }\r
+               if(bb==null) {\r
+                       bb=ByteBuffer.allocate(DEFAULT_CHUNK);\r
+               } else {\r
+                       bb.clear();// refresh reused buffer\r
+               }\r
+               return bb;\r
+       }\r
+       \r
+       private void ringPut(ByteBuffer bb) {\r
+               synchronized(ring) {\r
+                       ring[end]=bb; // if null or not, BB will just be Garbage collected\r
+                       if(++end>15)end=0;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CmdLine.java b/core/src/main/java/com/att/cadi/CmdLine.java
new file mode 100644 (file)
index 0000000..2d19234
--- /dev/null
@@ -0,0 +1,357 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.io.InputStreamReader;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.security.NoSuchAlgorithmException;\r
+\r
+import com.att.cadi.util.Chmod;\r
+import com.att.cadi.util.JsonOutputStream;\r
+\r
+\r
+\r
+/**\r
+ * A Class to run on command line to determine suitability of environment for certain TAFs.\r
+ * \r
+ * For instance, CSP supports services only in certain domains, and while dynamic host\r
+ * lookups on the machine work in most cases, sometimes, names and IPs are unexpected (and\r
+ * invalid) for CSP because of multiple NetworkInterfaces, etc\r
+ * \r
+ *\r
+ */\r
+public class CmdLine {\r
+\r
+       /**\r
+        * @param args\r
+        */\r
+       public static void main(String[] args) {\r
+               if(args.length>0) {\r
+                       if("digest".equalsIgnoreCase(args[0]) && (args.length>2 || (args.length>1 && System.console()!=null))) {\r
+                               String keyfile;\r
+                               String password;\r
+                               if(args.length>2) {\r
+                                       password = args[1];\r
+                                       keyfile = args[2];\r
+                               } else {\r
+                                       keyfile = args[1];\r
+                                       password = new String(System.console().readPassword("Type here (keystrokes hidden): "));\r
+                               }\r
+\r
+                               try {\r
+                                       Symm symm;\r
+                                       FileInputStream fis = new FileInputStream(keyfile);\r
+                                       try {\r
+                                               symm = Symm.obtain(fis);\r
+                                       } finally {\r
+                                               fis.close();\r
+                                       }\r
+                                       symm.enpass(password, System.out);\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                                       /*  testing code... don't want it exposed\r
+                                       System.out.println(" ******** Testing *********");\r
+                                       for(int i=0;i<100000;++i) {\r
+                                               System.out.println(args[1]);\r
+                                               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+                                               b64.enpass(args[1], baos);\r
+                                               String pass; \r
+                                               System.out.println(pass=new String(baos.toByteArray()));\r
+                                               ByteArrayOutputStream reconstituted = new ByteArrayOutputStream();\r
+                                               b64.depass(pass, reconstituted);\r
+                                               String r = reconstituted.toString();\r
+                                               System.out.println(r);\r
+                                               if(!r.equals(args[1])) {\r
+                                                       System.err.println("!!!!! STOP - ERROR !!!!!");\r
+                                                       return;\r
+                                               }\r
+                                               System.out.println();\r
+                                       }\r
+                                       System.out.flush();\r
+                                       */\r
+                                        \r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot digest password");\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+// .  Oh, well, Deployment services need this behavior.  I will put this code in, but leave it undocumented. \r
+// One still needs access to the keyfile to read.\r
+// July 2016 - thought of a tool "CMPass" to reguritate from properties, but only if allowed.\r
+                       } else if("regurgitate".equalsIgnoreCase(args[0]) && args.length>2) {\r
+                               try {\r
+                                       Symm symm;\r
+                                       FileInputStream fis = new FileInputStream(args[2]);\r
+                                       try {\r
+                                               symm = Symm.obtain(fis);\r
+                                       } finally {\r
+                                               fis.close();\r
+                                       }\r
+                                       boolean isFile = false;\r
+                                       if("-i".equals(args[1]) || (isFile="-f".equals(args[1]))) {\r
+                                               BufferedReader br;\r
+                                               if(isFile) {\r
+                                                       if(args.length<4) {\r
+                                                               System.err.println("Filename in 4th position");\r
+                                                               return;\r
+                                                       }\r
+                                                       br = new BufferedReader(new FileReader(args[3]));\r
+                                               } else {\r
+                                                       br = new BufferedReader(new InputStreamReader(System.in));\r
+                                               }\r
+                                               try {\r
+                                                       String line;\r
+                                                       boolean cont = false;\r
+                                                       StringBuffer sb = new StringBuffer();\r
+                                                       JsonOutputStream jw = new JsonOutputStream(System.out);\r
+                                                       while((line=br.readLine())!=null) {\r
+                                                               if(cont) {\r
+                                                                       int end;\r
+                                                                       if((end=line.indexOf('"'))>=0) {\r
+                                                                               sb.append(line,0,end);\r
+                                                                               cont=false;\r
+                                                                       } else {\r
+                                                                               sb.append(line);\r
+                                                                       }\r
+                                                               } else {\r
+                                                                       int idx;\r
+                                                                       if((idx = line.indexOf(' '))>=0 \r
+                                                                                       && (idx = line.indexOf(' ',++idx))>0\r
+                                                                                       && (idx = line.indexOf('=',++idx))>0\r
+                                                                                       && (idx = line.indexOf('=',++idx))>0\r
+                                                                                       ) {\r
+                                                                               System.out.println(line.substring(0, idx-5));\r
+                                                                               int start = idx+2;\r
+                                                                               int end;\r
+                                                                               if((end=line.indexOf('"',start))<0) {\r
+                                                                                       end = line.length();\r
+                                                                                       cont = true;\r
+                                                                               }\r
+                                                                               sb.append(line,start,end);\r
+                                                                       }\r
+                                                               }\r
+                                                               if(sb.length()>0) {\r
+                                                                       symm.depass(sb.toString(),jw);\r
+                                                                       if(!cont) {\r
+                                                                               System.out.println();\r
+                                                                       }\r
+                                                               }\r
+                                                               System.out.flush();\r
+                                                               sb.setLength(0);\r
+                                                               if(!cont) {\r
+                                                                       jw.resetIndent();\r
+                                                               }\r
+                                                       }\r
+                                               } finally {\r
+                                                       if(isFile) {\r
+                                                               br.close();\r
+                                                       }\r
+                                               }\r
+                                       } else {\r
+                                               symm.depass(args[1], System.out);\r
+                                       }\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot regurgitate password");\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       } else if("encode64".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       Symm.base64.encode(args[1], System.out);\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot encode Base64 with " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       } else if("decode64".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       Symm.base64.decode(args[1], System.out);\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot decode Base64 text from " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       } else if("encode64url".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       Symm.base64url.encode(args[1], System.out);\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot encode Base64url with " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       } else if("decode64url".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       Symm.base64url.decode(args[1], System.out);\r
+                                       System.out.println();\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot decode Base64url text from " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       } else if("md5".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       System.out.println(Hash.encryptMD5asStringHex(args[1]));\r
+                                       System.out.flush();\r
+                               } catch (NoSuchAlgorithmException e) {\r
+                                       System.err.println("Cannot hash MD5 from " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                               return;\r
+                       } else if("sha256".equalsIgnoreCase(args[0]) && args.length>1) {\r
+                               try {\r
+                                       if(args.length>2) {\r
+                                               int salt = Integer.parseInt(args[2]);\r
+                                               System.out.println(Hash.hashSHA256asStringHex(args[1],salt));\r
+                                       } else { \r
+                                               System.out.println(Hash.hashSHA256asStringHex(args[1]));\r
+                                       }\r
+                               } catch (NoSuchAlgorithmException e) {\r
+                                       System.err.println("Cannot hash SHA256 text from " + args[1]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                               System.out.flush();\r
+                               return;\r
+                       } else if("keygen".equalsIgnoreCase(args[0])) {\r
+                               try {\r
+                                       if(args.length>1) {\r
+                                               File f = new File(args[1]);\r
+                                               FileOutputStream fos = new FileOutputStream(f);\r
+                                               try {\r
+                                                       fos.write(Symm.baseCrypt().keygen());\r
+                                                       fos.flush();\r
+                                               } finally {\r
+                                                       fos.close();\r
+                                                       Chmod.to400.chmod(f);\r
+                                               }\r
+                                       } else {\r
+                                               // create a Symmetric Key out of same characters found in base64\r
+                                               System.out.write(Symm.baseCrypt().keygen());\r
+                                               System.out.flush();\r
+                                       }\r
+                                       return;\r
+                               } catch (IOException e) {\r
+                                       System.err.println("Cannot create a key " + args[0]);\r
+                                       System.err.println("   \""+ e.getMessage() + '"');\r
+                               }\r
+                       \r
+                       } else if("passgen".equalsIgnoreCase(args[0])) {\r
+                               int numDigits;\r
+                               if(args.length <= 1) {\r
+                                       numDigits = 24;\r
+                               } else {\r
+                                       numDigits = Integer.parseInt(args[1]); \r
+                                       if(numDigits<8)numDigits = 8;\r
+                               }\r
+                               String pass;\r
+                               boolean noLower,noUpper,noDigits,noSpecial,repeats;\r
+                               do {\r
+                                       pass = Symm.randomGen(numDigits);\r
+                                       noLower=noUpper=noDigits=noSpecial=true;\r
+                                       repeats=false;\r
+                                       int c=-1,last;\r
+                                       for(int i=0;i<numDigits;++i) {\r
+                                               last = c;\r
+                                               c = pass.charAt(i);\r
+                                               if(c==last) {\r
+                                                       repeats=true;\r
+                                                       break;\r
+                                               }\r
+                                               \r
+                                               if(noLower) {\r
+                                                       noLower=!(c>=0x61 && c<=0x7A);\r
+                                                       continue;\r
+                                               } \r
+                                               if(noUpper) {\r
+                                                       noUpper=!(c>=0x41 && c<=0x5A);\r
+                                                       continue;\r
+                                               } \r
+                                               if(noDigits) {\r
+                                                       noDigits=!(c>=0x30 && c<=0x39);\r
+                                                       continue;\r
+                                               } \r
+                                               if(noSpecial) {\r
+                                                       noSpecial = "+!@#$%^&*(){}[]?:;,.".indexOf(c)<0;\r
+                                                       continue;\r
+                                               } \r
+                                               \r
+                                               break;\r
+                                       }\r
+                               } while(noLower || noUpper || noDigits || noSpecial || repeats);\r
+                               System.out.println(pass.substring(0,numDigits));\r
+                       } else if("urlgen".equalsIgnoreCase(args[0])) {\r
+                               int numDigits;\r
+                               if(args.length < 1) {\r
+                                       numDigits = 24;\r
+                               } else {\r
+                                       numDigits = Integer.parseInt(args[1]); \r
+                               }\r
+                               System.out.println(Symm.randomGen(Symm.base64url.codeset, numDigits).substring(0,numDigits));\r
+                       \r
+                       } else if("csptest".equalsIgnoreCase(args[0])) {\r
+                               try {\r
+                                       System.out.println("CSP Compatibility test");\r
+                                       \r
+                                       String hostName = InetAddress.getLocalHost().getCanonicalHostName();\r
+                                       \r
+                                       System.out.println("  Your automatic hostname is reported as \"" + hostName + "\"\n");\r
+                                       System.out.flush();\r
+                                       return;\r
+                               } catch (UnknownHostException e) {\r
+                                       e.printStackTrace(System.err);\r
+                               }\r
+                       }\r
+               } else {\r
+                       System.out.println("Usage: java -jar <this jar> ...");\r
+                       System.out.println("  keygen [<keyfile>]                     (Generates Key on file, or Std Out)");\r
+                       System.out.println("  digest <keyfile>                       (Encrypts to Key with \"keyfile\")");\r
+                       System.out.println("  passgen <digits>                       (Generate Password of given size)");\r
+                       System.out.println("  urlgen <digits>                        (Generate URL field of given size)");\r
+                       System.out.println("  csptest                                (Tests for CSP compatibility)");\r
+                       System.out.println("  encode64 <your text>                   (Encodes to Base64)");\r
+                       System.out.println("  decode64 <base64 encoded text>         (Decodes from Base64)");\r
+                       System.out.println("  encode64url <your text>                (Encodes to Base64 URL charset)");\r
+                       System.out.println("  decode64url <base64url encoded text>   (Decodes from Base64 URL charset)");\r
+                       System.out.println("  sha256 <text>                          (Digest String into SHA256 Hash)");\r
+                       System.out.println("  md5 <text>                             (Digest String into MD5 Hash)");\r
+               }\r
+               System.exit(1);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Connector.java b/core/src/main/java/com/att/cadi/Connector.java
new file mode 100644 (file)
index 0000000..4f5576d
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+public interface Connector {\r
+       public Lur newLur() throws CadiException;\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/CredVal.java b/core/src/main/java/com/att/cadi/CredVal.java
new file mode 100644 (file)
index 0000000..040781d
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+/**\r
+ * UserPass\r
+ * \r
+ * The essential interface required by BasicAuth to determine if a given User/Password combination is \r
+ * valid.  This is done as an interface.\r
+ * \r
+ */\r
+public interface CredVal {\r
+       public enum Type{PASSWORD};\r
+       /**\r
+        *  Validate if the User/Password combination matches records \r
+        * @param user\r
+        * @param pass\r
+        * @return\r
+        */\r
+       public boolean validate(String user, Type type, byte[] cred);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/GetCred.java b/core/src/main/java/com/att/cadi/GetCred.java
new file mode 100644 (file)
index 0000000..f5289f0
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+public interface GetCred {\r
+       byte[] getCred();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Hash.java b/core/src/main/java/com/att/cadi/Hash.java
new file mode 100644 (file)
index 0000000..190049f
--- /dev/null
@@ -0,0 +1,203 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.nio.ByteBuffer;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+\r
+public class Hash {\r
+       private static char hexDigit[] = "0123456789abcdef".toCharArray();\r
+       \r
+/////////////////////////////////\r
+// MD5\r
+/////////////////////////////////\r
+       /**\r
+        * Encrypt MD5 from Byte Array to Byte Array\r
+        * @param input\r
+        * @return\r
+        * @throws NoSuchAlgorithmException\r
+        */\r
+       public static byte[] encryptMD5 (byte[] input) throws NoSuchAlgorithmException {\r
+               MessageDigest md = MessageDigest.getInstance("MD5");\r
+               md.update(input); \r
+               return md.digest();\r
+       }\r
+\r
+       /**\r
+        * Encrypt MD5 from Byte Array to Byte Array\r
+        * @param input\r
+        * @return\r
+        * @throws NoSuchAlgorithmException\r
+        */\r
+       public static byte[] encryptMD5 (byte[] input, int offset, int length) throws NoSuchAlgorithmException {\r
+               MessageDigest md = MessageDigest.getInstance("MD5");\r
+               md.update(input,offset,length); \r
+               return md.digest();\r
+       }\r
+\r
+\r
+\r
+       /**\r
+        * Convenience Function: Encrypt MD5 from String to String Hex representation \r
+        * \r
+        * @param input\r
+        * @return\r
+        * @throws NoSuchAlgorithmException\r
+        */\r
+       public static String encryptMD5asStringHex(String input) throws NoSuchAlgorithmException {\r
+               byte[] output = encryptMD5(input.getBytes());\r
+               StringBuilder sb = new StringBuilder("0x");\r
+                for (byte b : output) {\r
+                   sb.append(hexDigit[(b >> 4) & 0x0f]);\r
+                   sb.append(hexDigit[b & 0x0f]);\r
+                }\r
+                return sb.toString();\r
+       }\r
+\r
+/////////////////////////////////\r
+// SHA256\r
+/////////////////////////////////\r
+       /**\r
+        * SHA256 Hashing\r
+        */\r
+       public static byte[] hashSHA256(byte[] input) throws NoSuchAlgorithmException {\r
+               MessageDigest md = MessageDigest.getInstance("SHA-256");\r
+               md.update(input); \r
+               return md.digest();\r
+       }\r
+\r
+       /**\r
+        * SHA256 Hashing\r
+        */\r
+       public static byte[] hashSHA256(byte[] input, int offset, int length) throws NoSuchAlgorithmException {\r
+               MessageDigest md = MessageDigest.getInstance("SHA-256");\r
+               md.update(input,offset,length); \r
+               return md.digest();\r
+       }\r
+       \r
+       /**\r
+        * Convenience Function: Hash from String to String Hex representation\r
+        * \r
+        * @param input\r
+        * @return\r
+        * @throws NoSuchAlgorithmException\r
+        */\r
+       public static String hashSHA256asStringHex(String input) throws NoSuchAlgorithmException {\r
+               byte[] output = hashSHA256(input.getBytes());\r
+               StringBuilder sb = new StringBuilder("0x");\r
+                for (byte b : output) {\r
+                   sb.append(hexDigit[(b >> 4) & 0x0f]);\r
+                   sb.append(hexDigit[b & 0x0f]);\r
+                }\r
+                return sb.toString();\r
+       }\r
+\r
+       /**\r
+        * Convenience Function: Hash from String to String Hex representation\r
+        * \r
+        * @param input\r
+        * @return\r
+        * @throws NoSuchAlgorithmException\r
+        */\r
+       public static String hashSHA256asStringHex(String input, int salt) throws NoSuchAlgorithmException {\r
+               byte[] in = input.getBytes();\r
+               ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + in.length);\r
+               bb.putInt(salt);\r
+               bb.put(input.getBytes());\r
+               byte[] output = Hash.hashSHA256(bb.array());\r
+               StringBuilder sb = new StringBuilder("0x");\r
+                for (byte b : output) {\r
+                   sb.append(hexDigit[(b >> 4) & 0x0f]);\r
+                   sb.append(hexDigit[b & 0x0f]);\r
+                }\r
+                return sb.toString();\r
+       }\r
+       \r
+       /**\r
+        * Compare two byte arrays for equivalency\r
+        * @param ba1\r
+        * @param ba2\r
+        * @return\r
+        */\r
+       public static boolean isEqual(byte ba1[], byte ba2[]) {\r
+               if(ba1.length!=ba2.length)return false;\r
+               for(int i = 0;i<ba1.length; ++i) {\r
+                       if(ba1[i]!=ba2[i])return false;\r
+               }\r
+               return true;\r
+       }\r
+\r
+       public static int compareTo(byte[] a, byte[] b) {\r
+               int end = Math.min(a.length, b.length);\r
+               int compare = 0;\r
+               for(int i=0;compare == 0 && i<end;++i) {\r
+                       compare = a[i]-b[i];\r
+               }\r
+               if(compare==0)compare=a.length-b.length;\r
+               return compare;\r
+       }\r
+       \r
+       public static String toHex(byte[] ba) {\r
+               StringBuilder sb = new StringBuilder("0x");\r
+                for (byte b : ba) {\r
+                   sb.append(hexDigit[(b >> 4) & 0x0f]);\r
+                   sb.append(hexDigit[b & 0x0f]);\r
+                }\r
+                return sb.toString();\r
+       }\r
+       \r
+       public static byte[] fromHex(String s)  throws CadiException{\r
+               if(!s.startsWith("0x")) {\r
+                       throw new CadiException("HexString must start with \"0x\"");\r
+               }\r
+               boolean high = true;\r
+               int c;\r
+               byte b;\r
+               byte[] ba = new byte[(s.length()-2)/2];\r
+               int idx;\r
+               for(int i=2;i<s.length();++i) {\r
+                       c = s.charAt(i);\r
+                       if(c>=0x30 && c<=0x39) {\r
+                               b=(byte)(c-0x30);\r
+                       } else if(c>=0x61 && c<=0x66) {\r
+                               b=(byte)(c-0x57);  // account for "A"\r
+                       } else if(c>=0x41 && c<=0x46) {\r
+                               b=(byte)(c-0x37);\r
+                       } else {\r
+                               throw new CadiException("Invalid char '" + c + "' in HexString");\r
+                       }\r
+                       idx = (i-2)/2;\r
+                       if(high) {\r
+                               ba[idx]=(byte)(b<<4);\r
+                               high = false;\r
+                       } else {\r
+                               ba[idx]|=b;\r
+                               high = true;\r
+                       }\r
+               }\r
+               return ba;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Locator.java b/core/src/main/java/com/att/cadi/Locator.java
new file mode 100644 (file)
index 0000000..a1593bb
--- /dev/null
@@ -0,0 +1,37 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+public interface Locator<T> {\r
+       public T get(Locator.Item item) throws LocatorException;\r
+       public boolean hasItems();\r
+       public void invalidate(Locator.Item item) throws LocatorException;\r
+       public Locator.Item best() throws LocatorException;\r
+       public Item first() throws LocatorException;\r
+       public Item next(Item item) throws LocatorException;\r
+       public boolean refresh();\r
+       public void destroy();\r
+       \r
+       public interface Item {}\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/LocatorException.java b/core/src/main/java/com/att/cadi/LocatorException.java
new file mode 100644 (file)
index 0000000..b9260b9
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+public class LocatorException extends Exception {\r
+       /**\r
+        * \r
+        */\r
+       private static final long serialVersionUID = -4267929804321134469L;\r
+\r
+       public LocatorException(String arg0) {\r
+               super(arg0);\r
+       }\r
+\r
+       public LocatorException(Throwable arg0) {\r
+               super(arg0);\r
+       }\r
+\r
+       public LocatorException(String arg0, Throwable arg1) {\r
+               super(arg0, arg1);\r
+       }\r
+\r
+       public LocatorException(CharSequence cs) {\r
+               super(cs.toString());\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Lur.java b/core/src/main/java/com/att/cadi/Lur.java
new file mode 100644 (file)
index 0000000..7ca94c9
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+import java.util.List;\r
+\r
+\r
+\r
+/**\r
+ * LUR: Local User Registry\r
+ *\r
+ * Concept by Robert Garskof, Implementation by Jonathan Gathman\r
+ * \r
+ * Where we can keep local copies of users and roles for faster Authorization when asked.\r
+ * \r
+ * Note: Author cannot resist the mental image of using a Fishing Lure to this LUR pattern \r
+ * \r
+ *\r
+ */\r
+public interface Lur {\r
+       /**\r
+        * Allow the Lur, which has correct Permission access, to create and hand back. \r
+        */\r
+       public Permission createPerm(String p);\r
+       \r
+       /** \r
+        * Fish for Principals in a Pond\r
+        * \r
+        *   or more boringly, is the User identified within a named collection representing permission.\r
+        * \r
+        * @param principalName\r
+        * @return\r
+        */\r
+       public boolean fish(Principal bait, Permission pond);\r
+\r
+       /** \r
+        * Fish all the Principals out a Pond\r
+        * \r
+        *   For additional humor, pronounce the following with a Southern Drawl, "FishOil"\r
+        * \r
+        *   or more boringly, load the List with Permissions found for Principal\r
+        * \r
+        * @param principalName\r
+        * @return\r
+        */\r
+       public void fishAll(Principal bait, List<Permission> permissions);\r
+\r
+       /**\r
+        * Allow implementations to disconnect, or cleanup resources if unneeded\r
+        */\r
+       public void destroy();\r
+\r
+       /**\r
+        * Does this LUR handle this pond exclusively?  Important for EpiLUR to determine whether \r
+        * to try another (more expensive) LUR \r
+        * @param pond\r
+        * @return\r
+        */\r
+       public boolean handlesExclusively(Permission pond);  \r
+       \r
+       /**\r
+        * What domain of User does this LUR support?  (used to avoid asking when not possible)\r
+        * \r
+        * @param bait\r
+        * @return\r
+        */\r
+       public boolean supports(String userName);\r
+       \r
+       /**\r
+        * Clear: Clear any Caching, if exists\r
+        */\r
+       public void clear(Principal p, StringBuilder report);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Permission.java b/core/src/main/java/com/att/cadi/Permission.java
new file mode 100644 (file)
index 0000000..b8cd56e
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+public interface Permission {\r
+       public String permType();\r
+       public String getKey();\r
+       public boolean match(Permission p);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/PropAccess.java b/core/src/main/java/com/att/cadi/PropAccess.java
new file mode 100644 (file)
index 0000000..25573a0
--- /dev/null
@@ -0,0 +1,321 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfo;\r
+\r
+public class PropAccess implements Access {\r
+       private static final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");\r
+\r
+       public static Level DEFAULT = Level.AUDIT;\r
+       \r
+       private Symm symm;\r
+       private int level;\r
+       private Properties props;\r
+       private List<String> recursionProtection = null;\r
+       private PrintStream out;\r
+       \r
+       private String name;\r
+\r
+       public PropAccess() {\r
+               out=System.out;\r
+               init(null);\r
+       }\r
+       \r
+       /**\r
+        * This Constructor soley exists to instantiate Servlet Context Based Logging that will call "init" later.\r
+        * @param sc\r
+        */\r
+       protected PropAccess(Object o) {\r
+               out=System.out;\r
+               props = new Properties();\r
+       }\r
+       \r
+       public PropAccess(String ... args) {\r
+               this(System.out,args);\r
+       }\r
+       \r
+       public PropAccess(PrintStream ps, String[] args) {\r
+               out=ps==null?System.out:ps;\r
+               Properties nprops=new Properties();\r
+               int eq;\r
+               for(String arg : args) {\r
+                       if((eq=arg.indexOf('='))>0) {\r
+                               nprops.setProperty(arg.substring(0, eq),arg.substring(eq+1));\r
+                       }\r
+               }\r
+               init(nprops);\r
+       }\r
+\r
+       public PropAccess(Properties p) {\r
+               this(System.out,p);\r
+       }\r
+       \r
+       public PropAccess(PrintStream ps, Properties p) {\r
+               out=ps==null?System.out:ps;\r
+               init(p);\r
+       }\r
+       \r
+       protected void init(Properties p) {\r
+               // Make sure these two are set before any changes in Logging\r
+               name = "cadi";\r
+               level=DEFAULT.maskOf();\r
+               \r
+               props = new Properties();\r
+               // First, load related System Properties\r
+               for(Entry<Object,Object> es : System.getProperties().entrySet()) {\r
+                       String key = es.getKey().toString();\r
+                       for(String start : new String[] {"cadi_","aaf_","cm_","csp_"}) {\r
+                               if(key.startsWith(start)) {\r
+                                       props.put(key, es.getValue());\r
+                               }\r
+                       }                       \r
+               }\r
+               // Second, overlay or fill in with Passed in Props\r
+               if(p!=null) {\r
+                       props.putAll(p);\r
+               }\r
+               \r
+               // Third, load any Chained Property Files\r
+               load(props.getProperty(Config.CADI_PROP_FILES));\r
+               \r
+               String sLevel = props.getProperty(Config.CADI_LOGLEVEL); \r
+               if(sLevel!=null) {\r
+                       level=Level.valueOf(sLevel).maskOf(); \r
+               }\r
+               // Setup local Symmetrical key encryption\r
+               if(symm==null) {\r
+                       symm = Symm.obtain(this);\r
+               }\r
+               \r
+               name = props.getProperty(Config.CADI_LOGNAME, name);\r
+               \r
+               // Critical - if no Security Protocols set, then set it.  We'll just get messed up if not\r
+               if(props.get(Config.CADI_PROTOCOLS)==null) {\r
+                       props.setProperty(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT);\r
+               }\r
+       }\r
+\r
+       private void load(String cadi_prop_files) {\r
+               String prevKeyFile = props.getProperty(Config.CADI_KEYFILE);\r
+\r
+               if(cadi_prop_files!=null) {\r
+                       int prev = 0, end = cadi_prop_files.length();\r
+                       int idx;\r
+                       String filename;\r
+                       while(prev<end) {\r
+                               idx = cadi_prop_files.indexOf(File.pathSeparatorChar,prev);\r
+                               if(idx<0) {\r
+                                       idx = end;\r
+                               }\r
+                               File file = new File(filename=cadi_prop_files.substring(prev,idx));\r
+                               if(file.exists()) {\r
+                                       printf(Level.INIT,"Loading CADI Properties from %s",file.getAbsolutePath());\r
+                                       try {\r
+                                               FileInputStream fis = new FileInputStream(file);\r
+                                               try {\r
+                                                       props.load(fis);\r
+                                                       // Recursively Load\r
+                                                       String chainProp = props.getProperty(Config.CADI_PROP_FILES);\r
+                                                       if(chainProp!=null) {\r
+                                                               if(recursionProtection==null) {\r
+                                                                       recursionProtection = new ArrayList<String>();\r
+                                                                       recursionProtection.add(cadi_prop_files);\r
+                                                               }\r
+                                                               if(!recursionProtection.contains(chainProp)) {\r
+                                                                       recursionProtection.add(chainProp);\r
+                                                                       load(chainProp); // recurse\r
+                                                               }\r
+                                                       }\r
+                                               } finally {\r
+                                                       fis.close();\r
+                                               }\r
+                                       } catch (Exception e) {\r
+                                               log(e,filename,"cannot be opened");\r
+                                       }\r
+                               } else {\r
+                                       printf(Level.WARN,"Warning: recursive CADI Property %s does not exist",file.getAbsolutePath());\r
+                               }\r
+                               prev = idx+1;\r
+                       }\r
+               }\r
+               // Reset Symm if Keyfile Changes:\r
+               String newKeyFile = props.getProperty(Config.CADI_KEYFILE);\r
+               if((prevKeyFile==null && newKeyFile!=null) || (newKeyFile!=null && !newKeyFile.equals(prevKeyFile))) {\r
+                       symm = Symm.obtain(this);\r
+                       prevKeyFile=newKeyFile;\r
+               }\r
+               \r
+               String loglevel = props.getProperty(Config.CADI_LOGLEVEL);\r
+               if(loglevel!=null) {\r
+                       try {\r
+                               level=Level.valueOf(loglevel).maskOf();\r
+                       } catch (IllegalArgumentException e) {\r
+                               printf(Level.ERROR,"%s=%s is an Invalid Log Level",Config.CADI_LOGLEVEL,loglevel);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void load(InputStream is) throws IOException {\r
+               props.load(is);\r
+               load(props.getProperty(Config.CADI_PROP_FILES));\r
+       }\r
+\r
+       @Override\r
+       public void log(Level level, Object ... elements) {\r
+               if(willLog(level)) {\r
+                       StringBuilder sb = buildMsg(level, elements);\r
+                       out.println(sb);\r
+                       out.flush();\r
+               }\r
+       }\r
+       \r
+       protected StringBuilder buildMsg(Level level, Object[] elements) {\r
+               StringBuilder sb = new StringBuilder(iso8601.format(new Date()));\r
+               sb.append(' ');\r
+               sb.append(level.name());\r
+               sb.append(" [");\r
+               sb.append(name);\r
+               \r
+               int end = elements.length;\r
+               if(end<=0) {\r
+                       sb.append("] ");\r
+               } else {\r
+                       int idx = 0;\r
+                       if(elements[idx] instanceof Integer) {\r
+                               sb.append('-');\r
+                               sb.append(elements[idx]);\r
+                               ++idx;\r
+                       }\r
+                       sb.append("] ");\r
+                       String s;\r
+                       boolean first = true;\r
+                       for(Object o : elements) {\r
+                               if(o!=null) {\r
+                                       s=o.toString();\r
+                                       if(first) {\r
+                                               first = false;\r
+                                       } else {\r
+                                               int l = s.length();\r
+                                               if(l>0) {\r
+                                                       switch(s.charAt(l-1)) {\r
+                                                               case ' ':\r
+                                                                       break;\r
+                                                               default:\r
+                                                                       sb.append(' ');\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       sb.append(s);\r
+                               }\r
+                       }\r
+               }\r
+               return sb;\r
+       }\r
+\r
+       @Override\r
+       public void log(Exception e, Object... elements) {\r
+               log(Level.ERROR,e.getMessage(),elements);\r
+               e.printStackTrace(System.err);\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object... elements) {\r
+               if(willLog(level)) {\r
+                       log(level,String.format(fmt, elements));\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void setLogLevel(Level level) {\r
+               this.level = level.maskOf();\r
+       }\r
+\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return level.inMask(this.level);\r
+       }\r
+\r
+       @Override\r
+       public ClassLoader classLoader() {\r
+               return ClassLoader.getSystemClassLoader();\r
+       }\r
+\r
+       @Override\r
+       public String getProperty(String tag, String def) {\r
+               return props.getProperty(tag,def);\r
+       }\r
+\r
+       @Override\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+       \r
+       public String encrypt(String unencrypted) throws IOException {\r
+               return Symm.ENC+symm.enpass(unencrypted);\r
+       }\r
+\r
+       //////////////////\r
+       // Additional\r
+       //////////////////\r
+       public String getProperty(String tag) {\r
+               return props.getProperty(tag);\r
+       }\r
+       \r
+\r
+       public Properties getProperties() {\r
+               return props;\r
+       }\r
+\r
+       public void setProperty(String tag, String value) {\r
+               if(value!=null) {\r
+                       props.put(tag, value);\r
+                       if(Config.CADI_KEYFILE.equals(tag)) {\r
+                               // reset decryption too\r
+                               symm = Symm.obtain(this);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public Properties getDME2Properties() {\r
+               return Config.getDME2Props(this);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Revalidator.java b/core/src/main/java/com/att/cadi/Revalidator.java
new file mode 100644 (file)
index 0000000..ded7b2d
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+public interface Revalidator<TRANS> {\r
+       /**\r
+        * Re-Validate Credential\r
+        * \r
+        * @param prin\r
+        * @return\r
+        */\r
+       public CachedPrincipal.Resp revalidate(TRANS trans, CachedPrincipal prin);\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/SLF4JAccess.java b/core/src/main/java/com/att/cadi/SLF4JAccess.java
new file mode 100644 (file)
index 0000000..e3d8451
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.util.Properties;\r
+\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class SLF4JAccess extends PropAccess {\r
+       private static final Logger slf4j = LoggerFactory.getLogger("AAF");\r
+       \r
+       public SLF4JAccess(final Properties initial) throws CadiException {\r
+               super(initial);\r
+       }\r
+\r
+       public void log(Level level, Object... elements) {\r
+               switch(level) {\r
+                       case AUDIT:\r
+                               slf4j.info(msg(elements).toString());\r
+                               break;\r
+                       case DEBUG:\r
+                               slf4j.debug(msg(elements).toString());\r
+                               break;\r
+                       case ERROR:\r
+                               slf4j.error(msg(elements).toString());\r
+                               break;\r
+                       case INFO:\r
+                               slf4j.info(msg(elements).toString());\r
+                               break;\r
+                       case INIT:\r
+                               slf4j.info(msg(elements).toString());\r
+                               break;\r
+                       case WARN:\r
+                               slf4j.warn(msg(elements).toString());\r
+                               break;\r
+                       default:\r
+                               slf4j.info(msg(elements).toString());\r
+                               break;\r
+               }\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)\r
+        */\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               switch(level) {\r
+                       case DEBUG:\r
+                               return slf4j.isDebugEnabled();\r
+                       case ERROR:\r
+                               return slf4j.isErrorEnabled();\r
+                       case WARN:\r
+                               return slf4j.isWarnEnabled();\r
+//                     case INFO:\r
+//                     case INIT:\r
+//                     case AUDIT:\r
+                       default:\r
+                               return slf4j.isInfoEnabled();\r
+               }\r
+       }\r
+\r
+       private StringBuilder msg(Object ... elements) {\r
+               StringBuilder sb = new StringBuilder();\r
+               boolean first = true;\r
+               for(Object o : elements) {\r
+                       if(first) first = false;\r
+                       else {\r
+                               sb.append(' ');\r
+                       }\r
+                       sb.append(o.toString());\r
+               }\r
+               return sb;\r
+       }\r
+\r
+       public void log(Exception e, Object... elements) {\r
+               slf4j.error(msg(elements).toString(),e);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/SecuritySetter.java b/core/src/main/java/com/att/cadi/SecuritySetter.java
new file mode 100644 (file)
index 0000000..dadbd06
--- /dev/null
@@ -0,0 +1,45 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+/**\r
+ *  Apply any particular security mechanism\r
+ *  \r
+ *  This allows the definition of various mechanisms involved outside of DRcli jars \r
+ *  \r
+ *\r
+ */\r
+public interface SecuritySetter<CT> {\r
+       public String getID();\r
+       \r
+       public void setSecurity(CT client) throws CadiException;\r
+       \r
+       /**\r
+        * Returns number of bad logins registered\r
+        * @param respCode\r
+        * @return\r
+        */\r
+       public int setLastResponse(int respCode);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/ServletContextAccess.java b/core/src/main/java/com/att/cadi/ServletContextAccess.java
new file mode 100644 (file)
index 0000000..896f824
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+import java.util.Enumeration;\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletContext;\r
+\r
+import com.att.cadi.config.Config;\r
+\r
+public class ServletContextAccess extends PropAccess {\r
+\r
+       private ServletContext context;\r
+\r
+       public ServletContextAccess(FilterConfig filterConfig) {\r
+               super(filterConfig); // protected contstructor... does not have "init" called.\r
+               context = filterConfig.getServletContext();\r
+\r
+               for(Enumeration<?> en = filterConfig.getInitParameterNames();en.hasMoreElements();) {\r
+                       String name = (String)en.nextElement();\r
+                       setProperty(name, filterConfig.getInitParameter(name));\r
+               }\r
+               init(getProperties());\r
+               Config.getDME2Props(this);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.PropAccess#log(com.att.cadi.Access.Level, java.lang.Object[])\r
+        */\r
+       @Override\r
+       public void log(Level level, Object... elements) {\r
+               if(willLog(level)) {\r
+                       StringBuilder sb = buildMsg(level, elements);\r
+                       context.log(sb.toString());\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.PropAccess#log(java.lang.Exception, java.lang.Object[])\r
+        */\r
+       @Override\r
+       public void log(Exception e, Object... elements) {\r
+               StringBuilder sb = buildMsg(Level.ERROR, elements);\r
+               context.log(sb.toString(),e);\r
+       }\r
+\r
+       public ServletContext context() {\r
+               return context;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/StrLur.java b/core/src/main/java/com/att/cadi/StrLur.java
new file mode 100644 (file)
index 0000000..dc4c992
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.util.List;\r
+\r
+\r
+\r
+/**\r
+ * StrLUR: Implements fish with String, skipping the need to be a Principal where it doesn't make sense.\r
+ *\r
+ *\r
+ */\r
+public interface StrLur extends Lur {\r
+       /** \r
+        * Fish for Principals in a Pond\r
+        * \r
+        *   or more boringly, is the User identified within a named collection representing permission.\r
+        * \r
+        * @param principalName\r
+        * @return\r
+        */\r
+       public boolean fish(String bait, Permission pond);\r
+\r
+       /** \r
+        * Fish all the Principals out a Pond\r
+        * \r
+        *   For additional humor, pronounce the following with a Southern Drawl, "FishOil"\r
+        * \r
+        *   or more boringly, load the List with Permissions found for Principal\r
+        * \r
+        * @param principalName\r
+        * @return\r
+        */\r
+       public void fishAll(String bait, List<Permission> permissions);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Symm.java b/core/src/main/java/com/att/cadi/Symm.java
new file mode 100644 (file)
index 0000000..0b34b58
--- /dev/null
@@ -0,0 +1,812 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.DataInputStream;\r
+import java.io.DataOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.security.SecureRandom;\r
+import java.util.ArrayList;\r
+import java.util.Random;\r
+\r
+import javax.crypto.CipherInputStream;\r
+import javax.crypto.CipherOutputStream;\r
+\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.config.Config;\r
+\r
+/**\r
+ * Key Conversion, primarily "Base64"\r
+ * \r
+ * Base64 is required for "Basic Authorization", which is an important part of the overall CADI Package.\r
+ * \r
+ * Note: This author found that there is not a "standard" library for Base64 conversion within Java.  \r
+ * The source code implementations available elsewhere were surprisingly inefficient, requiring, for \r
+ * instance, multiple string creation, on a transaction pass.  Integrating other packages that might be\r
+ * efficient enough would put undue Jar File Dependencies given this Framework should have none-but-Java \r
+ * dependencies.\r
+ * \r
+ * The essential algorithm is good for a symmetrical key system, as Base64 is really just\r
+ * a symmetrical key that everyone knows the values.  \r
+ * \r
+ * This code is quite fast, taking about .016 ms for encrypting, decrypting and even .08 for key \r
+ * generation. The speed quality, especially of key generation makes this a candidate for a short term token \r
+ * used for identity.\r
+ * \r
+ * It may be used to easily avoid placing Clear-Text passwords in configurations, etc. and contains \r
+ * supporting functions such as 2048 keyfile generation (see keygen).  This keyfile should, of course, \r
+ * be set to "400" (Unix) and protected as any other mechanism requires. \r
+ * \r
+ * However, this algorithm has not been tested against hackers.  Until such a time, utilize more tested\r
+ * packages to protect Data, especially sensitive data at rest (long term). \r
+ *\r
+ */\r
+public class Symm {\r
+       private static final byte[] DOUBLE_EQ = new byte[] {'=','='}; \r
+       public static final String ENC = "enc:";\r
+       private static final SecureRandom random = new SecureRandom();\r
+       \r
+       public final char[] codeset;\r
+       private final int splitLinesAt;\r
+       private final String encoding;\r
+       private final Convert convert;\r
+       private final boolean endEquals;\r
+       //Note: AES Encryption is not Thread Safe.  It is Synchronized\r
+       private static AES aes = null;  // only initialized from File, and only if needed for Passwords\r
+       \r
+       /**\r
+        * This is the standard base64 Key Set.\r
+        * RFC 2045\r
+        */\r
+       public static final Symm base64 = new Symm(\r
+                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()\r
+                       ,76, Config.UTF_8,true);\r
+\r
+       public static final Symm base64noSplit = new Symm(\r
+                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()\r
+                       ,Integer.MAX_VALUE, Config.UTF_8,true);\r
+\r
+       /**\r
+        * This is the standard base64 set suitable for URLs and Filenames\r
+        * RFC 4648\r
+        */\r
+       public static final Symm base64url = new Symm(\r
+                       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray()\r
+                       ,76, Config.UTF_8,true);\r
+\r
+       /**\r
+        * A Password set, using US-ASCII\r
+        * RFC 4648\r
+        */\r
+       public static final Symm encrypt = new Symm(base64url.codeset,1024, "US-ASCII", false);\r
+\r
+       /**\r
+        * A typical set of Password Chars\r
+        * Note, this is too large to fit into the algorithm. Only use with PassGen\r
+        */\r
+       private static char passChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+!@#$%^&*(){}[]?:;,.".toCharArray();\r
+                       \r
+\r
+\r
+       /**\r
+        * Use this to create special case Case Sets and/or Line breaks\r
+        * \r
+        * If you don't know why you need this, use the Singleton Method\r
+        * \r
+        * @param codeset\r
+        * @param split\r
+        */\r
+       public Symm(char[] codeset, int split, String charset, boolean useEndEquals) {\r
+               this.codeset = codeset;\r
+               splitLinesAt = split;\r
+               encoding = charset;\r
+               endEquals = useEndEquals;\r
+               char prev = 0, curr=0, first = 0;\r
+               int offset=Integer.SIZE; // something that's out of range for integer array\r
+               \r
+               // There can be time efficiencies gained when the underlying keyset consists mainly of ordered \r
+               // data (i.e. abcde...).  Therefore, we'll quickly analyze the keyset.  If it proves to have\r
+               // too much entropy, the "Unordered" algorithm, which is faster in such cases is used.\r
+               ArrayList<int[]> la = new ArrayList<int[]>();\r
+               for(int i=0;i<codeset.length;++i) {\r
+                       curr = codeset[i];\r
+                       if(prev+1==curr) { // is next character in set\r
+                               prev = curr;\r
+                       } else {\r
+                               if(offset!=Integer.SIZE) { // add previous range \r
+                                       la.add(new int[]{first,prev,offset});\r
+                               }\r
+                               first = prev = curr;\r
+                               offset = curr-i;\r
+                       }\r
+               }\r
+               la.add(new int[]{first,curr,offset});\r
+               if(la.size()>codeset.length/3) {\r
+                       convert = new Unordered(codeset);\r
+               } else { // too random to get speed enhancement from range algorithm\r
+                       int[][] range = new int[la.size()][];\r
+                       la.toArray(range);\r
+                       convert = new Ordered(range);\r
+               }\r
+       }\r
+       \r
+       public Symm copy(int lines) {\r
+               return new Symm(codeset,lines,encoding,endEquals);\r
+       }\r
+       \r
+       // Only used by keygen, which is intentionally randomized. Therefore, always use unordered\r
+       private  Symm(char[] codeset, Symm parent) {\r
+               this.codeset = codeset;\r
+               splitLinesAt = parent.splitLinesAt;\r
+               endEquals = parent.endEquals;\r
+               encoding = parent.encoding;\r
+               convert = new Unordered(codeset);\r
+       }\r
+\r
+       /**\r
+        * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.\r
+        * @return\r
+        */\r
+       @Deprecated\r
+       public static final Symm base64() {\r
+               return base64;\r
+       }\r
+\r
+       /**\r
+        * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.  \r
+        * No Line Splitting\r
+        * @return\r
+        */\r
+       @Deprecated\r
+       public static final Symm base64noSplit() {\r
+               return base64noSplit;\r
+       }\r
+\r
+       /**\r
+        * Obtain the base64 "URL" behavior of this class, for use in File Names, etc. (no "/")\r
+        */\r
+       @Deprecated\r
+       public static final Symm base64url() {\r
+               return base64url;\r
+       }\r
+\r
+       /**\r
+        * Obtain a special ASCII version for Scripting, with base set of base64url use in File Names, etc. (no "/")\r
+        */\r
+       public static final Symm baseCrypt() {\r
+               return encrypt;\r
+       }\r
+\r
+       /*\r
+        *  Note: AES Encryption is NOT thread-safe.  Must surround entire use with synchronized\r
+        */\r
+       private synchronized void exec(AESExec exec) throws IOException {\r
+               if(aes == null) {\r
+                       try {\r
+                               byte[] bytes = new byte[AES.AES_KEY_SIZE/8];\r
+                               int offset = (Math.abs(codeset[0])+47)%(codeset.length-bytes.length);\r
+                               for(int i=0;i<bytes.length;++i) {\r
+                                       bytes[i] = (byte)codeset[i+offset];\r
+                               }\r
+                               aes = new AES(bytes,0,bytes.length);\r
+                       } catch (Exception e) {\r
+                               throw new IOException(e);\r
+                       }\r
+               }\r
+               exec.exec(aes);\r
+       }\r
+       \r
+       private static interface AESExec {\r
+               public void exec(AES aes) throws IOException;\r
+       }\r
+       \r
+    public byte[] encode(byte[] toEncrypt) throws IOException {\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(toEncrypt.length*1.25));\r
+               encode(new ByteArrayInputStream(toEncrypt),baos);\r
+               return baos.toByteArray();\r
+       }\r
+\r
+    public byte[] decode(byte[] encrypted) throws IOException {\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(encrypted.length*1.25));\r
+               decode(new ByteArrayInputStream(encrypted),baos);\r
+               return baos.toByteArray();\r
+       }\r
+\r
+       /**\r
+     *  Helper function for String API of "Encode"\r
+     *  use "getBytes" with appropriate char encoding, etc.\r
+     *  \r
+     * @param str\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    public String encode(String str) throws IOException {\r
+       byte[] array;\r
+       try { \r
+               array = str.getBytes(encoding);\r
+       } catch (IOException e) {\r
+               array = str.getBytes(); // take default\r
+       }\r
+       // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code\r
+       ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*1.363)); // account for 4 bytes for 3 and a byte or two more\r
+       \r
+       encode(new ByteArrayInputStream(array),baos);\r
+       return baos.toString(encoding);\r
+    }\r
+    \r
+    /**\r
+     * Helper function for the String API of "Decode"\r
+     * use "getBytes" with appropriate char encoding, etc.\r
+     * @param str\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    public String decode(String str) throws IOException {\r
+       byte[] array;\r
+       try { \r
+               array = str.getBytes(encoding);\r
+       } catch (IOException e) {\r
+               array = str.getBytes(); // take default\r
+       }\r
+       // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code\r
+       ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*.76)); // Decoding is 3 bytes for 4.  Allocate slightly more than 3/4s\r
+       decode(new ByteArrayInputStream(array), baos);\r
+       return baos.toString(encoding);\r
+       }\r
+\r
+       /**\r
+     * Convenience Function\r
+     * \r
+     * encode String into InputStream and call encode(InputStream, OutputStream)\r
+     * \r
+     * @param string\r
+     * @param out\r
+     * @throws IOException\r
+     */\r
+       public void encode(String string, OutputStream out) throws IOException {\r
+               encode(new ByteArrayInputStream(string.getBytes()),out);\r
+       }\r
+\r
+       /**\r
+        * Convenience Function\r
+        * \r
+        * encode String into InputStream and call decode(InputStream, OutputStream)\r
+        * \r
+        * @param string\r
+        * @param out\r
+        * @throws IOException\r
+        */\r
+       public void decode(String string, OutputStream out) throws IOException {\r
+               decode(new ByteArrayInputStream(string.getBytes()),out);\r
+       }\r
+\r
+    public void encode(InputStream is, OutputStream os, byte[] prefix) throws IOException {\r
+       os.write(prefix);\r
+       encode(is,os);\r
+    }\r
+\r
+       /** \r
+     * encode InputStream onto Output Stream\r
+     * \r
+     * @param is\r
+     * @param estimate\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    public void encode(InputStream is, OutputStream os) throws IOException {\r
+       // StringBuilder sb = new StringBuilder((int)(estimate*1.255)); // try to get the right size of StringBuilder from start.. slightly more than 1.25 times \r
+       int prev=0;\r
+       int read, idx=0, line=0;\r
+       boolean go;\r
+       do {\r
+               read = is.read();\r
+               if(go = read>=0) {\r
+                       if(line>=splitLinesAt) {\r
+                               os.write('\n');\r
+                               line = 0;\r
+                       }\r
+                       switch(++idx) { // 1 based reading, slightly faster ++\r
+                               case 1: // ptr is the first 6 bits of read\r
+                                       os.write(codeset[read>>2]);\r
+                                       prev = read;\r
+                                       break;\r
+                               case 2: // ptr is the last 2 bits of prev followed by the first 4 bits of read\r
+                                       os.write(codeset[((prev & 0x03)<<4) | (read>>4)]);\r
+                                       prev = read;\r
+                                       break;\r
+                               default: //(3+) \r
+                                               // Char 1 is last 4 bits of prev plus the first 2 bits of read\r
+                                           // Char 2 is the last 6 bits of read\r
+                                       os.write(codeset[(((prev & 0xF)<<2) | (read>>6))]);\r
+                                       if(line==splitLinesAt) { // deal with line splitting for two characters\r
+                                               os.write('\n');\r
+                                               line=0;\r
+                                       }\r
+                                       os.write(codeset[(read & 0x3F)]);\r
+                                       ++line;\r
+                                       idx = 0;\r
+                                       prev = 0;\r
+                       }\r
+                       ++line;\r
+               } else { // deal with any remaining bits from Prev, then pad\r
+                       switch(idx) {\r
+                               case 1: // just the last 2 bits of prev\r
+                                       os.write(codeset[(prev & 0x03)<<4]);\r
+                                       if(endEquals)os.write(DOUBLE_EQ);\r
+                                       break;\r
+                               case 2: // just the last 4 bits of prev\r
+                                       os.write(codeset[(prev & 0xF)<<2]);\r
+                                       if(endEquals)os.write('=');\r
+                                       break;\r
+                       }\r
+                       idx = 0;\r
+               }\r
+               \r
+       } while(go);\r
+    }\r
+\r
+    public void decode(InputStream is, OutputStream os, int skip) throws IOException {\r
+       is.skip(skip);\r
+       decode(is,os);\r
+    }\r
+\r
+    /**\r
+        * Decode InputStream onto OutputStream\r
+        * @param is\r
+        * @param os\r
+        * @throws IOException\r
+        */\r
+    public void decode(InputStream is, OutputStream os) throws IOException {\r
+          int read, idx=0;\r
+          int prev=0, index;\r
+               while((read = is.read())>=0) {\r
+                       index = convert.convert(read);\r
+                       if(index>=0) {\r
+                       switch(++idx) { // 1 based cases, slightly faster ++\r
+                               case 1: // index goes into first 6 bits of prev\r
+                                       prev = index<<2; \r
+                                       break;\r
+                               case 2: // write second 2 bits of into prev, write byte, last 4 bits go into prev\r
+                                       os.write((byte)(prev|(index>>4)));\r
+                                       prev = index<<4;\r
+                                       break;\r
+                               case 3: // first 4 bits of index goes into prev, write byte, last 2 bits go into prev\r
+                                       os.write((byte)(prev|(index>>2)));\r
+                                       prev = index<<6;\r
+                                       break;\r
+                               default: // (3+) | prev and last six of index\r
+                                       os.write((byte)(prev|(index&0x3F)));\r
+                                       idx = prev = 0;\r
+                       }\r
+                       }\r
+               };\r
+               os.flush();\r
+   }\r
+   \r
+   /**\r
+    * Interface to allow this class to choose which algorithm to find index of character in Key\r
+    *\r
+    */\r
+   private interface Convert {\r
+          public int convert(int read) throws IOException;\r
+   }\r
+\r
+   /**\r
+    * Ordered uses a range of orders to compare against, rather than requiring the investigation\r
+    * of every character needed.\r
+    *\r
+    */\r
+   private static final class Ordered implements Convert {\r
+          private int[][] range;\r
+          public Ordered(int[][] range) {\r
+                  this.range = range;\r
+          }\r
+          public int convert(int read) throws IOException {\r
+                  switch(read) {\r
+                          case -1: \r
+                          case '=':\r
+                          case '\n': \r
+                                  return -1;\r
+                  }\r
+                  for(int i=0;i<range.length;++i) {\r
+                          if(read >= range[i][0] && read<=range[i][1]) {\r
+                                  return read-range[i][2];\r
+                          }\r
+                  }\r
+                  throw new IOException("Unacceptable Character in Stream");\r
+          }\r
+   }\r
+   \r
+   /**\r
+    * Unordered, i.e. the key is purposely randomized, simply has to investigate each character\r
+    * until we find a match.\r
+    *\r
+    */\r
+   private static final class Unordered implements Convert {\r
+          private char[] codec;\r
+          public Unordered(char[] codec) {\r
+                  this.codec = codec;\r
+          }\r
+          public int convert(int read) throws IOException {\r
+                  switch(read) {\r
+                          case -1: \r
+                          case '=':\r
+                          case '\n': \r
+                                  return -1;\r
+                  }\r
+                  for(int i=0;i<codec.length;++i) {\r
+                          if(codec[i]==read)return i;\r
+                  }\r
+                 // don't give clue in Encryption mode\r
+                 throw new IOException("Unacceptable Character in Stream");\r
+          }\r
+   }\r
+\r
+   /**\r
+    * Generate a 2048 based Key from which we extract our code base\r
+    * \r
+    * @return\r
+    * @throws IOException\r
+    */\r
+   public byte[] keygen() throws IOException {\r
+               byte inkey[] = new byte[0x600];\r
+               new SecureRandom().nextBytes(inkey);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream(0x800);\r
+               base64url.encode(new ByteArrayInputStream(inkey), baos);\r
+               return baos.toByteArray();\r
+   }\r
+   \r
+   // A class allowing us to be less predictable about significant digits (i.e. not picking them up from the\r
+   // beginning, and not picking them up in an ordered row.  Gives a nice 2048 with no visible patterns.\r
+   private class Obtain {\r
+          private int last;\r
+          private int skip;\r
+          private int length;\r
+          private byte[] key;\r
+  \r
+          private Obtain(Symm b64, byte[] key) {\r
+                  skip = Math.abs(key[key.length-13]%key.length);\r
+                  if((key.length&0x1) == (skip&0x1)) { // if both are odd or both are even\r
+                          ++skip;\r
+                  }\r
+                  length = b64.codeset.length;\r
+                  last = 17+length%59; // never start at beginning\r
+                  this.key = key;\r
+          }\r
+          \r
+          private int next() {\r
+                  return Math.abs(key[(++last*skip)%key.length])%length;\r
+          }\r
+   };\r
+  \r
+   /**\r
+    * Obtain a Symm from "keyfile" (Config.KEYFILE) property\r
+    * \r
+    * @param acesss\r
+    * @return\r
+    */\r
+   public static Symm obtain(Access access) {\r
+               Symm symm = Symm.baseCrypt();\r
+\r
+               String keyfile = access.getProperty(Config.CADI_KEYFILE,null);\r
+               if(keyfile!=null) {\r
+                       File file = new File(keyfile);\r
+                       try {\r
+                               access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getCanonicalPath());\r
+                       } catch (IOException e1) {\r
+                               access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getAbsolutePath());\r
+                       }\r
+                       if(file.exists()) {\r
+                               try {\r
+                                       FileInputStream fis = new FileInputStream(file);\r
+                                       try {\r
+                                               symm = Symm.obtain(fis);\r
+                                       } finally {\r
+                                               try {\r
+                                                  fis.close();\r
+                                               } catch (IOException e) {\r
+                                               }\r
+                                       }\r
+                               } catch (IOException e) {\r
+                                       access.log(e, "Cannot load keyfile");\r
+                               }\r
+                       }\r
+               }\r
+               return symm;\r
+   }\r
+  /**\r
+   *  Create a new random key \r
+   */\r
+  public Symm obtain() throws IOException {\r
+               byte inkey[] = new byte[0x800];\r
+               new SecureRandom().nextBytes(inkey);\r
+               return obtain(inkey);\r
+  }\r
+  \r
+  /**\r
+   * Obtain a Symm from 2048 key from a String\r
+   * \r
+   * @param key\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public static Symm obtain(String key) throws IOException {\r
+         return obtain(new ByteArrayInputStream(key.getBytes()));\r
+  }\r
+  \r
+  /**\r
+   * Obtain a Symm from 2048 key from a Stream\r
+   * \r
+   * @param is\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public static Symm obtain(InputStream is) throws IOException {\r
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+         try {\r
+                 base64url.decode(is, baos);\r
+         } catch (IOException e) {\r
+                 // don't give clue\r
+                 throw new IOException("Invalid Key");\r
+         }\r
+         byte[] bkey = baos.toByteArray();\r
+         if(bkey.length<0x88) { // 2048 bit key\r
+                 throw new IOException("Invalid key");\r
+         }\r
+         return baseCrypt().obtain(bkey);\r
+  }\r
+\r
+  /**\r
+   * Convenience for picking up Keyfile\r
+   * \r
+   * @param f\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public static Symm obtain(File f) throws IOException {\r
+         FileInputStream fis = new FileInputStream(f);\r
+         try {\r
+                 return obtain(fis);\r
+         } finally {\r
+                 fis.close();\r
+         }\r
+  }\r
+  /**\r
+   * Decrypt into a String\r
+   *\r
+   *  Convenience method\r
+   * \r
+   * @param password\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public String enpass(String password) throws IOException {\r
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+         enpass(password,baos);\r
+         return new String(baos.toByteArray());\r
+  }\r
+\r
+  /**\r
+   * Create an encrypted password, making sure that even short passwords have a minimum length.\r
+   * \r
+   * @param password\r
+   * @param os\r
+   * @throws IOException\r
+   */\r
+  public void enpass(final String password, final OutputStream os) throws IOException {\r
+               final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               DataOutputStream dos = new DataOutputStream(baos);\r
+               byte[] bytes = password.getBytes();\r
+               if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization\r
+                       dos.write(bytes);\r
+               } else {\r
+                       \r
+                       Random r = new SecureRandom();\r
+                       int start = 0;\r
+                       byte b;\r
+                       for(int i=0;i<3;++i) {\r
+                               dos.writeByte(b=(byte)r.nextInt());\r
+                               start+=Math.abs(b);\r
+                       }\r
+                       start%=0x7;\r
+                       for(int i=0;i<start;++i) {\r
+                               dos.writeByte(r.nextInt());\r
+                       }\r
+                       dos.writeInt((int)System.currentTimeMillis());\r
+                       int minlength = Math.min(0x9,bytes.length);\r
+                       dos.writeByte(minlength); // expect truncation\r
+                       if(bytes.length<0x9) {\r
+                               for(int i=0;i<bytes.length;++i) {\r
+                                       dos.writeByte(r.nextInt());\r
+                                       dos.writeByte(bytes[i]);\r
+                               }\r
+                               // make sure it's long enough\r
+                               for(int i=bytes.length;i<0x9;++i) {\r
+                                       dos.writeByte(r.nextInt());\r
+                               }\r
+                       } else {\r
+                               dos.write(bytes);\r
+                       }\r
+               }\r
+               \r
+               // 7/21/2016 jg add AES Encryption to the mix\r
+               exec(new AESExec() {\r
+                       @Override\r
+                       public void exec(AES aes) throws IOException {\r
+                               CipherInputStream cis = aes.inputStream(new ByteArrayInputStream(baos.toByteArray()), true);\r
+                               try {\r
+                                       encode(cis,os);\r
+                               } finally {\r
+                                       os.flush();\r
+                                       cis.close();\r
+                               }\r
+                       }\r
+               });\r
+               synchronized(ENC) {\r
+               }\r
+       }\r
+\r
+  /**\r
+   * Decrypt a password into a String\r
+   * \r
+   * Convenience method\r
+   * \r
+   * @param password\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public String depass(String password) throws IOException {\r
+         if(password==null)return null;\r
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+         depass(password,baos);\r
+         return new String(baos.toByteArray());\r
+  }\r
+  \r
+  /**\r
+   * Decrypt a password\r
+   * \r
+   * Skip Symm.ENC\r
+   * \r
+   * @param password\r
+   * @param os\r
+   * @return\r
+   * @throws IOException\r
+   */\r
+  public long depass(final String password, final OutputStream os) throws IOException {\r
+         int offset = password.startsWith(ENC)?4:0;\r
+         final ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+         final ByteArrayInputStream bais =  new ByteArrayInputStream(password.getBytes(),offset,password.length()-offset);\r
+         exec(new AESExec() {\r
+               @Override\r
+               public void exec(AES aes) throws IOException {\r
+                         CipherOutputStream cos = aes.outputStream(baos, false);\r
+                         decode(bais,cos);\r
+                         cos.close(); // flush\r
+               }\r
+         });\r
+         byte[] bytes = baos.toByteArray();\r
+         DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));\r
+         long time;\r
+         if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization\r
+                 os.write(bytes);\r
+                 time = 0L;\r
+         } else {\r
+                 int start=0;\r
+                 for(int i=0;i<3;++i) {\r
+                         start+=Math.abs(dis.readByte());\r
+                 }\r
+                 start%=0x7;\r
+                 for(int i=0;i<start;++i) {\r
+                         dis.readByte();\r
+                 }\r
+                 time = (dis.readInt() & 0xFFFF)|(System.currentTimeMillis()&0xFFFF0000);\r
+                 int minlength = dis.readByte();\r
+                 if(minlength<0x9){\r
+                       DataOutputStream dos = new DataOutputStream(os);\r
+                       for(int i=0;i<minlength;++i) {\r
+                               dis.readByte();\r
+                               dos.writeByte(dis.readByte());\r
+                       }\r
+                 } else {\r
+                         int pre =((Byte.SIZE*3+Integer.SIZE+Byte.SIZE)/Byte.SIZE)+start; \r
+                         os.write(bytes, pre, bytes.length-pre);\r
+                 }\r
+         }\r
+         return time;\r
+  }\r
+\r
+  public static String randomGen(int numBytes) {\r
+         return randomGen(passChars,numBytes);  \r
+  }\r
+  \r
+  public static String randomGen(char[] chars ,int numBytes) {\r
+           int rint;\r
+           StringBuilder sb = new StringBuilder(numBytes);\r
+           for(int i=0;i<numBytes;++i) {\r
+               rint = random.nextInt(chars.length);\r
+               sb.append(chars[rint]);\r
+           }\r
+           return sb.toString();\r
+  }\r
+  // Internal mechanism for helping to randomize placement of characters within a Symm codeset\r
+  // Based on an incoming data stream (originally created randomly, but can be recreated within \r
+  // 2048 key), go after a particular place in the new codeset.  If that codeset spot is used, then move\r
+  // right or left (depending on iteration) to find the next available slot.  In this way, key generation \r
+  // is speeded up by only enacting N iterations, but adds a spreading effect of the random number stream, so that keyset is also\r
+  // shuffled for a good spread. It is, however, repeatable, given the same number set, allowing for \r
+  // quick recreation when the official stream is actually obtained.\r
+  public Symm obtain(byte[] key) throws IOException {\r
+         try {\r
+               byte[] bytes = new byte[AES.AES_KEY_SIZE/8];\r
+               int offset = (Math.abs(key[(47%key.length)])+137)%(key.length-bytes.length);\r
+               for(int i=0;i<bytes.length;++i) {\r
+                       bytes[i] = key[i+offset];\r
+               }\r
+\r
+               aes = new AES(bytes,0,bytes.length);\r
+         } catch (Exception e) {\r
+                 throw new IOException(e);\r
+         }\r
+               int filled = codeset.length;\r
+               char[] seq = new char[filled];\r
+               int end = filled--;\r
+               \r
+               boolean right = true;\r
+               int index;\r
+               Obtain o = new Obtain(this,key);\r
+               \r
+               while(filled>=0) {\r
+                       index = o.next();\r
+                       if(index<0 || index>=codeset.length) {\r
+                               System.out.println("uh, oh");\r
+                       }\r
+                       if(right) { // alternate going left or right to find the next open slot (keeps it from taking too long to hit something) \r
+                               for(int j=index;j<end;++j) {\r
+                                       if(seq[j]==0) {\r
+                                               seq[j]=codeset[filled];\r
+                                               --filled;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               right = false;\r
+                       } else {\r
+                               for(int j=index;j>=0;--j) {\r
+                                       if(seq[j]==0) {\r
+                                               seq[j]=codeset[filled];\r
+                                               --filled;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               right = true;\r
+                       }\r
+               }\r
+               return new Symm(seq,this);\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Taf.java b/core/src/main/java/com/att/cadi/Taf.java
new file mode 100644 (file)
index 0000000..7ba6fb4
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import com.att.cadi.taf.TafResp;\r
+\r
+\r
+/**\r
+ * TAF - Transmutative Assertion Framework.  \r
+ * \r
+ * This main Interface embodies the essential of the assertion, where a number of different TAFs might be used to authenticate\r
+ * and that authentication to be recognized through other elements.\r
+ * \r
+ * Concept by Robert Garskof.  Implemented by Jonathan Gathman\r
+ *  \r
+ *\r
+ */\r
+public interface Taf {\r
+       enum LifeForm {CBLF, SBLF, LFN};\r
+       /**\r
+        * The lifeForm param is a humorous way of describing whether the interaction is proceeding from direct Human Interaction via a browser \r
+        * or App which can directly query a memorized password, key sequence, bio-feedback, from that user, or a machine mechanism for which identity\r
+        * can more easily be determined by Certificate, Mechanical ID/Password etc.  Popularized in modern culture and Science Fiction (especially \r
+        * Star Trek), we (starting with Robert Garskof) use the terms "Carbon Based Life Form" (CBLF) for mechanisms with people at the end of them, or \r
+        * "Silicon Based Life Forms" (SBLF) to indicate machine only interactions.  I have added "LFN" for (Life-Form Neutral) to aid identifying\r
+        * processes for which it doesn't matter whether there is a human at the immediate end of the chain, or cannot be determined mechanically.  \r
+        * \r
+        * The variable parameter is not necessarily ideal, but with too many unknown Tafs to be created, flexibility,\r
+        * is unfortunately required at this point.  Future versions could lock this down more.  JG 10/18/2012\r
+        * \r
+        * @param lifeForm\r
+        * @param info\r
+        * @return\r
+        */\r
+       public TafResp validate(LifeForm reading, String ... info);\r
+       \r
+}\r
diff --git a/core/src/main/java/com/att/cadi/Transmutate.java b/core/src/main/java/com/att/cadi/Transmutate.java
new file mode 100644 (file)
index 0000000..e392e86
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+\r
+/**\r
+ * The unique element of TAF is that we establish the relationship/mechanism to mutate the Principal derived from\r
+ * one Authentication mechanism into a trustable Principal of another.  The mechanism needs to be decided by system\r
+ * trusting.  \r
+ * \r
+ * The Generic "T" is used so that the code used will be very specific for the implementation, enforced by Compiler\r
+ * \r
+ * This interface will allow differences of trusting Transmutation of Authentication \r
+ *\r
+ */\r
+public interface Transmutate<T> {\r
+       /**\r
+        * Mutate the (assumed validated) Principal into the expected Principal name to be used to construct\r
+        * \r
+        * @param p\r
+        * @return\r
+        */\r
+       public T mutate(Principal p);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/TrustChecker.java b/core/src/main/java/com/att/cadi/TrustChecker.java
new file mode 100644 (file)
index 0000000..2cf2203
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+\r
+import com.att.cadi.taf.TafResp;\r
+\r
+/**\r
+ * Change to another Principal based on Trust of caller and User Chain (if desired)\r
+ * \r
+ *\r
+ */\r
+public interface TrustChecker {\r
+       public TafResp mayTrust(TafResp tresp, HttpServletRequest req);\r
+       \r
+       /**\r
+        * A class that trusts no-one else, so just return same TResp\r
+        */\r
+       public static TrustChecker NOTRUST = new TrustChecker() {\r
+               @Override\r
+               public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {\r
+                       return tresp;\r
+               }\r
+\r
+               @Override\r
+               public void setLur(Lur lur) {\r
+               }\r
+       };\r
+\r
+       public void setLur(Lur lur);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/User.java b/core/src/main/java/com/att/cadi/User.java
new file mode 100644 (file)
index 0000000..6903cb3
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.security.Principal;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+import com.att.cadi.lur.LocalPermission;\r
+\r
+/**\r
+ * Class to hold info from the User Perspective.\r
+ * \r
+ *\r
+ */\r
+public final class User<PERM extends Permission> {\r
+       private static Map<String,Permission> NULL_MAP = new HashMap<String,Permission>();\r
+       public Principal principal;\r
+       Map<String, Permission> perms ;\r
+       long permExpires;\r
+       private final long interval;\r
+       int count;\r
+       \r
+       // Note: This should only be used for Local RBAC (in memory)\r
+       public User(Principal principal) {\r
+               this.principal = principal;\r
+               perms = NULL_MAP;\r
+               permExpires = Long.MAX_VALUE; // Never.  Well, until 64 bits of millis since 1970 expires...\r
+               interval = 0L;\r
+               count = 0;\r
+       }\r
+\r
+       public User(Principal principal, long expireInterval) {\r
+               this.principal = principal;\r
+               perms = NULL_MAP;\r
+               expireInterval = Math.max(expireInterval, 0); // avoid < 1\r
+               interval = Math.max(AbsUserCache.MIN_INTERVAL,Math.min(expireInterval,AbsUserCache.MAX_INTERVAL));\r
+               permExpires = 0;\r
+               count = 0;\r
+       }\r
+       \r
+       public void renewPerm() {\r
+               permExpires = System.currentTimeMillis()+interval;\r
+       }\r
+       \r
+       public long permExpires() {\r
+               return permExpires;\r
+       }\r
+       \r
+       public boolean permExpired() {\r
+               return System.currentTimeMillis() > permExpires;\r
+       }\r
+\r
+       public boolean noPerms() {\r
+               return perms==null || perms.values().size()==0; \r
+       }\r
+       \r
+       public void setNoPerms() {\r
+               perms=NULL_MAP;\r
+               permExpires = System.currentTimeMillis() + interval;\r
+       }\r
+\r
+       public boolean permsUnloaded() {\r
+               return perms==null;\r
+       }\r
+\r
+       public synchronized void incCount() {\r
+               ++count;\r
+       }\r
+       \r
+       public synchronized void resetCount() {\r
+               count=0;\r
+       }\r
+       \r
+       public Map<String,Permission> newMap() {\r
+               return new ConcurrentHashMap<String,Permission>();\r
+       }\r
+\r
+       public void add(LocalPermission permission) {\r
+               if(perms==NULL_MAP)perms=newMap();\r
+               perms.put(permission.getKey(),permission);\r
+       }\r
+\r
+       public void add(Map<String, Permission> newMap, PERM permission) {\r
+               newMap.put(permission.getKey(),permission);\r
+       }\r
+\r
+       public void setMap(Map<String, Permission> newMap) {\r
+               perms = newMap;\r
+       }\r
+\r
+       public boolean contains(Permission perm) {\r
+               for (Permission p : perms.values()) {\r
+                       if (p.match(perm)) return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       public void copyPermsTo(List<Permission> sink) {\r
+               sink.addAll(perms.values());\r
+       }\r
+       \r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append(principal.getName());\r
+               sb.append('|');\r
+               boolean first = true;\r
+               synchronized(perms) {\r
+                       for(Permission gp : perms.values()) {\r
+                               if(first) {\r
+                                       first = false;\r
+                                       sb.append(':');\r
+                               } else {\r
+                                       sb.append(',');\r
+                               }\r
+                               sb.append(gp.getKey());\r
+                       }\r
+               }\r
+               return sb.toString();\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/UserChain.java b/core/src/main/java/com/att/cadi/UserChain.java
new file mode 100644 (file)
index 0000000..90c47c1
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+/**\r
+ * Interface to add a User Chain String to Principal\r
+ * \r
+ * \r
+ * \r
+ *  Where\r
+ *  APP is name suitable for Logging (i.e. official App Acronym) \r
+ *  ID is official User or MechID, best if includes Identity Source (i.e. ab1234@csp.att.com)\r
+ *  Protocol is the Security protocol,\r
+ *  \r
+ *  Format:<ID>:<APP>:<protocol>[:AS][,<ID>:<APP>:<protocol>]*\r
+ *  \r
+ * \r
+ *\r
+ */\r
+public interface UserChain  {\r
+       public enum Protocol {BasicAuth,Cookie,Cert,OAuth};\r
+       public String userChain();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/Config.java b/core/src/main/java/com/att/cadi/config/Config.java
new file mode 100644 (file)
index 0000000..dd8e56d
--- /dev/null
@@ -0,0 +1,815 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.net.UnknownHostException;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.security.cert.CertificateException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+import java.util.TimerTask;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachingLur;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CredVal;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.lur.LocalLur;\r
+import com.att.cadi.lur.NullLur;\r
+import com.att.cadi.taf.HttpEpiTaf;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.basic.BasicHttpTaf;\r
+import com.att.cadi.taf.cert.X509Taf;\r
+import com.att.cadi.taf.dos.DenialOfServiceTaf;\r
+\r
+/**\r
+ * Create a Consistent Configuration mechanism, even when configuration styles are as vastly different as\r
+ * Properties vs JavaBeans vs FilterConfigs...\r
+ * \r
+ *\r
+ */\r
+public class Config {\r
+\r
+       private static final String HIDE_PASS = "***************";\r
+\r
+       public static final String UTF_8 = "UTF-8";\r
+\r
+       // Property Names associated with configurations.\r
+       // As of 1.0.2, these have had the dots removed so as to be compatible with JavaBean style\r
+       // configurations as well as property list style.\r
+       public static final String HOSTNAME = "hostname";\r
+       public static final String CADI_PROP_FILES = "cadi_prop_files"; // Additional Properties files (separate with ;)\r
+       public static final String CADI_LOGLEVEL = "cadi_loglevel";\r
+       public static final String CADI_LOGNAME = "cadi_logname";\r
+       public static final String CADI_KEYFILE = "cadi_keyfile";\r
+       public static final String CADI_KEYSTORE = "cadi_keystore";\r
+       public static final String CADI_KEYSTORE_PASSWORD = "cadi_keystore_password";\r
+       public static final String CADI_ALIAS = "cadi_alias";\r
+       public static final String CADI_LOGINPAGE_URL = "cadi_loginpage_url";\r
+\r
+       public static final String CADI_KEY_PASSWORD = "cadi_key_password";\r
+       public static final String CADI_TRUSTSTORE = "cadi_truststore";\r
+       public static final String CADI_TRUSTSTORE_PASSWORD = "cadi_truststore_password";\r
+       public static final String CADI_X509_ISSUERS = "cadi_x509_issuers";\r
+       public static final String CADI_TRUST_MASKS="cadi_trust_masks";\r
+       public static final String CADI_TRUST_PERM="cadi_trust_perm"; //  IDs with this perm can utilize the "AS " user concept\r
+       public static final String CADI_PROTOCOLS = "cadi_protocols";\r
+       public static final String CADI_NOAUTHN = "cadi_noauthn";\r
+       public static final String CADI_LOC_LIST = "cadi_loc_list";\r
+       \r
+       public static final String CADI_USER_CHAIN_TAG = "cadi_user_chain";\r
+       public static final String CADI_USER_CHAIN = "USER_CHAIN";\r
+\r
+       \r
+       \r
+       public static final String CSP_DOMAIN = "csp_domain";\r
+       public static final String CSP_HOSTNAME = "csp_hostname";\r
+       public static final String CSP_DEVL_LOCALHOST = "csp_devl_localhost";\r
+       public static final String CSP_USER_HEADER = "CSP_USER";\r
+       public static final String CSP_SYSTEMS_CONF = "CSPSystems.conf";\r
+    public static final String CSP_SYSTEMS_CONF_FILE = "csp_systems_conf_file";\r
+\r
+\r
+       public static final String TGUARD_ENV="tguard_env";\r
+       public static final String TGUARD_DOMAIN = "tguard_domain";\r
+       public static final String TGUARD_TIMEOUT = "tguard_timeout";\r
+       public static final String TGUARD_TIMEOUT_DEF = "5000";\r
+       public static final String TGUARD_CERTS = "tguard_certs"; // comma delimited SHA-256 finger prints\r
+//     public static final String TGUARD_DEVL_LOCALHOST = "tguard_devl_localhost";\r
+//     public static final String TGUARD_USER_HEADER = "TGUARD_USER";\r
+\r
+       public static final String LOCALHOST_ALLOW = "localhost_allow";\r
+       public static final String LOCALHOST_DENY = "localhost_deny";\r
+       \r
+       public static final String BASIC_REALM = "basic_realm";  // what is sent to the client \r
+       public static final String BASIC_WARN = "basic_warn";  // Warning of insecure channel \r
+       public static final String USERS = "local_users";\r
+       public static final String GROUPS = "local_groups";\r
+       public static final String WRITE_TO = "local_writeto"; // dump RBAC to local file in Tomcat Style (some apps use)\r
+       \r
+       public static final String AAF_ENV = "aaf_env";\r
+       public static final String AAF_ROOT_NS = "aaf_root_ns";\r
+       public static final String AAF_ROOT_COMPANY = "aaf_root_company";\r
+       public static final String AAF_URL = "aaf_url"; //URL for AAF... Use to trigger AAF configuration\r
+       public static final String AAF_MECHID = "aaf_id";\r
+       public static final String AAF_MECHPASS = "aaf_password";\r
+       public static final String AAF_LUR_CLASS = "aaf_lur_class";\r
+       public static final String AAF_TAF_CLASS = "aaf_taf_class";\r
+       public static final String AAF_CONNECTOR_CLASS = "aaf_connector_class";\r
+       public static final String AAF_LOCATOR_CLASS = "aaf_locator_class";\r
+       public static final String AAF_CONN_TIMEOUT = "aaf_conn_timeout";\r
+       public static final String AAF_CONN_TIMEOUT_DEF = "3000";\r
+       public static final String AAF_READ_TIMEOUT = "aaf_timeout";\r
+       public static final String AAF_READ_TIMEOUT_DEF = "5000";\r
+       public static final String AAF_USER_EXPIRES = "aaf_user_expires";\r
+       public static final String AAF_USER_EXPIRES_DEF = "600000"; // Default is 10 mins\r
+       public static final String AAF_CLEAN_INTERVAL = "aaf_clean_interval";\r
+       public static final String AAF_CLEAN_INTERVAL_DEF = "30000"; // Default is 30 seconds\r
+       public static final String AAF_REFRESH_TRIGGER_COUNT = "aaf_refresh_trigger_count";\r
+       public static final String AAF_REFRESH_TRIGGER_COUNT_DEF = "3"; // Default is 10 mins\r
+       \r
+       public static final String AAF_HIGH_COUNT = "aaf_high_count";\r
+       public static final String AAF_HIGH_COUNT_DEF = "1000"; // Default is 1000 entries\r
+       public static final String AAF_PERM_MAP = "aaf_perm_map";\r
+       public static final String AAF_DEPLOYED_VERSION = "DEPLOYED_VERSION";\r
+       public static final String AAF_CERT_IDS = "aaf_cert_ids";\r
+       public static final String AAF_DEBUG_IDS = "aaf_debug_ids"; // comma delimited\r
+       \r
+       public static final String GW_URL = "gw_url";\r
+       public static final String CM_URL = "cm_url";\r
+       public static final String CM_TRUSTED_CAS = "cm_trusted_cas";\r
+\r
+       public static final String PATHFILTER_URLPATTERN = "pathfilter_urlpattern";\r
+       public static final String PATHFILTER_STACK = "pathfilter_stack";\r
+       public static final String PATHFILTER_NS = "pathfilter_ns";\r
+       public static final String PATHFILTER_NOT_AUTHORIZED_MSG = "pathfilter_not_authorized_msg";\r
+\r
+       public static final String AFT_DME2_TRUSTSTORE_PASSWORD = "AFT_DME2_TRUSTSTORE_PASSWORD";\r
+       public static final String AFT_DME2_TRUSTSTORE = "AFT_DME2_TRUSTSTORE";\r
+       public static final String AFT_DME2_KEYSTORE_PASSWORD = "AFT_DME2_KEYSTORE_PASSWORD";\r
+       public static final String AFT_DME2_KEY_PASSWORD = "AFT_DME2_KEY_PASSWORD";\r
+       public static final String AFT_DME2_KEYSTORE = "AFT_DME2_KEYSTORE";\r
+       public static final String AFT_DME2_SSL_TRUST_ALL = "AFT_DME2_SSL_TRUST_ALL";\r
+       public static final String AFT_DME2_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_SSL_INCLUDE_PROTOCOLS";\r
+\r
+\r
+       // DME2 Client.  First property must be set to "false", and the others set in order to use SSL Client\r
+       public static final String AFT_DME2_CLIENT_IGNORE_SSL_CONFIG="AFT_DME2_CLIENT_IGNORE_SSL_CONFIG";\r
+       public static final String AFT_DME2_CLIENT_KEYSTORE = "AFT_DME2_CLIENT_KEYSTORE";\r
+       public static final String AFT_DME2_CLIENT_KEYSTORE_PASSWORD = "AFT_DME2_CLIENT_KEYSTORE_PASSWORD";\r
+       public static final String AFT_DME2_CLIENT_TRUSTSTORE = "AFT_DME2_CLIENT_TRUSTSTORE";\r
+       public static final String AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD = "AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD";\r
+       public static final String AFT_DME2_CLIENT_SSL_CERT_ALIAS = "AFT_DME2_CLIENT_SSL_CERT_ALIAS"; \r
+       public static final String AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS";\r
+\r
+       \r
+       // This one should go unpublic\r
+       public static final String AAF_DEFAULT_REALM = "aaf_default_realm";\r
+       private static String defaultRealm="none";\r
+\r
+       public static final String AAF_DOMAIN_SUPPORT = "aaf_domain_support";\r
+       //public static final String AAF_DOMAIN_SUPPORT_DEF = ".com";\r
+       public static final String AAF_DOMAIN_SUPPORT_DEF = ".org";\r
+\r
+\r
+       public static void setDefaultRealm(Access access) throws CadiException {\r
+               try {\r
+                       boolean hasCSP;\r
+                       try {\r
+                               Class.forName("com.att.cadi.taf.csp.CSPTaf");\r
+                               hasCSP=true;\r
+                       } catch(ClassNotFoundException e) {\r
+                               hasCSP = logProp(access,Config.CSP_DOMAIN, null)!=null;\r
+                       }\r
+                       defaultRealm = logProp(access,Config.AAF_DEFAULT_REALM,\r
+                                       hasCSP?"csp.att.com":\r
+                                       logProp(access,Config.BASIC_REALM,\r
+                                               logProp(access,HOSTNAME,InetAddress.getLocalHost().getHostName())\r
+                                               )\r
+                                       );\r
+               } catch (UnknownHostException e) {\r
+                       //defaultRealm="none";\r
+               }\r
+       }\r
+       \r
+\r
+       public static HttpTaf configHttpTaf(Access access, TrustChecker tc, CredVal up, Lur lur, Object ... additionalTafLurs) throws CadiException {\r
+               /////////////////////////////////////////////////////\r
+               // Setup AAFCon for any following\r
+               /////////////////////////////////////////////////////\r
+               Object aafcon = null;\r
+               if(lur != null) {\r
+                       Field f = null;\r
+                       try {\r
+                               f = lur.getClass().getField("aaf");\r
+                               aafcon = f.get(lur);\r
+                       } catch (Exception nsfe) {\r
+                       }\r
+               }\r
+               // IMPORTANT!  Don't attempt to load AAF Connector if there is no AAF URL\r
+               String aafURL = access.getProperty(AAF_URL,null);\r
+               if(aafcon==null && aafURL!=null) {\r
+                       aafcon = loadAAFConnector(access, aafURL);      \r
+               }\r
+               \r
+               HttpTaf taf;\r
+               // Setup Host, in case Network reports an unusable Hostname (i.e. VTiers, VPNs, etc)\r
+               String hostname = logProp(access, HOSTNAME,null);\r
+               if(hostname==null) {\r
+                       try {\r
+                               hostname = InetAddress.getLocalHost().getHostName();\r
+                       } catch (UnknownHostException e1) {\r
+                               throw new CadiException("Unable to determine Hostname",e1);\r
+                       }\r
+               }\r
+               \r
+               access.log(Level.INIT, "Hostname set to",hostname);\r
+               // Get appropriate TAFs\r
+               ArrayList<HttpTaf> htlist = new ArrayList<HttpTaf>();\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Add a Denial of Service TAF\r
+               // Note: how IPs and IDs are added are up to service type.\r
+               // They call "DenialOfServiceTaf.denyIP(String) or denyID(String)\r
+               /////////////////////////////////////////////////////\r
+               htlist.add(new DenialOfServiceTaf(access));\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Configure LocalHost \r
+               /////////////////////////////////////////////////////\r
+               \r
+               String truststore = logProp(access, CADI_TRUSTSTORE, access.getProperty("AFT_DME2_TRUSTSTORE", null));\r
+               if(truststore!=null) {\r
+                       String truststore_pwd = access.getProperty(CADI_TRUSTSTORE_PASSWORD, access.getProperty("AFT_DME2_TRUSTSTORE_PASSWORD",null));\r
+                       if(truststore_pwd!=null) {\r
+                               if(truststore_pwd.startsWith(Symm.ENC)) {\r
+                                       try {\r
+                                               truststore_pwd = access.decrypt(truststore_pwd,false);\r
+                                       } catch (IOException e) {\r
+                                               throw new CadiException(CADI_TRUSTSTORE_PASSWORD + " cannot be decrypted",e);\r
+                                       }\r
+                               }\r
+                               try {\r
+                                       htlist.add(new X509Taf(access,lur));\r
+                                       access.log(Level.INIT,"Certificate Authorization enabled");\r
+                               } catch (SecurityException e) {\r
+                                       access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);\r
+                               } catch (CertificateException e) {\r
+                                       access.log(Level.INIT,"Certificate Authorization failed, it is disabled",e);\r
+                               } catch (NoSuchAlgorithmException e) {\r
+                                       access.log(Level.INIT,"Certificate Authorization failed, wrong Security Algorithm",e);\r
+                               }\r
+                       }\r
+               } else {\r
+                       access.log(Level.INIT,"Certificate Authorization not enabled");\r
+               }\r
+               \r
+               /////////////////////////////////////////////////////\r
+               // Configure Basic Auth (local content)\r
+               /////////////////////////////////////////////////////\r
+               String basic_realm = logProp(access, BASIC_REALM,null);\r
+               boolean basic_warn = "TRUE".equals(access.getProperty(BASIC_WARN,"FALSE"));\r
+               if(basic_realm!=null && up!=null) {\r
+                       access.log(Level.INIT,"Basic Authorization is enabled using realm",basic_realm);\r
+                       // Allow warning about insecure channel to be turned off\r
+                       if(!basic_warn)access.log(Level.INIT,"WARNING! The basic_warn property has been set to false.",\r
+                                       " There will be no additional warning if Basic Auth is used on an insecure channel"\r
+                                       );\r
+                       String aafCleanup = logProp(access, AAF_USER_EXPIRES,AAF_USER_EXPIRES_DEF); // Default is 10 mins\r
+                       long userExp = Long.parseLong(aafCleanup);\r
+\r
+                       htlist.add(new BasicHttpTaf(access, up, basic_realm, userExp, basic_warn));\r
+               } else {\r
+                       access.log(Level.INIT,"Local Basic Authorization is disabled.  Enable by setting basic_realm=<appropriate realm, i.e. my.att.com>");\r
+               }\r
+               \r
+               /////////////////////////////////////////////////////\r
+               // Configure AAF Driven Basic Auth\r
+               /////////////////////////////////////////////////////\r
+               boolean getRemoteAAF = true;\r
+               if(additionalTafLurs!=null) {\r
+                       for(Object o : additionalTafLurs) {\r
+                               if(o.getClass().getSimpleName().equals("DirectAAFLur")) {\r
+                                       getRemoteAAF = false;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               HttpTaf aaftaf=null;\r
+               if(getRemoteAAF) {\r
+                       if(aafcon==null) {\r
+                               access.log(Level.INIT,"AAF Connection (AAFcon) is null.  Cannot create an AAF TAF");\r
+                       } else if(aafURL==null) {\r
+                               access.log(Level.INIT,"No AAF URL in properties, Cannot create an AAF TAF");\r
+                       } else {// There's an AAF_URL... try to configure an AAF \r
+                               String defName = aafURL.contains("version=2.0")?"com.att.cadi.aaf.v2_0.AAFTaf":"";\r
+                               String aafTafClassName = logProp(access, AAF_TAF_CLASS,defName);\r
+                               // Only 2.0 available at this time\r
+                               if("com.att.cadi.aaf.v2_0.AAFTaf".equals(aafTafClassName)) { \r
+                                       try {\r
+                                               Class<?> aafTafClass = loadClass(access,aafTafClassName);\r
+                                               Class<?> aafConClass = loadClass(access,"com.att.cadi.aaf.v2_0.AAFCon");\r
+       \r
+                                               Constructor<?> cstr = aafTafClass.getConstructor(aafConClass,boolean.class,AbsUserCache.class);\r
+                                               if(cstr!=null) {\r
+                                                       aaftaf = (HttpTaf)cstr.newInstance(aafcon,basic_warn,lur);\r
+                                                       if(aaftaf==null) {\r
+                                                               access.log(Level.INIT,"ERROR! AAF TAF Failed construction.  NOT Configured");\r
+                                                       } else {\r
+                                                               access.log(Level.INIT,"AAF TAF Configured to ",aafURL);\r
+                                                               // Note: will add later, after all others configured\r
+                                                       }\r
+                                               }\r
+                                       } catch(Exception e) {\r
+                                               access.log(Level.INIT,"ERROR! AAF TAF Failed construction.  NOT Configured");\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               \r
+               String alias = logProp(access, CADI_ALIAS,null);\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Configure tGuard... (AT&T Client Repo)\r
+               /////////////////////////////////////////////////////\r
+               // TGUARD Environment, translated to any other remote Environment validation mechanism...\r
+               String tGuard_domain = logProp(access, TGUARD_DOMAIN,null);\r
+               String tGuard_env = logProp(access, TGUARD_ENV, null);\r
+\r
+               if(!("PROD".equals(tGuard_env) || "STAGE".equals(tGuard_env))) {\r
+                       access.log(Level.INIT, "tGuard Authorization is disabled.  Enable by setting", TGUARD_ENV, "to \"PROD\" or \"STAGE\"");\r
+               } else if(tGuard_domain==null) {\r
+                       access.log(Level.INIT,TGUARD_DOMAIN + " must be set:  tGuard Authorization is disabled.");\r
+               } else if(alias == null) {\r
+                       access.log(Level.INIT,CADI_ALIAS + " must be set:  tGuard Authorization is disabled.");\r
+               } else {\r
+                       try {\r
+                               Class<?> tGuardClass = loadClass(access,"com.att.cadi.tguard.TGuardHttpTaf");\r
+                               if(aaftaf!=null) {\r
+                                       Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, AbsUserCache.class});\r
+                                       htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {access,aaftaf}));\r
+                                       access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");\r
+                               } else {\r
+                                       Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, int.class, int.class, int.class});\r
+                                       htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {\r
+                                                       access,\r
+                                                       Integer.parseInt(logProp(access, AAF_CLEAN_INTERVAL,AAF_CLEAN_INTERVAL_DEF)),\r
+                                                       Integer.parseInt(logProp(access, AAF_HIGH_COUNT, AAF_HIGH_COUNT_DEF)),\r
+                                                       Integer.parseInt(logProp(access, AAF_REFRESH_TRIGGER_COUNT, AAF_REFRESH_TRIGGER_COUNT_DEF))\r
+                                                       }));\r
+                                       access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");\r
+                               }\r
+                       } catch(Exception e) {\r
+                               access.log(e, Level.INIT,"tGuard Class cannot be loaded:  tGuard Authorization is disabled.");\r
+                       }\r
+               }\r
+               \r
+               /////////////////////////////////////////////////////\r
+               // Adding BasicAuth (AAF) last, after other primary Cookie Based\r
+               // Needs to be before Cert... see below\r
+               /////////////////////////////////////////////////////\r
+               if(aaftaf!=null) {\r
+                       htlist.add(aaftaf);\r
+               }\r
+\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Any Additional Lurs passed in Constructor\r
+               /////////////////////////////////////////////////////\r
+               if(additionalTafLurs!=null) {\r
+                       for(Object additional : additionalTafLurs) {\r
+                               if(additional instanceof HttpTaf) {\r
+                                       htlist.add((HttpTaf)additional);\r
+                                       access.log(Level.INIT,additional);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Create EpiTaf from configured TAFs\r
+               /////////////////////////////////////////////////////\r
+               if(htlist.size()==1) {\r
+                       // just return the one\r
+                       taf = htlist.get(0);\r
+               } else {\r
+                       HttpTaf[] htarray = new HttpTaf[htlist.size()];\r
+                       htlist.toArray(htarray);\r
+                       Locator<URI> locator = loadLocator(access, logProp(access, CADI_LOGINPAGE_URL, null));\r
+                       \r
+                       taf = new HttpEpiTaf(access,locator, tc, htarray); // ok to pass locator == null\r
+                       String level = logProp(access, CADI_LOGLEVEL, null);\r
+                       if(level!=null) {\r
+                               access.setLogLevel(Level.valueOf(level));\r
+                       }\r
+               }\r
+               \r
+               return taf;\r
+       }\r
+       \r
+       public static String logProp(Access access,String tag, String def) {\r
+               String rv = access.getProperty(tag, def);\r
+               if(rv == null) {\r
+                       access.log(Level.INIT,tag,"is not set");\r
+               } else {\r
+                       access.log(Level.INIT,tag,"is set to",rv);\r
+               }\r
+               return rv;\r
+       }\r
+       \r
+       public static Lur configLur(Access access, Object ... additionalTafLurs) throws CadiException {\r
+               List<Lur> lurs = new ArrayList<Lur>();\r
+               \r
+               /////////////////////////////////////////////////////\r
+               // Configure a Local Property Based RBAC/LUR\r
+               /////////////////////////////////////////////////////\r
+               try {\r
+                       String users = access.getProperty(USERS,null);\r
+                       String groups = access.getProperty(GROUPS,null);\r
+\r
+                       if(groups!=null || users!=null) {\r
+                               LocalLur ll;\r
+                               lurs.add(ll = new LocalLur(access, users, groups)); // note b64==null is ok.. just means no encryption.\r
+                               \r
+                               String writeto = access.getProperty(WRITE_TO,null);\r
+                               if(writeto!=null) {\r
+                                       String msg = UsersDump.updateUsers(writeto, ll);\r
+                                       if(msg!=null) access.log(Level.INIT,"ERROR! Error Updating ",writeto,"with roles and users:",msg);\r
+                               }\r
+                       }\r
+               } catch (IOException e) {\r
+                       throw new CadiException(e);\r
+               }\r
+               \r
+               /////////////////////////////////////////////////////\r
+               // Configure the AAF Lur (if any)\r
+               /////////////////////////////////////////////////////\r
+               String aafURL = logProp(access,AAF_URL,null); // Trigger Property\r
+               String aaf_env = access.getProperty(AAF_ENV,null);\r
+               if(aaf_env == null && aafURL!=null && access instanceof PropAccess) { // set AAF_ENV from AAF_URL\r
+                       int ec = aafURL.indexOf("envContext=");\r
+                       if(ec>0) {\r
+                               ec += 11; // length of envContext=\r
+                               int slash = aafURL.indexOf('/', ec);\r
+                               if(slash>0) {\r
+                                       aaf_env = aafURL.substring(ec, slash);\r
+                                       ((PropAccess)access).setProperty(AAF_ENV, aaf_env);\r
+                                       access.printf(Level.INIT, "Setting aaf_env to %s from aaf_url value",aaf_env);\r
+                               }\r
+                       }\r
+               }\r
+                       \r
+               if(aafURL==null) {\r
+                       access.log(Level.INIT,"No AAF LUR properties, AAF will not be loaded");\r
+               } else {// There's an AAF_URL... try to configure an AAF\r
+                       String aafLurClassStr = logProp(access,AAF_LUR_CLASS,"com.att.cadi.aaf.v2_0.AAFLurPerm");\r
+                       ////////////AAF Lur 2.0 /////////////\r
+                       if(aafLurClassStr.startsWith("com.att.cadi.aaf.v2_0")) { \r
+                               try {\r
+                                       Object aafcon = loadAAFConnector(access, aafURL);\r
+                                       if(aafcon==null) {\r
+                                               access.log(Level.INIT,"AAF LUR class,",aafLurClassStr,"cannot be constructed without valid AAFCon object.");\r
+                                       } else {\r
+                                               Class<?> aafAbsAAFCon = loadClass(access, "com.att.cadi.aaf.v2_0.AAFCon");\r
+                                               Method mNewLur = aafAbsAAFCon.getMethod("newLur");\r
+                                               Object aaflur = mNewLur.invoke(aafcon);\r
+       \r
+                                               if(aaflur==null) {\r
+                                                       access.log(Level.INIT,"ERROR! AAF LUR Failed construction.  NOT Configured");\r
+                                               } else {\r
+                                                       access.log(Level.INIT,"AAF LUR Configured to ",aafURL);\r
+                                                       lurs.add((Lur)aaflur);\r
+                                                       String debugIDs = logProp(access,Config.AAF_DEBUG_IDS, null);\r
+                                                       if(debugIDs !=null && aaflur instanceof CachingLur) {\r
+                                                               ((CachingLur<?>)aaflur).setDebug(debugIDs);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } catch (Exception e) {\r
+                                       access.log(e,"AAF LUR class,",aafLurClassStr,"could not be constructed with given Constructors.");\r
+                               }\r
+                       } \r
+               } \r
+\r
+               /////////////////////////////////////////////////////\r
+               // Any Additional passed in Constructor\r
+               /////////////////////////////////////////////////////\r
+               if(additionalTafLurs!=null) {\r
+                       for(Object additional : additionalTafLurs) {\r
+                               if(additional instanceof Lur) {\r
+                                       lurs.add((Lur)additional);\r
+                                       access.log(Level.INIT, additional);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               /////////////////////////////////////////////////////\r
+               // Return a Lur based on how many there are... \r
+               /////////////////////////////////////////////////////\r
+               switch(lurs.size()) {\r
+                       case 0: \r
+                               access.log(Level.INIT,"WARNING! No CADI LURs configured");\r
+                               // Return a NULL Lur that does nothing.\r
+                               return new NullLur();\r
+                       case 1:\r
+                               return lurs.get(0); // Only one, just return it, save processing\r
+                       default:\r
+                               // Multiple Lurs, use EpiLUR to handle\r
+                               Lur[] la = new Lur[lurs.size()];\r
+                               lurs.toArray(la);\r
+                               return new EpiLur(la);\r
+               }\r
+       }\r
+       \r
+       private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2 = "com.att.cadi.aaf.v2_0.AAFConDME2";\r
+       private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP = "com.att.cadi.aaf.v2_0.AAFConHttp";\r
+       public static Object loadAAFConnector(Access access, String aafURL) {\r
+               Object aafcon = null;\r
+               Class<?> aafConClass = null;\r
+\r
+               try {\r
+                       if(aafURL!=null) {\r
+                               String aafConnector = access.getProperty(AAF_CONNECTOR_CLASS, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);\r
+                               if(COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2.equals(aafConnector) || aafURL.contains("/service=")) {\r
+                                       aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2);\r
+                                       if(aafConClass!=null) {\r
+                                               Constructor<?> cons = aafConClass.getConstructor(PropAccess.class);\r
+                                               aafcon = cons.newInstance(access);\r
+                                       } else {\r
+                                               access.log(Level.ERROR, "URL contains '/service=', which requires DME2");\r
+                                       }\r
+                               } else if(COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP.equals(aafConnector)) {\r
+                                       aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);\r
+                                       for(Constructor<?> c : aafConClass.getConstructors()) {\r
+                                               List<Object> lo = new ArrayList<Object>();\r
+                                               for(Class<?> pc : c.getParameterTypes()) {\r
+                                                       if(pc.equals(PropAccess.class)) {\r
+                                                               lo.add(access);\r
+                                                       } else if(pc.equals(Locator.class)) {\r
+                                                               lo.add(loadLocator(access, aafURL));\r
+                                                       } else {\r
+                                                               continue;\r
+                                                       }\r
+                                               }\r
+                                               if(c.getParameterTypes().length!=lo.size()) {\r
+                                                       continue; // back to another Constructor\r
+                                               } else {\r
+                                                       aafcon = c.newInstance(lo.toArray());\r
+                                               }\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if(aafcon!=null) {\r
+                                       String mechid = logProp(access,Config.AAF_MECHID, null);\r
+                                       String pass = access.getProperty(Config.AAF_MECHPASS, null);\r
+                                       if(mechid!=null && pass!=null) {\r
+                                               try {\r
+                                                       Method basicAuth = aafConClass.getMethod("basicAuth", String.class, String.class);\r
+                                                       basicAuth.invoke(aafcon, mechid,pass);\r
+                                               } catch (NoSuchMethodException nsme) {\r
+                                                       // it's ok, don't use\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               } catch (Exception e) {\r
+                       access.log(e,"AAF Connector could not be constructed with given Constructors.");\r
+               }\r
+               \r
+               return aafcon;\r
+       }\r
+\r
+       public static Class<?> loadClass(Access access, String className) {\r
+               Class<?> cls=null;\r
+               try {\r
+                       cls = access.classLoader().loadClass(className);\r
+               } catch (ClassNotFoundException cnfe) {\r
+                       try {\r
+                               cls = access.getClass().getClassLoader().loadClass(className);\r
+                       } catch (ClassNotFoundException cnfe2) {\r
+                               // just return null\r
+                       }\r
+               }\r
+               return cls;\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public static Locator<URI> loadLocator(Access access, String url) {\r
+               Locator<URI> locator = null;\r
+               if(url==null) {\r
+                       access.log(Level.INIT,"No URL for AAF Login Page. Disabled");\r
+               } else {\r
+                       if(url.contains("DME2RESOLVE")) {\r
+                               try {\r
+                                       Class<?> lcls = loadClass(access,"com.att.cadi.locator.DME2Locator");\r
+                                       Class<?> dmcls = loadClass(access,"com.att.aft.dme2.api.DME2Manager");\r
+                                       Constructor<?> cnst = lcls.getConstructor(new Class[] {Access.class,dmcls,String.class});\r
+                                       locator = (Locator<URI>)cnst.newInstance(new Object[] {access,null,url});\r
+                                       access.log(Level.INFO, "DME2Locator enabled with " + url);\r
+                               } catch (Exception e) {\r
+                                       access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires DME2. It is now disabled",e);\r
+                               }\r
+                       } else {\r
+                               try {\r
+                                       Class<?> cls = loadClass(access,"com.att.cadi.locator.PropertyLocator");\r
+                                       Constructor<?> cnst = cls.getConstructor(new Class[] {String.class});\r
+                                       locator = (Locator<URI>)cnst.newInstance(new Object[] {url});\r
+                                       access.log(Level.INFO, "PropertyLocator enabled with " + url);\r
+                               } catch (Exception e) {\r
+                                       access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires PropertyLocator. It is now disabled",e);\r
+                               }\r
+                       }\r
+               }\r
+               return locator;\r
+       }\r
+\r
+       /*\r
+        * DME2 can only read Passwords as clear text properties.  Leaving in "System Properties" un-encrypted exposes these passwords\r
+        */\r
+       public static class PasswordRemoval extends TimerTask {\r
+               private Access access;\r
+               \r
+               private final List<String> pws;\r
+\r
+               public PasswordRemoval(Access access) {\r
+                       this.access = access;\r
+                       pws = new ArrayList<String>();\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       for(String key:pws) {\r
+                               access.log(Level.INIT, "Scrubbing " + key);\r
+                               System.clearProperty(key);\r
+                       }\r
+               }               \r
+               public void add(String key) {\r
+                       pws.add(key);\r
+               }\r
+       }\r
+\r
+       private static final String Y = "Y";\r
+\r
+       private static String[][] CONVERTER_STRINGS=new String[][] {\r
+                       {AFT_DME2_KEYSTORE,CADI_KEYSTORE,null},\r
+                       {AFT_DME2_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},\r
+                       {AFT_DME2_KEY_PASSWORD,CADI_KEY_PASSWORD,null},\r
+                       {AFT_DME2_TRUSTSTORE,CADI_TRUSTSTORE,null},\r
+                       {AFT_DME2_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},\r
+                       {AFT_DME2_CLIENT_KEYSTORE,CADI_KEYSTORE,null},\r
+                       {AFT_DME2_CLIENT_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},\r
+                       {AFT_DME2_CLIENT_TRUSTSTORE,CADI_TRUSTSTORE,null},\r
+                       {AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},\r
+                       {AFT_DME2_CLIENT_SSL_CERT_ALIAS,CADI_ALIAS,null},\r
+                       {AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},\r
+                       {"AFT_DME2_HOSTNAME",HOSTNAME,null},\r
+                       {"AFT_LATITUDE",null,Y},\r
+                       {"AFT_LONGITUDE",null,Y},\r
+                       {"AFT_ENVIRONMENT",null,Y},\r
+                       {"SCLD_PLATFORM",null,Y},\r
+                       {"DME2_EP_REGISTRY_CLASS",null,Y},// for Developer local access\r
+                       {"AFT_DME2_EP_REGISTRY_FS_DIR",null,Y},\r
+                       {"DME2.DEBUG",null,null},\r
+                       {"AFT_DME2_HTTP_EXCHANGE_TRACE_ON",null,null},\r
+                       {"AFT_DME2_SSL_ENABLE",null,null},\r
+                       {"AFT_DME2_SSL_WANT_CLIENT_AUTH",null,null},\r
+                       {AFT_DME2_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},\r
+                       {"AFT_DME2_SSL_VALIDATE_CERTS",null,null},\r
+                       {AFT_DME2_CLIENT_IGNORE_SSL_CONFIG,null,null},\r
+                       {"https.protocols",CADI_PROTOCOLS,Y},\r
+                       };\r
+\r
+\r
+\r
+       public static Properties getDME2Props(PropAccess access) {\r
+               Properties dprops = new Properties();\r
+               String value = null;\r
+               boolean reqClientConfig = false;\r
+               for(String[] row : CONVERTER_STRINGS) {\r
+                       value = access.getProperty(row[0],null);\r
+                       if(value==null) {\r
+                               value = System.getProperty(row[0]);\r
+                               if(value==null && row[1]!=null) {\r
+                                       value = access.getProperty(row[1],null);\r
+                                       if(value == null) {\r
+                                               value = System.getProperty(row[1]);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if(value!=null) {\r
+                               if(row[0].contains("_SSL_")) {\r
+                                       reqClientConfig = true;\r
+                               }\r
+                               if(row[0].startsWith("AFT") || row[0].startsWith("SCLD") || row[0].contains("DME2")) {\r
+                                       if(value.startsWith("enc:")) {\r
+                                               try {\r
+                                                       value = access.decrypt(value, true);\r
+                                               } catch (IOException e) {\r
+                                                       access.log(Level.ERROR, e);\r
+                                               }\r
+                                               System.setProperty(row[0], value);\r
+                                       } else if(Y.equals(row[2])) {\r
+                                               System.setProperty(row[0], value);\r
+                                               dprops.setProperty(row[0], value);\r
+                                       } else if(row[0].contains("PASSWORD") || row[0].contains("STORE")) {\r
+                                               System.setProperty(row[0], value);\r
+                                       } else {\r
+                                               dprops.setProperty(row[0], value);\r
+                                       }\r
+                               }\r
+                               \r
+                       }\r
+                       \r
+               }\r
+               \r
+               Properties sprops = System.getProperties();\r
+               if(reqClientConfig && sprops.getProperty(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {\r
+                       sprops.put(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG, "false");\r
+                       replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE,AFT_DME2_TRUSTSTORE);\r
+                       replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE_PASSWORD,AFT_DME2_TRUSTSTORE_PASSWORD);\r
+                       replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE,AFT_DME2_CLIENT_TRUSTSTORE);\r
+                       replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE_PASSWORD,AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD);\r
+               }\r
+               \r
+               if(sprops.getProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS)==null) {\r
+                       sprops.setProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));\r
+               }\r
+\r
+               if(sprops.getProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS)==null) {\r
+                       sprops.setProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));\r
+               }\r
+               \r
+               if(access.willLog(Level.DEBUG)) {\r
+                       if(access instanceof PropAccess) {\r
+                               access.log(Level.DEBUG,"Access Properties");\r
+                               for(Entry<Object, Object> es : ((PropAccess)access).getProperties().entrySet()) {\r
+                                       access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),es.getValue().toString());\r
+                               }\r
+                       }\r
+                       access.log(Level.DEBUG,"DME2 Properties()");\r
+                       for(Entry<Object, Object> es : dprops.entrySet()) {\r
+                               value = es.getValue().toString();\r
+                               if(es.getKey().toString().contains("PASS")) {\r
+                                       if(value==null || !value.contains("enc:")) {\r
+                                               value = HIDE_PASS;\r
+                                       }\r
+                               }\r
+                               access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),value);\r
+                       }\r
+                       \r
+                       access.log(Level.DEBUG,"System (AFT) Properties");\r
+                       for(Entry<Object, Object> es : System.getProperties().entrySet()) {\r
+                               if(es.getKey().toString().startsWith("AFT")) {\r
+                                       value = es.getValue().toString();\r
+                                       if(es.getKey().toString().contains("PASS")) {\r
+                                               if(value==null || !value.contains("enc:")) {\r
+                                                       value = HIDE_PASS;\r
+                                               }\r
+                                       }\r
+                                       access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),value);\r
+                               }\r
+                       }\r
+               }\r
+               // Cover any not specific AFT props\r
+               String key;\r
+               for(Entry<Object, Object> es : access.getProperties().entrySet()) {\r
+                       if((key=es.getKey().toString()).startsWith("AFT_") && \r
+                                       !key.contains("PASSWORD") &&\r
+                                       dprops.get(key)==null) {\r
+                               dprops.put(key, es.getValue());\r
+                       }\r
+               }\r
+               return dprops;\r
+       }\r
+       \r
+       private static void replaceKeyWithTrust(Properties props, String ks, String ts) {\r
+               String value;\r
+               if(props.get(ks)==null && (value=props.getProperty(ts))!=null) {\r
+                       props.put(ks,value);\r
+                       props.remove(ts);\r
+               }\r
+       }\r
+       // Set by CSP, or is hostname.\r
+       public static String getDefaultRealm() {\r
+               return defaultRealm;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/Get.java b/core/src/main/java/com/att/cadi/config/Get.java
new file mode 100644 (file)
index 0000000..d6bb35b
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+\r
+public interface Get {\r
+       public String get(String name, String def, boolean print);\r
+       \r
+       \r
+       /**\r
+        * A class for Getting info out of "JavaBean" format\r
+        *\r
+        */\r
+       public static class Bean implements Get {\r
+               private Object bean;\r
+               private Class<?> bc;\r
+               private Class<?>[] params;\r
+               private Object[] args;\r
+               \r
+               public Bean(Object bean) {\r
+                       this.bean = bean;\r
+                       bc = bean.getClass();\r
+                       params = new Class<?>[0]; // note, this will allow to go out of scope after config\r
+                       args = new Object[0];\r
+               }\r
+               \r
+               public String get(String name, String def, boolean print) {\r
+                       String str = null;\r
+                       String gname = "get"+Character.toUpperCase(name.charAt(0))+name.substring(1);\r
+                       try {\r
+                               Method meth = bc.getMethod(gname, params);\r
+                               Object obj = meth.invoke(bean, args);\r
+                               str = obj==null?null:obj.toString(); // easy string convert... \r
+                       } catch (Exception e) {\r
+                       }\r
+                       \r
+                       // Take def if nothing else\r
+                       if(str==null) {\r
+                               str = def;\r
+                               // don't log defaults\r
+                       } else {\r
+                               str = str.trim(); // this is vital in Property File based values, as spaces can hide easily\r
+                       }\r
+                       // Note: Can't log during configuration\r
+                       return str;\r
+               }\r
+       }\r
+\r
+       public static Get NULL = new Get() {\r
+               public String get(String name, String def, boolean print) {\r
+                       return def;\r
+               }\r
+       };\r
+\r
+       public static class AccessGet implements Get {\r
+               private Access access;\r
+               public AccessGet(Access access) {\r
+                       this.access = access;\r
+               }\r
+               public String get(String name, String def, boolean print) {\r
+                       String gotten = access.getProperty(name, def);\r
+                       if(print) {\r
+                               if(gotten == null) {\r
+                                       access.log(Level.INIT,name, "is not set");\r
+                               } else {\r
+                                       access.log(Level.INIT,name, "is set to", gotten);\r
+                               }\r
+                       }\r
+                       return gotten;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/GetAccess.java b/core/src/main/java/com/att/cadi/config/GetAccess.java
new file mode 100644 (file)
index 0000000..bdd6afd
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import com.att.cadi.PropAccess;\r
+\r
+public class GetAccess extends PropAccess {\r
+       private final Get getter;\r
+       \r
+       public GetAccess(Get getter) {\r
+               super(new String[]{"cadi_prop_files="+getter.get("cadi_prop_files", null, true)});\r
+               this.getter = getter;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.PropAccess#getProperty(java.lang.String, java.lang.String)\r
+        */\r
+       @Override\r
+       public String getProperty(String tag, String def) {\r
+               String rv;\r
+               rv = super.getProperty(tag, null);\r
+               if(rv==null && getter!=null) {\r
+                       rv = getter.get(tag, null, true);\r
+               }\r
+               return rv==null?def:rv;\r
+       }\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.PropAccess#getProperty(java.lang.String)\r
+        */\r
+       @Override\r
+       public String getProperty(String tag) {\r
+               String rv;\r
+               rv = super.getProperty(tag, null);\r
+               if(rv==null && getter!=null) {\r
+                       rv = getter.get(tag, null, true);\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       public Get get() {\r
+               return getter;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/MultiGet.java b/core/src/main/java/com/att/cadi/config/MultiGet.java
new file mode 100644 (file)
index 0000000..a304319
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+public class MultiGet implements Get {\r
+    private Get[] getters;\r
+\r
+    public MultiGet(Get ... getters) {\r
+        this.getters = getters;\r
+    }\r
+\r
+    @Override\r
+    public String get(String name, String def, boolean print) {\r
+        String str;\r
+        for(Get getter : getters) {\r
+            str = getter.get(name, null, print);\r
+            if(str!=null) \r
+                return str;\r
+        }\r
+        return def;\r
+    }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/SecurityInfo.java b/core/src/main/java/com/att/cadi/config/SecurityInfo.java
new file mode 100644 (file)
index 0000000..a1ef35b
--- /dev/null
@@ -0,0 +1,244 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.rmi.AccessException;\r
+import java.security.GeneralSecurityException;\r
+import java.security.KeyStore;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.X509Certificate;\r
+import java.util.ArrayList;\r
+\r
+import javax.net.ssl.HostnameVerifier;\r
+import javax.net.ssl.HttpsURLConnection;\r
+import javax.net.ssl.KeyManager;\r
+import javax.net.ssl.KeyManagerFactory;\r
+import javax.net.ssl.SSLContext;\r
+import javax.net.ssl.SSLSession;\r
+import javax.net.ssl.SSLSocketFactory;\r
+import javax.net.ssl.TrustManager;\r
+import javax.net.ssl.TrustManagerFactory;\r
+import javax.net.ssl.X509KeyManager;\r
+import javax.net.ssl.X509TrustManager;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.util.MaskFormatException;\r
+import com.att.cadi.util.NetMask;\r
+\r
+public class SecurityInfo {\r
+       private static final String SECURITY_ALGO = "RSA";\r
+       private static final String HTTPS_PROTOCOLS = "https.protocols";\r
+       private static final String JDK_TLS_CLIENT_PROTOCOLS = "jdk.tls.client.protocols";\r
+\r
+       public static final String HTTPS_PROTOCOLS_DEFAULT = "TLSv1.1,TLSv1.2";\r
+       public static final String REGEX_COMMA = "\\s*,\\s*";\r
+       public static final String SslKeyManagerFactoryAlgorithm;\r
+       \r
+       private SSLSocketFactory scf;\r
+       private X509KeyManager[] km;\r
+       private X509TrustManager[] tm;\r
+       public final String default_alias;\r
+       private NetMask[] trustMasks;\r
+       private SSLContext ctx;\r
+       private HostnameVerifier maskHV;\r
+\r
+       // Change Key Algorithms for IBM's VM.  Could put in others, if needed.\r
+       static {\r
+               if(System.getProperty("java.vm.vendor").equalsIgnoreCase("IBM Corporation")) {\r
+                       SslKeyManagerFactoryAlgorithm = "IbmX509";\r
+               } else {\r
+                       SslKeyManagerFactoryAlgorithm = "SunX509";\r
+               }\r
+       }\r
+       \r
+\r
+       public SecurityInfo(final Access access) throws GeneralSecurityException, IOException {\r
+               // reuse DME2 Properties for convenience if specific Properties don't exist\r
+               String keyStore = access.getProperty(Config.CADI_KEYSTORE,\r
+                               access.getProperty(Config.AFT_DME2_KEYSTORE,null));\r
+               String keyStorePasswd = access.getProperty(Config.CADI_KEYSTORE_PASSWORD,\r
+                               access.getProperty(Config.AFT_DME2_KEYSTORE_PASSWORD, null));\r
+               keyStorePasswd = keyStorePasswd==null?null:access.decrypt(keyStorePasswd,false);\r
+               String trustStore = access.getProperty(Config.CADI_TRUSTSTORE,\r
+                               access.getProperty(Config.AFT_DME2_TRUSTSTORE, null));\r
+               String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD,\r
+                               access.getProperty(Config.AFT_DME2_TRUSTSTORE_PASSWORD,null));\r
+               trustStorePasswd = trustStorePasswd==null?null:access.decrypt(trustStorePasswd,false);\r
+               default_alias = access.getProperty(Config.CADI_ALIAS, \r
+                               access.getProperty(Config.AFT_DME2_CLIENT_SSL_CERT_ALIAS,null));\r
+               \r
+               String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD,null);\r
+               keyPasswd = keyPasswd==null?keyStorePasswd:access.decrypt(keyPasswd,false);\r
+               String tips=access.getProperty(Config.CADI_TRUST_MASKS, null);\r
+               if(tips!=null) {\r
+                       access.log(Level.INIT,"Explicitly accepting valid X509s from",tips);\r
+                       String[] ipsplit = tips.split(REGEX_COMMA);\r
+                       trustMasks = new NetMask[ipsplit.length];\r
+                       for(int i=0;i<ipsplit.length;++i) {\r
+                               try {\r
+                                       trustMasks[i]=new NetMask(ipsplit[i]);\r
+                               } catch (MaskFormatException e) {\r
+                                       throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS,e);\r
+                               }\r
+                       }\r
+               }\r
+               String https_protocols = Config.logProp(access,Config.CADI_PROTOCOLS, \r
+                               access.getProperty(Config.AFT_DME2_SSL_INCLUDE_PROTOCOLS, \r
+                                       access.getProperty(HTTPS_PROTOCOLS,HTTPS_PROTOCOLS_DEFAULT)\r
+                                       ));\r
+               System.setProperty(HTTPS_PROTOCOLS,https_protocols);\r
+               System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, https_protocols);\r
+               \r
+               KeyManagerFactory kmf = KeyManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);\r
+               File file;\r
+\r
+\r
+               if(keyStore==null || keyStorePasswd == null) { \r
+                       km = new X509KeyManager[0];\r
+               } else {\r
+                       ArrayList<X509KeyManager> kmal = new ArrayList<X509KeyManager>();\r
+                       for(String ksname : keyStore.split(REGEX_COMMA)) {\r
+                               file = new File(ksname);\r
+                               String keystoreFormat;\r
+                               if(ksname.endsWith("pkcs12")) {\r
+                                       keystoreFormat = "PKCS12";\r
+                               } else {\r
+                                       keystoreFormat = "JKS";\r
+                               }\r
+                               if(file.exists()) {\r
+                                       FileInputStream fis = new FileInputStream(file);\r
+                                       try {\r
+                                               KeyStore ks = KeyStore.getInstance(keystoreFormat);\r
+                                               ks.load(fis, keyStorePasswd.toCharArray());\r
+                                               kmf.init(ks, keyPasswd.toCharArray());\r
+                                       } finally {\r
+                                               fis.close();\r
+                                       }\r
+                               }\r
+                       }\r
+                       for(KeyManager km : kmf.getKeyManagers()) {\r
+                               if(km instanceof X509KeyManager) {\r
+                                       kmal.add((X509KeyManager)km);\r
+                               }\r
+                       }\r
+                       km = new X509KeyManager[kmal.size()];\r
+                       kmal.toArray(km);\r
+               }\r
+\r
+               TrustManagerFactory tmf = TrustManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);\r
+               if(trustStore!=null) {\r
+                       for(String tsname : trustStore.split(REGEX_COMMA)) {\r
+                               file = new File(tsname);\r
+                               if(file.exists()) {\r
+                                       FileInputStream fis = new FileInputStream(file);\r
+                                       try {\r
+                                               KeyStore ts = KeyStore.getInstance("JKS");\r
+                                               ts.load(fis, trustStorePasswd.toCharArray());\r
+                                               tmf.init(ts); \r
+                                       } finally {\r
+                                               fis.close();\r
+                                       }\r
+                               }\r
+                       }\r
+                       TrustManager tms[] = tmf.getTrustManagers();\r
+                       tm = new X509TrustManager[tms==null?0:tms.length];\r
+                       for(int i=0;i<tms.length;++i) {\r
+                               try {\r
+                                       tm[i]=(X509TrustManager)tms[i];\r
+                               } catch (ClassCastException e) {\r
+                                       access.log(Level.WARN, "Non X509 TrustManager", tm[i].getClass().getName(),"skipped in SecurityInfo");\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               if(trustMasks!=null) {\r
+                       final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();\r
+                       HttpsURLConnection.setDefaultHostnameVerifier(maskHV = new HostnameVerifier() {\r
+                               @Override\r
+                               public boolean verify(final String urlHostName, final SSLSession session) {\r
+                                       try {\r
+                                               // This will pick up /etc/host entries as well as DNS\r
+                                               InetAddress ia = InetAddress.getByName(session.getPeerHost());\r
+                                               for(NetMask tmask : trustMasks) {\r
+                                                       if(tmask.isInNet(ia.getHostAddress())) {\r
+                                                               return true;\r
+                                                       }\r
+                                               }\r
+                                       } catch (UnknownHostException e) {\r
+                                               // It's ok. do normal Verify\r
+                                       }\r
+                                       return origHV.verify(urlHostName,session);\r
+                               };\r
+                       });\r
+               }\r
+               ctx = SSLContext.getInstance("TLS");\r
+               ctx.init(km, tm, null);\r
+               SSLContext.setDefault(ctx);\r
+               scf = ctx.getSocketFactory();\r
+       }\r
+\r
+       /**\r
+        * @return the scf\r
+        */\r
+       public SSLSocketFactory getSSLSocketFactory() {\r
+               return scf;\r
+       }\r
+\r
+       public SSLContext getSSLContext() {\r
+               return ctx;\r
+       }\r
+\r
+       /**\r
+        * @return the km\r
+        */\r
+       public X509KeyManager[] getKeyManagers() {\r
+               return km;\r
+       }\r
+\r
+       public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {\r
+               for(X509TrustManager xtm : tm) {\r
+                       xtm.checkClientTrusted(certarr, SECURITY_ALGO);\r
+               }\r
+       }\r
+\r
+       public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {\r
+               for(X509TrustManager xtm : tm) {\r
+                       xtm.checkServerTrusted(certarr, SECURITY_ALGO);\r
+               }\r
+       }\r
+\r
+       public void setSocketFactoryOn(HttpsURLConnection hsuc) {\r
+               hsuc.setSSLSocketFactory(scf);\r
+               if(maskHV!=null && !maskHV.equals(hsuc.getHostnameVerifier())) {\r
+                       hsuc.setHostnameVerifier(maskHV);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/SecurityInfoC.java b/core/src/main/java/com/att/cadi/config/SecurityInfoC.java
new file mode 100644 (file)
index 0000000..5e2fd54
--- /dev/null
@@ -0,0 +1,45 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import java.io.IOException;\r
+import java.security.GeneralSecurityException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.SecuritySetter;\r
+\r
+\r
+public class SecurityInfoC<CLIENT> extends SecurityInfo {\r
+       public SecuritySetter<CLIENT> defSS;\r
+\r
+       public SecurityInfoC(Access access) throws GeneralSecurityException, IOException {\r
+               super(access);\r
+       }\r
+\r
+       public SecurityInfoC<CLIENT> set(SecuritySetter<CLIENT> defSS) {\r
+               this.defSS = defSS;\r
+               return this;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/config/UsersDump.java b/core/src/main/java/com/att/cadi/config/UsersDump.java
new file mode 100644 (file)
index 0000000..7d47b7e
--- /dev/null
@@ -0,0 +1,159 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.config;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.io.PrintStream;\r
+import java.util.Date;\r
+import java.util.HashSet;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.lur.LocalLur;\r
+\r
+public class UsersDump {\r
+\r
+       /**\r
+        * @param args\r
+        */\r
+       public static boolean write(OutputStream os, AbsUserCache<?> lur) {\r
+               PrintStream ps;\r
+               if(os instanceof PrintStream) {\r
+                       ps = (PrintStream)os;\r
+               } else {\r
+                       ps = new PrintStream(os);\r
+               }\r
+               try {\r
+                       ps.println("<?xml version='1.0' encoding='utf-8'?>");\r
+                       ps.println("<!--");\r
+                       ps.print(  "     Code Generated Tomcat Users and Roles from AT&T LUR on ");\r
+                       ps.println(new Date());\r
+                       ps.println(  "-->");\r
+                       ps.println("<tomcat-users>");\r
+\r
+                       // We loop through Users, but want to write Groups first... therefore, save off print\r
+                       StringBuilder sb = new StringBuilder();\r
+                       \r
+                       // Obtain all unique role names\r
+                       HashSet<String> groups = new HashSet<String>();\r
+                       for(AbsUserCache<?>.DumpInfo di : lur.dumpInfo()) {\r
+                               sb.append("\n  <user username=\"");\r
+                               sb.append(di.user);\r
+                               sb.append("\" roles=\"");\r
+                               boolean first = true;\r
+                               for(String role : di.perms) {\r
+                                       groups.add(role);\r
+                                       if(first)first = false;\r
+                                       else sb.append(',');\r
+                                       sb.append(role);\r
+                               }\r
+                               sb.append("\"/>");\r
+\r
+                       }\r
+\r
+                       // Print roles\r
+                       for(String group : groups) {\r
+                               ps.print("  <role rolename=\"");\r
+                               ps.print(group);\r
+                               ps.println("\"/>");\r
+                       }\r
+       \r
+                       ps.println(sb);\r
+\r
+                       ps.println("</tomcat-users>");\r
+                       ps.flush();\r
+               } catch (Throwable t) {\r
+                       t.printStackTrace(ps);\r
+                       return false;\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       /**\r
+        * \r
+        * Note: This method returns a String if there's an error, or null if ok.\r
+        * This unusual style is necessitated by the fact that any Exceptions thrown are likely to \r
+        * be unlogged and hidden from view, making debugging almost impossible.\r
+        * \r
+        * @param writeto\r
+        * @param up\r
+        * @return\r
+        */\r
+       public static String updateUsers(String writeto, LocalLur up) {\r
+               // Dump a Tomcat-user.xml lookalike (anywhere)\r
+               if(writeto!=null) {\r
+                       // First read content\r
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+                       if(UsersDump.write(baos, up)) {\r
+                               byte[] postulate = baos.toByteArray();\r
+                               // now get contents of file\r
+                               File file = new File(writeto);\r
+                               boolean writeIt;\r
+                               if(file.exists()) {\r
+                                       try {\r
+                                               FileInputStream fis = new FileInputStream(file);\r
+                                               byte[] orig = new byte[(int)file.length()];\r
+                                               try {\r
+                                                       fis.read(orig);\r
+                                               } finally {\r
+                                                       fis.close();\r
+                                               }\r
+                                               // Starting at third "<" (<tomcat-users> line)\r
+                                               int startA=0, startB=0;\r
+                                               for(int i=0;startA<orig.length && i<3;++startA) if(orig[startA]=='<')++i;\r
+                                               for(int i=0;startB<orig.length && i<3;++startB) if(postulate[startB]=='<')++i;\r
+                                               \r
+                                               writeIt=orig.length-startA!=postulate.length-startB; // first, check if remaining length is the same\r
+                                               while(!writeIt && startA<orig.length && startB<postulate.length) {\r
+                                                       if(orig[startA++]!=postulate[startB++])writeIt = true;\r
+                                               }\r
+                                       } catch (Exception e) {\r
+                                               writeIt = true;\r
+                                       }\r
+                               } else {\r
+                                       writeIt = true;\r
+                               }\r
+                               \r
+                               if(writeIt) {\r
+                                       try {\r
+                                               FileOutputStream fos = new FileOutputStream(file);\r
+                                               try {\r
+                                                       fos.write(postulate);\r
+                                               } finally {\r
+                                                       fos.close();\r
+                                               }\r
+                                       } catch (IOException e) {\r
+                                               return e.getMessage();\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return null; // no message means ok.\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/AUTHZ.java b/core/src/main/java/com/att/cadi/filter/AUTHZ.java
new file mode 100644 (file)
index 0000000..8f33105
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import static java.lang.annotation.ElementType.TYPE;\r
+import static java.lang.annotation.RetentionPolicy.RUNTIME;\r
+\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.Target;\r
+\r
+import javax.servlet.Servlet;\r
+\r
+@Target({TYPE})\r
+@Retention(RUNTIME)\r
+public @interface AUTHZ {\r
+       Class<? extends Servlet> value();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/AUTHZServlet.java b/core/src/main/java/com/att/cadi/filter/AUTHZServlet.java
new file mode 100644 (file)
index 0000000..dab6b47
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.io.IOException;\r
+\r
+import javax.servlet.Servlet;\r
+import javax.servlet.ServletConfig;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+/**\r
+ * \r
+ *\r
+ */\r
+public class AUTHZServlet<S extends Servlet> implements Servlet {\r
+       private String[] roles;\r
+       private Servlet delegate;\r
+\r
+       protected AUTHZServlet(Class<S> cls) {\r
+               try {\r
+                       delegate = cls.newInstance();\r
+               } catch (Exception e) {\r
+                       delegate = null;\r
+               }\r
+               RolesAllowed rolesAllowed = cls.getAnnotation(RolesAllowed.class);\r
+               if(rolesAllowed == null) {\r
+                       roles = null;\r
+               } else {\r
+                       roles = rolesAllowed.value();\r
+               }\r
+       }\r
+       \r
+       public void init(ServletConfig sc) throws ServletException {\r
+               if(delegate == null) throw new ServletException("Invalid Servlet Delegate");\r
+               delegate.init(sc);\r
+       }\r
+       \r
+       public ServletConfig getServletConfig() {\r
+               return delegate.getServletConfig();\r
+       }\r
+\r
+       public String getServletInfo() {\r
+               return delegate.getServletInfo();\r
+       }\r
+\r
+       public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {\r
+               if(roles==null) {\r
+                       delegate.service(req,resp);\r
+               } else { // Validate\r
+                       try {\r
+                               HttpServletRequest hreq = (HttpServletRequest)req;\r
+                               boolean proceed = false;\r
+                               for(String role : roles) {\r
+                                       if(hreq.isUserInRole(role)) {\r
+                                               proceed = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if(proceed) {\r
+                                       delegate.service(req,resp);\r
+                               } else {\r
+                                       //baseRequest.getServletContext().log(hreq.getUserPrincipal().getName()+" Refused " + roles);\r
+                                       ((HttpServletResponse)resp).sendError(403); // forbidden\r
+                               }\r
+                       } catch(ClassCastException e) {\r
+                               throw new ServletException("JASPIServlet only supports HTTPServletRequest/HttpServletResponse");\r
+                       }\r
+               }\r
+       }\r
+\r
+       public void destroy() {\r
+               delegate.destroy();\r
+       }\r
+\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/AccessGetter.java b/core/src/main/java/com/att/cadi/filter/AccessGetter.java
new file mode 100644 (file)
index 0000000..a36b7c7
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.config.Get;\r
+\r
+public class AccessGetter implements Get {\r
+       private final Access access;\r
+       public AccessGetter(Access access) {\r
+               this.access = access;\r
+       }\r
+       public String get(String name, String def, boolean print) {\r
+               return access.getProperty(name, def);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/CadiAccess.java b/core/src/main/java/com/att/cadi/filter/CadiAccess.java
new file mode 100644 (file)
index 0000000..c7a9250
--- /dev/null
@@ -0,0 +1,244 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Properties;\r
+\r
+import javax.servlet.ServletContext;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.Get;\r
+\r
+public class CadiAccess implements Access {\r
+       // constants for a couple of very commonly used strings.\r
+       protected static final String FROM = "from";\r
+       protected static final String FOR = "for";\r
+\r
+       // Properties derived from <pass> sources (could be property files, Valve Configurations, Filter\r
+       // configs, etc. \r
+       protected Properties props;\r
+\r
+       // Will we write Logs?\r
+       protected Level willWrite = Level.INFO;\r
+       \r
+       protected ServletContext context;\r
+       protected Get getter = Get.NULL; // replace with Derived Class getter\r
+       private Symm symm;\r
+\r
+       public CadiAccess(Map<String, Object> map) {\r
+               if(map!=null && !map.isEmpty()) {\r
+                       props = new Properties();\r
+                       for(Entry<String, Object> es : map.entrySet()) {\r
+                               Object v = es.getValue();\r
+                               if(v!=null) {\r
+                                       props.put(es.getKey(), v.toString());\r
+                               }\r
+                       }\r
+                       Object keyfile = props.get(Config.CADI_KEYFILE);\r
+                       if(keyfile!=null) {\r
+                               try {\r
+                                       FileInputStream fis = new FileInputStream(keyfile.toString());\r
+                                       symm = Symm.obtain(fis);\r
+                               } catch (Exception e) {\r
+                               }\r
+                       }\r
+\r
+               }\r
+       }\r
+       \r
+       public Level willWrite() {\r
+               return willWrite;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)\r
+        */\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return willWrite.compareTo(level)<=0;\r
+       }\r
+\r
+       /**\r
+        * Add the "Level" to the Buildline for Logging types that don't specify, or straight Streams, etc.  Then buildline\r
+        * \r
+        * Build a line of code onto a StringBuilder based on Objects.  Analyze whether \r
+        * spaces need including.\r
+        *\r
+        * @param level\r
+        * @param sb\r
+        * @param elements\r
+        * @return\r
+        */\r
+       public final static StringBuilder buildLine(Level level, StringBuilder sb, Object[] elements) {\r
+               sb.append(level.name());\r
+               return buildLine(sb,elements);\r
+       }\r
+       \r
+       /*\r
+        * Build a line of code onto a StringBuilder based on Objects.  Analyze whether \r
+        * spaces need including.\r
+        * \r
+        * @param sb\r
+        * @param elements\r
+        * @return\r
+        */\r
+       public final static StringBuilder buildLine(StringBuilder sb, Object[] elements) {\r
+               sb.append(' ');\r
+               String str;\r
+               boolean notFirst = false;\r
+               for(Object o : elements) {\r
+                       if(o!=null) {\r
+                               str = o.toString();\r
+                               \r
+                               if(str.length()>0) {\r
+                                       if(notFirst && shouldAddSpace(str,true) && shouldAddSpace(sb,false)) {\r
+                                               sb.append(' ');\r
+                                       } else {\r
+                                               notFirst=true;\r
+                                       }\r
+                                       sb.append(str);\r
+                               }\r
+                       }\r
+               }\r
+               return sb;\r
+       }\r
+       \r
+       private static boolean shouldAddSpace(CharSequence c,boolean start) {\r
+               if(c.length()>0)\r
+                       switch(c.charAt(start?0:c.length()-1)) {\r
+                               case ' ':\r
+                               case '\t':\r
+                               case '\n':\r
+                               case '\'':\r
+                               case '"':\r
+                               case '|':\r
+                                       return false;\r
+                       }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Standard mechanism for logging, given being within a Servlet Context\r
+        * \r
+        * Here, we treat\r
+        * \r
+        * if context exists, log to it, otherwise log to Std Out (The latter is usually for startup \r
+        * scenarios)\r
+        *\r
+        */\r
+       public void log(Level level, Object... elements) {\r
+               if(willWrite.compareTo(level)<=0) {\r
+                       StringBuilder sb = buildLine(level, new StringBuilder(),elements);\r
+                       if(context==null) {\r
+                               System.out.println(sb.toString());\r
+                       } else {\r
+                               context.log(sb.toString());\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Standard mechanism for logging an Exception, given being within a Servlet Context, etc\r
+        * \r
+        * if context exists, log to it, otherwise log to Std Out (The latter is usually for startup \r
+        * scenarios)\r
+        *\r
+        */\r
+       public void log(Exception e, Object... elements) {\r
+               if(willWrite.compareTo(Level.ERROR)<=0) {\r
+                       StringBuilder sb = buildLine(Level.ERROR, new StringBuilder(),elements);\r
+               \r
+                       if(context==null) {\r
+                               sb.append(e.toString());\r
+                               System.out.println(sb.toString());\r
+                       } else {\r
+                               context.log(sb.toString(),e);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public void setLogLevel(Level level) {\r
+               willWrite = level;\r
+       }\r
+       \r
+       /**\r
+        * Pass back the classloader of the Servlet Context, if it exists. Otherwise, get the classloader\r
+        * of this object.\r
+        */\r
+       public ClassLoader classLoader() { // Use the Classloader that Context was created with\r
+               return (context==null?this:context).getClass().getClassLoader();\r
+       }\r
+\r
+       /**\r
+        * Get the Property from Context\r
+        */\r
+       public String getProperty(String string, String def) {\r
+               String rv = null;\r
+\r
+        if ( props != null )\r
+            rv = props.getProperty( string, def );\r
+        \r
+               if(rv==null) {\r
+            rv = context.getInitParameter(string);\r
+               }\r
+               return rv==null?def:rv;\r
+\r
+       }\r
+\r
+       public void load(InputStream is) throws IOException {\r
+               if(this.props==null) {\r
+                       this.props = new Properties();\r
+               }\r
+               this.props.load(is);\r
+               symm = Symm.obtain(this);\r
+       }\r
+\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               if(symm==null) {\r
+                       String keyfile = getter.get(Config.CADI_KEYFILE, null, true);\r
+                       if(keyfile!=null) {\r
+                               FileInputStream fis = new FileInputStream(keyfile);\r
+                               symm=Symm.obtain(fis);\r
+                               fis.close();\r
+                       }\r
+               }\r
+               return (symm!=null && encrypted!=null && (anytext || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object[] elements) {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/CadiFilter.java b/core/src/main/java/com/att/cadi/filter/CadiFilter.java
new file mode 100644 (file)
index 0000000..578cbba
--- /dev/null
@@ -0,0 +1,306 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.Constructor;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.servlet.Filter;\r
+import javax.servlet.FilterChain;\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CadiWrap;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.ServletContextAccess;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.Get;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+\r
+/**\r
+ * CadiFilter\r
+ * \r
+ * This class implements Servlet Filter, and ties together CADI implementations\r
+ * \r
+ * This class can be used in a standard J2EE Servlet manner.  Optimal usage is for POJO operations, where\r
+ * one can enforce this Filter being first and primary.  Depending on the Container, it \r
+ * may be more effective, in some cases, to utilize features that allow earlier determination of \r
+ * AUTHN (Authorization).  An example would be "Tomcat Valve".  These implementations, however, should\r
+ * be modeled after the "init" and "doFilter" functions, and be kept up to date as this class changes.\r
+ * \r
+ * \r
+ *\r
+ */\r
+public class CadiFilter implements Filter {\r
+       private static CadiHTTPManip httpChecker;\r
+       private static String[] pathExceptions;\r
+       private static List<Pair> mapPairs;\r
+       private Access access;\r
+       private Object[] additionalTafLurs;\r
+       private static int count=0;\r
+       \r
+       public Lur getLur() {\r
+               return httpChecker.getLur();\r
+       }\r
+       \r
+       /**\r
+        * Construct a viable Filter\r
+        * \r
+        * Due to the vagaries of many containers, there is a tendency to create Objects and call "Init" on \r
+        * them at a later time.  Therefore, this object creates with an object that denies all access\r
+        * until appropriate Init happens, just in case the container lets something slip by in the meantime.\r
+        * \r
+        */\r
+       public CadiFilter() {\r
+               additionalTafLurs = CadiHTTPManip.noAdditional;\r
+       }\r
+\r
+       /**\r
+        * This constructor to be used when directly constructing and placing in HTTP Engine\r
+        * \r
+        * @param access\r
+        * @param moreTafLurs\r
+        * @throws ServletException \r
+        */\r
+       public CadiFilter(Access access, Object ... moreTafLurs) throws ServletException {\r
+               additionalTafLurs = moreTafLurs;\r
+               init(new AccessGetter(this.access = access));\r
+       }\r
+\r
+\r
+       /**\r
+        * Use this to pass in a PreContructed CADI Filter, but with initializing... let Servlet do it\r
+        * @param init\r
+        * @param access\r
+        * @param moreTafLurs\r
+        * @throws ServletException\r
+        */\r
+       public CadiFilter(boolean init, PropAccess access, Object ... moreTafLurs) throws ServletException {\r
+               this.access = access;\r
+               if(init) {\r
+                       init(new AccessGetter(access));\r
+               }\r
+               additionalTafLurs = moreTafLurs;\r
+       }\r
+\r
+       /**\r
+        * Init\r
+        * \r
+        * Standard Filter "init" call with FilterConfig to obtain properties.  POJOs can construct a\r
+        * FilterConfig with the mechanism of their choice, and standard J2EE Servlet engines utilize this\r
+        * mechanism already.\r
+        */\r
+       //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM Init functions\r
+       public void init(FilterConfig filterConfig) throws ServletException {\r
+               // need the Context for Logging, instantiating ClassLoader, etc\r
+               ServletContextAccess sca=new ServletContextAccess(filterConfig); \r
+               if(access==null) {\r
+                       access = sca;\r
+               }\r
+               \r
+               // Set Protected getter with base Access, for internal class instantiations\r
+               init(new FCGet(access, sca.context(), filterConfig));\r
+       }\r
+       \r
+\r
+   private void init(Get getter) throws ServletException {\r
+        // Start with the assumption of "Don't trust anyone".\r
+          TrustChecker tc = TrustChecker.NOTRUST; // default position\r
+          try {\r
+                  @SuppressWarnings("unchecked")\r
+                  Class<TrustChecker> ctc = (Class<TrustChecker>) Class.forName("com.att.cadi.aaf.v2_0.AAFTrustChecker");\r
+                  if(ctc!=null) {\r
+                          Constructor<TrustChecker> contc = ctc.getConstructor(Access.class);\r
+                          if(contc!=null) {\r
+                                  tc = contc.newInstance(access);\r
+                          }\r
+                  }\r
+          } catch (Exception e) {\r
+                  access.log(Level.INIT, "AAFTrustChecker cannot be loaded",e.getMessage());\r
+          }\r
+       \r
+        \r
+        // Synchronize, because some instantiations call init several times on the same object\r
+        // In this case, the epiTaf will be changed to a non-NullTaf, and thus not instantiate twice.\r
+               synchronized(CadiHTTPManip.noAdditional /*will always remain same Object*/) {\r
+                       ++count;\r
+                       if(httpChecker == null) {\r
+                               if(access==null) {\r
+                                       access = new PropAccess();\r
+                               }\r
+                               try {\r
+                                       httpChecker = new CadiHTTPManip(access,null /*reuseable Con*/,tc, additionalTafLurs);\r
+                               } catch (CadiException e1) {\r
+                                       throw new ServletException(e1);\r
+                               }\r
+                       } else if(access==null) {\r
+                               access= httpChecker.getAccess();\r
+                       }\r
+\r
+                       /*\r
+                        * Setup Authn Path Exceptions\r
+                        */\r
+                       if(pathExceptions==null) {\r
+                               String str = getter.get(Config.CADI_NOAUTHN, null, true);\r
+                               if(str!=null) {\r
+                                       pathExceptions = str.split("\\s*:\\s*");\r
+                               }\r
+                       }\r
+       \r
+                       /* \r
+                        * SETUP Permission Converters... those that can take Strings from a Vendor Product, and convert to appropriate AAF Permissions\r
+                        */\r
+                       if(mapPairs==null) {\r
+                               String str = getter.get(Config.AAF_PERM_MAP, null, true);\r
+                               if(str!=null) {\r
+                                       String mstr = getter.get(Config.AAF_PERM_MAP, null, true);\r
+                                       if(mstr!=null) {\r
+                                               String map[] = mstr.split("\\s*:\\s*");\r
+                                               if(map.length>0) {\r
+                                                       MapPermConverter mpc=null;\r
+                                                       int idx;\r
+                                                       mapPairs = new ArrayList<Pair>();\r
+                                                       for(String entry : map) {\r
+                                                               if((idx=entry.indexOf('='))<0) { // it's a Path, so create a new converter\r
+                                                                       access.log(Level.INIT,"Loading Perm Conversions for:",entry);\r
+                                                                       mapPairs.add(new Pair(entry,mpc=new MapPermConverter()));\r
+                                                               } else {\r
+                                                                       if(mpc!=null) {\r
+                                                                               mpc.map().put(entry.substring(0,idx),entry.substring(idx+1));\r
+                                                                       } else {\r
+                                                                               access.log(Level.ERROR,"cadi_perm_map is malformed; ",entry, "is skipped");\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // Remove Getter\r
+        getter = Get.NULL;\r
+       }\r
+\r
+       /**\r
+        * Containers call "destroy" when time to cleanup \r
+        */\r
+       public void destroy() {\r
+               // Synchronize, in case multiCadiFilters are used.\r
+               synchronized(CadiHTTPManip.noAdditional) {\r
+                       if(--count<=0 && httpChecker!=null) {\r
+                               httpChecker.destroy();\r
+                               httpChecker=null;\r
+                               access=null;\r
+                               pathExceptions=null;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * doFilter\r
+        * \r
+        * This is the standard J2EE invocation.  Analyze the request, modify response as necessary, and\r
+        * only call the next item in the filterChain if request is suitably Authenticated.\r
+        */\r
+       //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM functions\r
+       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\r
+               try {\r
+                       HttpServletRequest hreq = (HttpServletRequest)request;\r
+                       if(noAuthn(hreq)) {\r
+                               chain.doFilter(request, response);\r
+                       } else {\r
+                               HttpServletResponse hresp = (HttpServletResponse)response;\r
+                               TafResp tresp = httpChecker.validate(hreq, hresp);\r
+                               if(tresp.isAuthenticated()==RESP.IS_AUTHENTICATED) {\r
+                                               CadiWrap cw = new CadiWrap(hreq, tresp, httpChecker.getLur(),getConverter(hreq));\r
+                                               if(httpChecker.notCadi(cw, hresp)) {\r
+                                                       chain.doFilter(cw,response);\r
+                                               }\r
+                               }                                               \r
+                       }\r
+               } catch (ClassCastException e) {\r
+                       throw new ServletException("CadiFilter expects Servlet to be an HTTP Servlet",e);\r
+               }\r
+       }\r
+\r
+\r
+       /** \r
+        * If PathExceptions exist, report if these should not have Authn applied.\r
+        * @param hreq\r
+        * @return\r
+        */\r
+       private boolean noAuthn(HttpServletRequest hreq) {\r
+               if(pathExceptions!=null) {\r
+                       String pi = hreq.getPathInfo();\r
+                       if(pi==null) return false; // JBoss sometimes leaves null\r
+                       for(String pe : pathExceptions) {\r
+                               if(pi.startsWith(pe))return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Get Converter by Path\r
+        */\r
+       private PermConverter getConverter(HttpServletRequest hreq) {\r
+               if(mapPairs!=null) {\r
+                       String pi = hreq.getPathInfo();\r
+                       if(pi!=null) {\r
+                       for(Pair p: mapPairs) {\r
+                               if(pi.startsWith(p.name))return p.pc;\r
+                       }\r
+                       }\r
+               }\r
+               return NullPermConverter.singleton();\r
+       }\r
+       \r
+       /**\r
+        * store PermConverters by Path prefix\r
+        *\r
+        */\r
+       private class Pair {\r
+               public Pair(String key, PermConverter pc) {\r
+                       name = key;\r
+                       this.pc = pc;\r
+               }\r
+               public String name;\r
+               public PermConverter pc;\r
+       }\r
+\r
+}\r
+\r
diff --git a/core/src/main/java/com/att/cadi/filter/CadiHTTPManip.java b/core/src/main/java/com/att/cadi/filter/CadiHTTPManip.java
new file mode 100644 (file)
index 0000000..821dae9
--- /dev/null
@@ -0,0 +1,228 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CadiWrap;\r
+import com.att.cadi.Connector;\r
+import com.att.cadi.CredVal;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Taf;\r
+import com.att.cadi.TrustChecker;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.lur.EpiLur;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.util.UserChainManip;\r
+\r
+/**\r
+ * Encapsulate common HTTP Manipulation Behavior.  It will appropriately set\r
+ * HTTPServletResponse for Redirect or Forbidden, as needed.\r
+ * \r
+ * Further, this is useful, because it avoids multiple creates of Connections, where some Filters\r
+ * are created and destroyed regularly.\r
+ * \r
+ *\r
+ *\r
+ */\r
+public class CadiHTTPManip {\r
+       private static final String ACCESS_CADI_CONTROL = ".access|cadi|control";\r
+       private static final String METH = "OPTIONS";\r
+       private static final String CADI = "/cadi/";\r
+       private static final String CADI_CACHE_PRINT = "/cadi/cache/print";\r
+       private static final String CADI_CACHE_CLEAR = "/cadi/cache/clear";\r
+       private static final String CADI_LOG_SET = "/cadi/log/set/";\r
+       private Access access;\r
+       private HttpTaf taf;\r
+       private CredVal up;\r
+       private Lur lur;\r
+       private String thisPerm,companyPerm,aaf_id;\r
+       \r
+       public static final Object[] noAdditional = new Object[0]; // CadiFilter can be created each call in some systems\r
+\r
+\r
+       public CadiHTTPManip(Access access, Connector con, TrustChecker tc, Object ... additionalTafLurs) throws CadiException {\r
+               synchronized(CADI) {\r
+                       this.access = access;\r
+//                     Get getter = new AccessGetter(access);\r
+                       Config.setDefaultRealm(access);\r
+       \r
+                       aaf_id = access.getProperty(Config.CADI_ALIAS,access.getProperty(Config.AAF_MECHID, null));\r
+                       if(aaf_id==null) {\r
+                               access.printf(Level.INIT, "%s is not set. %s can be used instead",Config.AAF_MECHID,Config.CADI_ALIAS);\r
+                       } else {\r
+                               access.printf(Level.INIT, "%s is set to %s",Config.AAF_MECHID,aaf_id);\r
+                       }\r
+                       String ns = aaf_id==null?null:UserChainManip.idToNS(aaf_id);\r
+                       if(ns!=null) {\r
+                               thisPerm = ns+ACCESS_CADI_CONTROL;\r
+                               int dot = ns.indexOf('.');\r
+                               if(dot>=0) {\r
+                                       int dot2=ns.indexOf('.',dot+1);\r
+                                       if(dot2<0) {\r
+                                               dot2=dot;\r
+                                       }\r
+                                       companyPerm = ns.substring(0, dot2)+ACCESS_CADI_CONTROL;\r
+                               } else {\r
+                                       companyPerm = "com"+ACCESS_CADI_CONTROL;\r
+                               }\r
+                       } else {\r
+                               thisPerm = companyPerm = "com"+ACCESS_CADI_CONTROL;\r
+                       }\r
+                       \r
+                       if(con!=null) { // try to reutilize connector\r
+                               List<Lur> ll = null;\r
+                               for(Object tl : additionalTafLurs) {\r
+                                       if(tl instanceof Lur) {\r
+                                               if(ll==null) {\r
+                                                       ll = new ArrayList<Lur>();\r
+                                                       ll.add(con.newLur());\r
+                                               }\r
+                                               ll.add((Lur)tl);\r
+                                       }\r
+                               }\r
+                               if(ll==null) {\r
+                                       lur = con.newLur();\r
+                               } else {\r
+                                       lur = new EpiLur((Lur[])ll.toArray());\r
+                               }\r
+                       } else {\r
+                               lur = Config.configLur(access, additionalTafLurs);\r
+                       }\r
+                       tc.setLur(lur);\r
+                       if(lur instanceof EpiLur) {\r
+                               up = ((EpiLur)lur).getUserPassImpl();\r
+                       } else if(lur instanceof CredVal) {\r
+                               up = (CredVal)lur;\r
+                       } else {\r
+                               up = null;\r
+                       }\r
+                       taf = Config.configHttpTaf(access, tc, up, lur, additionalTafLurs);\r
+               }\r
+       }\r
+\r
+       public TafResp validate(HttpServletRequest hreq, HttpServletResponse hresp) throws IOException {\r
+               TafResp tresp = taf.validate(Taf.LifeForm.LFN, hreq, hresp);\r
+               switch(tresp.isAuthenticated()) {\r
+                       case IS_AUTHENTICATED:\r
+                               access.printf(Level.INFO,"Authenticated: %s from %s:%d"\r
+                                               , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                               break;\r
+                       case TRY_AUTHENTICATING:\r
+                               switch (tresp.authenticate()) {\r
+                                       case IS_AUTHENTICATED:\r
+                                               access.printf(Level.INFO,"Authenticated: %s from %s:%d"\r
+                                                               , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                                               break;\r
+                                       case HTTP_REDIRECT_INVOKED:\r
+                                               access.log(Level.INFO,"Authenticating via redirection: ", tresp.desc());\r
+                                               break;\r
+                                       case NO_FURTHER_PROCESSING:\r
+                                               access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d"\r
+                                                               , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                                               hresp.sendError(403, tresp.desc()); // Forbidden\r
+                                               break;\r
+\r
+                                       default:\r
+                                               access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"\r
+                                                               , hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                                               hresp.sendError(403, tresp.desc()); // Forbidden\r
+                               }\r
+                               break;\r
+                       case NO_FURTHER_PROCESSING:\r
+                               access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d", \r
+                                               tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                               hresp.sendError(403, "Access Denied"); // FORBIDDEN\r
+                               break;\r
+                       default:\r
+                               access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"\r
+                                               , hreq.getRemoteAddr(), hreq.getRemotePort());\r
+                               hresp.sendError(403, "Access Denied"); // FORBIDDEN\r
+               }\r
+               return tresp;\r
+       }\r
+       \r
+       public boolean notCadi(CadiWrap req, HttpServletResponse resp) {\r
+               \r
+               String pathInfo = req.getPathInfo();\r
+               if(METH.equalsIgnoreCase(req.getMethod()) && pathInfo!=null && pathInfo.contains(CADI)) {\r
+                       if(req.getUser().equals(aaf_id) || req.isUserInRole(thisPerm) || req.isUserInRole(companyPerm)) {\r
+                               try {\r
+                                       if(pathInfo.contains(CADI_CACHE_PRINT)) {\r
+                                               resp.getOutputStream().println(lur.toString());\r
+                                               resp.setStatus(200);\r
+                                               return false;\r
+                                       } else if(pathInfo.contains(CADI_CACHE_CLEAR)) {\r
+                                               StringBuilder report = new StringBuilder();\r
+                                               lur.clear(req.getUserPrincipal(), report);\r
+                                               resp.getOutputStream().println(report.toString());\r
+                                               resp.setStatus(200);\r
+                                               return false;\r
+                                       } else if(pathInfo.contains(CADI_LOG_SET))  {\r
+                                               Level l;\r
+                                               int slash = pathInfo.lastIndexOf('/');\r
+                                               String level = pathInfo.substring(slash+1);\r
+                                               try {\r
+                                                       l = Level.valueOf(level);\r
+                                                       access.printf(Level.AUDIT, "%s has set CADI Log Level to '%s'",req.getUser(),l.name());\r
+                                                       access.setLogLevel(l);\r
+                                               } catch (IllegalArgumentException e) {\r
+                                                       access.printf(Level.AUDIT, "'%s' is not a valid CADI Log Level",level);\r
+                                               }\r
+                                               return false;\r
+                                       }\r
+                               } catch (IOException e) {\r
+                                       access.log(e);\r
+                               }\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+\r
+       public Lur getLur() {\r
+               return lur;\r
+       }\r
+       \r
+       public void destroy() {\r
+               access.log(Level.INFO,"CadiHttpChecker destroyed.");\r
+               if(lur!=null) {\r
+                       lur.destroy();\r
+                       lur=null;\r
+               }\r
+       }\r
+\r
+       public Access getAccess() {\r
+               return access;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/FCGet.java b/core/src/main/java/com/att/cadi/filter/FCGet.java
new file mode 100644 (file)
index 0000000..97840d4
--- /dev/null
@@ -0,0 +1,78 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletContext;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.config.Get;\r
+\r
+/*\r
+ * A private method to query the Filter config and if not exists, return the default.  This\r
+ * cleans up the initialization code.\r
+ */\r
+class FCGet implements Get {\r
+       /**\r
+        * \r
+        */\r
+       private final Access access;\r
+       private FilterConfig filterConfig;\r
+       private ServletContext context;\r
+\r
+       public FCGet(Access access, ServletContext context, FilterConfig filterConfig) {\r
+               this.access = access;\r
+               this.context = context;\r
+               this.filterConfig = filterConfig;\r
+       }\r
+\r
+       public String get(String name, String def, boolean print) {\r
+               String str = null;\r
+               // Try Server Context First\r
+               if(context!=null) {\r
+                       str = context.getInitParameter(name);\r
+               }\r
+               \r
+               // Try Filter Context next\r
+               if(str==null && filterConfig != null) {\r
+                       str = filterConfig.getInitParameter(name);\r
+               }\r
+               \r
+               if(str==null) {\r
+                       str = access.getProperty(name, def);\r
+               }\r
+               // Take def if nothing else\r
+               if(str==null) {\r
+                       str = def;\r
+                       // don't log defaults\r
+               } else {\r
+                       str = str.trim(); // this is vital in Property File based values, as spaces can hide easily\r
+                       if(print) {\r
+                               access.log(Level.INFO,"Setting", name, "to", str);\r
+                       }\r
+               }\r
+               return str;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/MapPermConverter.java b/core/src/main/java/com/att/cadi/filter/MapPermConverter.java
new file mode 100644 (file)
index 0000000..19aeb18
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+public class MapPermConverter implements PermConverter {\r
+       private HashMap<String,String> map;\r
+\r
+       /**\r
+        * Create with colon separated name value pairs\r
+        *  i.e. teAdmin=com.att.myNS.myPerm|*|*:teUser=...\r
+        *  \r
+        * @param value\r
+        */\r
+       public MapPermConverter() {\r
+               map = new HashMap<String,String>();\r
+       }\r
+\r
+       /**\r
+        * use to instantiate entries \r
+        * \r
+        * @return\r
+        */\r
+       public Map<String,String> map() {\r
+               return map;\r
+       }\r
+\r
+       public String convert(String minimal) {\r
+               String rv = map.get(minimal);\r
+               return rv==null?minimal:rv;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/NullPermConverter.java b/core/src/main/java/com/att/cadi/filter/NullPermConverter.java
new file mode 100644 (file)
index 0000000..07c565d
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+\r
+/**\r
+ * A NullPermConverter \r
+ * \r
+ * Obey the PermConverter Interface, but passed in "minimal" String is not converted.\r
+ * \r
+ *\r
+ */\r
+public class NullPermConverter implements PermConverter {\r
+\r
+       private NullPermConverter() {}\r
+       private static final NullPermConverter singleton = new NullPermConverter();\r
+       public static NullPermConverter singleton() {return singleton;}\r
+\r
+       public String convert(String minimal) {\r
+               return minimal;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/PathFilter.java b/core/src/main/java/com/att/cadi/filter/PathFilter.java
new file mode 100644 (file)
index 0000000..3ea6536
--- /dev/null
@@ -0,0 +1,184 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+import java.io.IOException;\r
+\r
+import javax.servlet.Filter;\r
+import javax.servlet.FilterChain;\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletContext;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.config.Config;\r
+\r
+/**\r
+ * PathFilter\r
+ * \r
+ * This class implements Servlet Filter, and uses AAF to validate access to a Path.\r
+ * \r
+ * This class can be used in a standard J2EE Servlet manner.\r
+ *  \r
+ *\r
+ */\r
+public class PathFilter implements Filter {\r
+       private ServletContext context;\r
+       private String aaf_type;\r
+       private String not_authorized_msg;\r
+       private final Log log;\r
+\r
+       /**\r
+        * Construct a viable Filter for installing in Container WEB.XML, etc.\r
+        * \r
+        */\r
+       public PathFilter() {\r
+               log = new Log() {\r
+                       public void info(String ... msg) {\r
+                               context.log(build("INFO:",msg));\r
+                       }\r
+                       public void audit(String ... msg) {\r
+                               context.log(build("AUDIT:",msg));\r
+                       }\r
+                       private String build(String type, String []msg) {\r
+                               StringBuilder sb = new StringBuilder(type);\r
+                               for(String s : msg) {\r
+                                       sb.append(' ');\r
+                                       sb.append(s);\r
+                               }\r
+                               return sb.toString();\r
+                       }\r
+               \r
+               };\r
+       }\r
+       \r
+       /**\r
+        * Filter that can be constructed within Java\r
+        * @param access\r
+        */\r
+       public PathFilter(final Access access) {\r
+               log = new Log() {\r
+                       public void info(String ... msg) {\r
+                               access.log(Level.INFO, (Object[])msg);\r
+                       }\r
+                       public void audit(String ... msg) {\r
+                               access.log(Level.AUDIT, (Object[])msg);\r
+                       }\r
+               };\r
+       }\r
+       \r
+       /**\r
+        * Init\r
+        * \r
+        * Standard Filter "init" call with FilterConfig to obtain properties.  POJOs can construct a\r
+        * FilterConfig with the mechanism of their choice, and standard J2EE Servlet engines utilize this\r
+        * mechanism already.\r
+        */\r
+       public void init(FilterConfig filterConfig) throws ServletException {\r
+               // need the Context for Logging, instantiating ClassLoader, etc\r
+               context = filterConfig.getServletContext();\r
+               StringBuilder sb = new StringBuilder();\r
+               StringBuilder err = new StringBuilder(); \r
+               Object attr = context.getAttribute(Config.PATHFILTER_NS);\r
+               if(attr==null) {\r
+                       err.append("PathFilter - pathfilter_ns is not set");\r
+               } else {\r
+                       sb.append(attr.toString()); \r
+               }\r
+\r
+               attr = context.getAttribute(Config.PATHFILTER_STACK);\r
+               if(attr==null) {\r
+                       log.info("PathFilter - No pathfilter_stack set, ignoring");\r
+               } else {\r
+                       sb.append('.');\r
+                       sb.append(attr.toString());\r
+               }\r
+\r
+               attr = context.getAttribute(Config.PATHFILTER_URLPATTERN);\r
+               if(attr==null) {\r
+                       log.info("PathFilter - No pathfilter_urlpattern set, defaulting to 'urlpattern'");\r
+                       sb.append(".urlpattern");\r
+               } else {\r
+                       sb.append('.');\r
+                       sb.append(attr.toString());\r
+               }\r
+\r
+               log.info("PathFilter - AAF Permission Type is",sb.toString());\r
+               \r
+               sb.append('|');\r
+               \r
+               aaf_type = sb.toString();\r
+\r
+               attr = context.getAttribute(Config.PATHFILTER_NOT_AUTHORIZED_MSG);\r
+               if(attr==null) {\r
+                       not_authorized_msg = "Forbidden - Not Authorized to access this Path";\r
+               } else {\r
+                       not_authorized_msg = attr.toString();\r
+               }\r
+\r
+               if(err.length()>0) {\r
+                       throw new ServletException(err.toString());\r
+               }\r
+       }\r
+\r
+       private interface Log {\r
+               public void info(String ... msg);\r
+               public void audit(String ... msg);\r
+       }\r
+\r
+       /**\r
+        * doFilter\r
+        * \r
+        * This is the standard J2EE invocation.  Analyze the request, modify response as necessary, and\r
+        * only call the next item in the filterChain if request is suitably Authenticated.\r
+        */\r
+       //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM functions\r
+       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\r
+               HttpServletRequest hreq = (HttpServletRequest)request;\r
+               HttpServletResponse hresp = (HttpServletResponse)response;\r
+               String perm = aaf_type+hreq.getPathInfo()+'|'+hreq.getMethod();\r
+               if(hreq.isUserInRole(perm)) {\r
+                       chain.doFilter(request, response);\r
+               } else {\r
+                       log.audit("PathFilter has denied",hreq.getUserPrincipal().getName(),"access to",perm);\r
+                       hresp.sendError(403,not_authorized_msg);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Containers call "destroy" when time to cleanup \r
+        */\r
+       public void destroy() {\r
+               log.info("PathFilter destroyed.");\r
+       }\r
+\r
+\r
+\r
+}\r
+\r
diff --git a/core/src/main/java/com/att/cadi/filter/PermConverter.java b/core/src/main/java/com/att/cadi/filter/PermConverter.java
new file mode 100644 (file)
index 0000000..e5bfcb7
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.filter;\r
+\r
+/**\r
+ * Convert a simplistic, single string Permission into an Enterprise Scoped Perm\r
+ * \r
+ *\r
+ */\r
+public interface PermConverter {\r
+       public String convert(String minimal);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/RolesAllowed.java b/core/src/main/java/com/att/cadi/filter/RolesAllowed.java
new file mode 100644 (file)
index 0000000..ec350fd
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+/**\r
+ * RolesAllowed \r
+ * \r
+ * \r
+ * Similar to Java EE's Spec from Annotations 1.1, 2.8\r
+ * \r
+ * That Spec, however, was geared towards being able to route calls to Methods on Objects, and thus needed a more refined\r
+ * sense of permissions hierarchy.  The same mechanism, however, can easily be achieved on single Servlet/Handlers in\r
+ * POJOs like Jetty by simply adding the Roles Allowed in a similar Annotation\r
+ * \r
+ */\r
+package com.att.cadi.filter;\r
+import static java.lang.annotation.ElementType.TYPE;\r
+import static java.lang.annotation.RetentionPolicy.RUNTIME;\r
+\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.Target;\r
+\r
+/**\r
+ * JASPI Style Annotation of RolesAllowed when the coding style is desired but actually including all \r
+ * JEE jars is not. If using actual JASPI, use official @interface classes, not this one...\r
+ * \r
+ */\r
+@Target({TYPE})\r
+@Retention(RUNTIME)\r
+public @interface RolesAllowed {\r
+       /**\r
+        * Security role of the implementation, which doesn't have to be an EJB or CORBA like object.  Can be just a\r
+        * Handler\r
+        * @return\r
+        */\r
+       String[] value();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/filter/ServletImpl.java b/core/src/main/java/com/att/cadi/filter/ServletImpl.java
new file mode 100644 (file)
index 0000000..3db6d4e
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+/**\r
+ * RolesAllowed \r
+ * \r
+ * \r
+ * Similar to Java EE's Spec from Annotations 1.1, 2.8\r
+ * \r
+ * That Spec, however, was geared towards being able to route calls to Methods on Objects, and thus needed a more refined\r
+ * sense of permissions hierarchy.  The same mechanism, however, can easily be achieved on single Servlet/Handlers in\r
+ * POJOs like Jetty by simply adding the Roles Allowed in a similar Annotation\r
+ * \r
+ */\r
+package com.att.cadi.filter;\r
+import static java.lang.annotation.ElementType.TYPE;\r
+import static java.lang.annotation.RetentionPolicy.RUNTIME;\r
+\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.Target;\r
+\r
+import javax.servlet.Servlet;\r
+\r
+/**\r
+ * \r
+ */\r
+@Target({TYPE})\r
+@Retention(RUNTIME)\r
+public @interface ServletImpl {\r
+       /**\r
+        * Security role of the implementation, which doesn't have to be an EJB or CORBA like object.  Can be just a\r
+        * Handler\r
+        * @return\r
+        */\r
+       Class<? extends Servlet> value();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/lur/ConfigPrincipal.java b/core/src/main/java/com/att/cadi/lur/ConfigPrincipal.java
new file mode 100644 (file)
index 0000000..03a7961
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Symm;\r
+\r
+public class ConfigPrincipal implements Principal, GetCred {\r
+       private String name;\r
+       private byte[] cred;\r
+       private String content;\r
+\r
+       public ConfigPrincipal(String name, String passwd) {\r
+               this.name = name;\r
+               this.cred = passwd.getBytes();\r
+               content = null;\r
+       }\r
+\r
+       public ConfigPrincipal(String name, byte[] cred) {\r
+               this.name = name;\r
+               this.cred = cred;\r
+               content = null;\r
+       }\r
+\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       public byte[] getCred() {\r
+               return cred;\r
+       }\r
+\r
+       public String toString() {\r
+               return name;\r
+       }\r
+       \r
+       public String getAsBasicAuthHeader() throws IOException {\r
+               if(content ==null) {\r
+                       String s = name + ':' + new String(cred);\r
+                       content = "Basic " + Symm.base64.encode(s);  \r
+               } else if(!content.startsWith("Basic ")) { // content is the saved password from construction\r
+                       String s = name + ':' + content;\r
+                       content = "Basic " + Symm.base64.encode(s);  \r
+               }\r
+               return content;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/lur/EpiLur.java b/core/src/main/java/com/att/cadi/lur/EpiLur.java
new file mode 100644 (file)
index 0000000..de6c057
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur;\r
+\r
+import java.security.Principal;\r
+import java.util.List;\r
+\r
+import com.att.cadi.CachingLur;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.CredVal;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Permission;\r
+\r
+/**\r
+ * EpiLUR\r
+ * \r
+ * Short for "Epic LUR". Be able to run through a series of LURs to obtain the validation needed.\r
+ * \r
+ * The pun is better for the other pattern... "TAF" (aka EpiTaf), but it's still the larger picture of \r
+ * LURs that will be accomplished.\r
+ * \r
+ * FYI, the reason we separate LURs, rather than combine, is that Various User Repository Resources have\r
+ * different Caching requirements.  For instance, the Local User Repo (with stand alone names), never expire, but might be\r
+ * refreshed with a change in Configuration File, while the Remote Service based LURs will need to expire at prescribed intervals \r
+ * \r
+ *\r
+ */\r
+public final class EpiLur implements Lur {\r
+       private final Lur[] lurs;\r
+       \r
+       /**\r
+        * EpiLur constructor\r
+        * \r
+        * Construct the EpiLur from variable TAF parameters\r
+        * @param lurs\r
+        * @throws CadiException\r
+        */\r
+       public EpiLur(Lur ... lurs) throws CadiException{\r
+               this.lurs = lurs;\r
+               if(lurs.length==0) throw new CadiException("Need at least one Lur implementation in constructor");\r
+       }\r
+\r
+       public boolean fish(Principal bait, Permission pond) {\r
+               if(pond==null) {\r
+                       return false;\r
+               }\r
+               boolean rv = false;\r
+               Lur lur;\r
+               for(int i=0;!rv && i<lurs.length;++i) {\r
+                       rv = (lur = lurs[i]).fish(bait, pond);\r
+                       if(!rv && lur.handlesExclusively(pond)) break;\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       public void fishAll(Principal bait, List<Permission> permissions) {\r
+               for(Lur lur : lurs) {\r
+                       lur.fishAll(bait, permissions);\r
+               }\r
+       }\r
+\r
+       public void destroy() {\r
+               for(Lur lur : lurs) {\r
+                       lur.destroy();\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Return the first Lur (if any) which also implements UserPass \r
+        * @return\r
+        */\r
+       public CredVal getUserPassImpl() {\r
+               for(Lur lur : lurs) {\r
+                       if(lur instanceof CredVal) {\r
+                               return (CredVal)lur;\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       // Never needed... Only EpiLur uses...\r
+       public boolean handlesExclusively(Permission pond) {\r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Get Lur for index.  Returns null if out of range\r
+        * @param idx\r
+        * @return\r
+        */\r
+       public Lur get(int idx) {\r
+               if(idx>=0 && idx<lurs.length) {\r
+                       return lurs[idx];\r
+               }\r
+               return null;\r
+       }\r
+\r
+       public boolean supports(String userName) {\r
+               for(Lur l : lurs) {\r
+                       if(l.supports(userName))return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public void remove(String id) {\r
+               for(Lur l : lurs) {\r
+                       if(l instanceof CachingLur) {\r
+                               ((CachingLur<?>)l).remove(id);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public Lur subLur(Class<? extends Lur> cls ) {\r
+               for(Lur l : lurs) {\r
+                       if(l.getClass().isAssignableFrom(cls)) {\r
+                               return l;\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public Permission createPerm(String p) {\r
+               return new LocalPermission(p);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Lur#clear(java.security.Principal, java.lang.StringBuilder)\r
+        */\r
+       @Override\r
+       public void clear(Principal p, StringBuilder report) {\r
+               for(Lur lur : lurs) {\r
+                       lur.clear(p, report);\r
+               }\r
+       }\r
+       \r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder();\r
+               for(Lur lur : lurs) {\r
+                       sb.append(lur.getClass().getSimpleName());\r
+                       sb.append(": Report\n");\r
+                       sb.append(lur.toString());\r
+                       sb.append('\n');\r
+               }\r
+               return sb.toString();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/lur/LocalLur.java b/core/src/main/java/com/att/cadi/lur/LocalLur.java
new file mode 100644 (file)
index 0000000..80b302a
--- /dev/null
@@ -0,0 +1,202 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import com.att.cadi.AbsUserCache;\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CredVal;\r
+import com.att.cadi.Hash;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.StrLur;\r
+import com.att.cadi.User;\r
+import com.att.cadi.config.Config;\r
+\r
+\r
+/**\r
+ * An in-memory Lur that can be configured locally with User info via properties, similar to Tomcat-users.xml mechanisms.\r
+ * \r
+ *\r
+ */\r
+public final class LocalLur extends AbsUserCache<LocalPermission> implements StrLur, CredVal {\r
+       public static final String SEMI = "\\s*;\\s*";\r
+       public static final String COLON = "\\s*:\\s*";\r
+       public static final String COMMA = "\\s*,\\s*";\r
+       public static final String PERCENT = "\\s*%\\s*";\r
+       \r
+       // Use to quickly determine whether any given group is supported by this LUR\r
+       private final Set<String> supportingGroups;\r
+       private String supportedRealm; \r
+       \r
+       /**\r
+        * Construct by building structure, see "build"\r
+        * \r
+        * Reconstruct with "build"\r
+        * \r
+        * @param userProperty\r
+        * @param groupProperty\r
+        * @param decryptor\r
+        * @throws IOException\r
+        */\r
+       public LocalLur(Access access, String userProperty, String groupProperty) throws IOException {\r
+               super(access, 0, 0, Integer.MAX_VALUE);  // data doesn't expire\r
+               supportedRealm = access.getProperty(Config.BASIC_REALM, "localized");\r
+               supportingGroups = new TreeSet<String>();\r
+               \r
+               if(userProperty!=null) {\r
+                       // For each User name...\r
+                       for(String user : userProperty.trim().split(SEMI)) {\r
+                               String[] us = user.split(COLON,2);\r
+                               String[] userpass = us[0].split(PERCENT,2);\r
+                               String u;\r
+                               User<LocalPermission> usr;\r
+                               if(userpass.length>1) {\r
+                                       if(userpass.length>0 && userpass[0].indexOf('@')<0) {\r
+                                               userpass[0]=userpass[0] + '@' + access.getProperty(Config.AAF_DEFAULT_REALM,Config.getDefaultRealm());\r
+                                       }\r
+\r
+                                       u = userpass[0];\r
+                                       byte[] pass = access.decrypt(userpass[1], true).getBytes();\r
+                                       usr = new User<LocalPermission>(new ConfigPrincipal(u, pass));\r
+                               } else {\r
+                                       u = us[0];\r
+                                       usr = new User<LocalPermission>(new ConfigPrincipal(u, (byte[])null));\r
+                               }\r
+                               addUser(usr);\r
+                               access.log(Level.INIT, "Local User:",usr.principal);\r
+                               \r
+                               if(us.length>1) {\r
+                                       Map<String, Permission> newMap = usr.newMap();\r
+                                       for(String group : us[1].split(COMMA)) {\r
+                                               supportingGroups.add(group);\r
+                                               usr.add(newMap,new LocalPermission(group));\r
+                                       }\r
+                                       usr.setMap(newMap);\r
+                               }\r
+                       }\r
+               }\r
+               if(groupProperty!=null) {\r
+                       // For each Group name...\r
+                       for(String group : groupProperty.trim().split(SEMI)) {\r
+                               String[] gs = group.split(COLON,2);\r
+                               if(gs.length>1) {\r
+                                       supportingGroups.add(gs[0]);\r
+                                       LocalPermission p = new LocalPermission(gs[0]);\r
+                                       // Add all users (known by comma separators)    \r
+                                       \r
+                                       for(String grpMem : gs[1].split(COMMA)) {\r
+                                               // look for password, if so, put in passMap\r
+                                               String[] userpass = grpMem.split(PERCENT,2);\r
+                                               if(userpass.length>0 && userpass[0].indexOf('@')<0) {\r
+                                                       userpass[0]=userpass[0] + '@' + access.getProperty(Config.AAF_DEFAULT_REALM,Config.getDefaultRealm());\r
+                                               }\r
+                                               User<LocalPermission> usr = getUser(userpass[0]);\r
+                                               if(userpass.length>1) {\r
+                                                       byte[] pass = access.decrypt(userpass[1], true).getBytes();\r
+                                                       if(usr==null)addUser(usr=new User<LocalPermission>(new ConfigPrincipal(userpass[0],pass)));\r
+                                                       else usr.principal=new ConfigPrincipal(userpass[0],pass);\r
+                                               } else {\r
+                                                       if(usr==null)addUser(usr=new User<LocalPermission>(new ConfigPrincipal(userpass[0],(byte[])null)));\r
+                                               }\r
+                                               usr.add(p);\r
+                                               access.log(Level.INIT, "Local User:",usr.principal);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public boolean validate(String user, CredVal.Type type, byte[] cred) {\r
+               User<LocalPermission> usr = getUser(user);\r
+               switch(type) {\r
+                       case PASSWORD:\r
+                               // covers null as well as bad pass\r
+                               if(usr!=null && cred!=null && usr.principal instanceof ConfigPrincipal) {\r
+                                       return Hash.isEqual(cred,((ConfigPrincipal)usr.principal).getCred());\r
+                               }\r
+                               break;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       //      @Override\r
+       public boolean fish(Principal bait, Permission pond) {\r
+               if(supports(bait.getName()) && pond instanceof LocalPermission) { // local Users only have LocalPermissions\r
+                               User<LocalPermission> user = getUser(bait);\r
+                               return user==null?false:user.contains((LocalPermission)pond);\r
+                       }\r
+               return false;\r
+       }\r
+\r
+       public boolean fish(String bait, Permission pond) {\r
+               if(supports(bait) && pond instanceof LocalPermission) { // local Users only have LocalPermissions\r
+                       User<LocalPermission> user = getUser(bait);\r
+                       return user==null?false:user.contains((LocalPermission)pond);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       // We do not want to expose the actual Group, so make a copy.\r
+       public void fishAll(Principal bait, List<Permission> perms) {\r
+               if(supports(bait.getName())) {\r
+                       User<LocalPermission> user = getUser(bait);\r
+                       if(user!=null) {\r
+                               user.copyPermsTo(perms);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public void fishAll(String bait, List<Permission> perms) {\r
+               if(supports(bait)) {\r
+                       User<LocalPermission> user = getUser(bait);\r
+                       if(user!=null) {\r
+                               user.copyPermsTo(perms);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public boolean supports(String userName) {\r
+               return userName!=null && userName.endsWith(supportedRealm);\r
+       }\r
+\r
+       public boolean handlesExclusively(Permission pond) {\r
+               return supportingGroups.contains(pond.getKey());\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Lur#createPerm(java.lang.String)\r
+        */\r
+       @Override\r
+       public Permission createPerm(String p) {\r
+               return new LocalPermission(p);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/lur/LocalPermission.java b/core/src/main/java/com/att/cadi/lur/LocalPermission.java
new file mode 100644 (file)
index 0000000..8fdaec2
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur;\r
+\r
+import com.att.cadi.Permission;\r
+\r
+public class LocalPermission implements Permission {\r
+       private String key;\r
+       \r
+       public LocalPermission(String role) {\r
+               this.key = role;\r
+       }\r
+       \r
+       public String getKey() {\r
+               return key;\r
+       }\r
+\r
+       public String toString() {\r
+               return key;\r
+       }\r
+\r
+       public boolean match(Permission p) {\r
+               return key.equals(p.getKey());\r
+       }\r
+\r
+       public String permType() {\r
+               return "LOCAL";\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/core/src/main/java/com/att/cadi/lur/NullLur.java b/core/src/main/java/com/att/cadi/lur/NullLur.java
new file mode 100644 (file)
index 0000000..91fb7bb
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur;\r
+\r
+import java.security.Principal;\r
+import java.util.List;\r
+\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Permission;\r
+\r
+public class NullLur implements Lur {\r
+       private static final Permission NULL = new Permission() {\r
+               @Override\r
+               public String permType() {\r
+                       return "";\r
+               }\r
+\r
+               @Override\r
+               public String getKey() {\r
+                       return "";\r
+               }\r
+\r
+               @Override\r
+               public boolean match(Permission p) {\r
+                       return false;\r
+               }};\r
+\r
+       public boolean fish(Principal bait, Permission pond) {\r
+               // Well, for Jenkins, this is ok... It finds out it can't do J2EE Security, and then looks at it's own\r
+//             System.err.println("CADI's LUR has not been configured, but is still being called.  Access is being denied");\r
+               return false;\r
+       }\r
+\r
+       public void fishAll(Principal bait,     List<Permission> permissions) {\r
+       }\r
+\r
+       public void destroy() {\r
+       }\r
+\r
+       public boolean handlesExclusively(Permission pond) {\r
+               return false;\r
+       }\r
+\r
+       public boolean supports(String userName) {\r
+               return false;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Lur#createPerm(java.lang.String)\r
+        */\r
+       @Override\r
+       public Permission createPerm(String p) {\r
+               return NULL;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.Lur#clear(java.security.Principal, java.lang.StringBuilder)\r
+        */\r
+       @Override\r
+       public void clear(Principal p, StringBuilder report) {\r
+               report.append(NullLur.class.getSimpleName());\r
+               report.append('\n');\r
+       }\r
+       \r
+       public String toString() {\r
+               return NullLur.class.getSimpleName() + '\n';\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/BasicPrincipal.java b/core/src/main/java/com/att/cadi/principal/BasicPrincipal.java
new file mode 100644 (file)
index 0000000..58f7d71
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Date;\r
+\r
+import com.att.cadi.BasicCred;\r
+import com.att.cadi.GetCred;\r
+import com.att.cadi.Symm;\r
+\r
+public class BasicPrincipal extends BearerPrincipal implements GetCred {\r
+       private static byte[] basic = "Basic ".getBytes();\r
+\r
+       private String name = null;\r
+       private String shortName = null;\r
+       private byte[] cred = null;\r
+       \r
+       private long created;\r
+\r
+       public BasicPrincipal(String content,String domain) throws IOException {\r
+               created = System.currentTimeMillis();\r
+               ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());\r
+               // Read past "Basic ", ensuring it starts with it.\r
+               for(int i=0;i<basic.length;++i) {\r
+                       if(bis.read()!=basic[i]) {\r
+                               name=content;\r
+                               cred = null;\r
+                               return;\r
+                       }\r
+               }\r
+               BasicOS bos = new BasicOS(content.length());\r
+               Symm.base64.decode(bis,bos); // note: writes directly to name until ':'\r
+               if(name==null) throw new IOException("Invalid Coding");\r
+               else cred = bos.toCred();\r
+               int at;\r
+               if((at=name.indexOf('@'))>0) {\r
+                       domain=name.substring(at+1);\r
+                       shortName=name.substring(0, at);\r
+               } else {\r
+                       shortName = name;\r
+                       name = name + '@' + domain;\r
+               }\r
+       }\r
+       \r
+       public BasicPrincipal(BasicCred bc, String domain) {\r
+               name = bc.getUser();\r
+               cred = bc.getCred();\r
+       }\r
+\r
+       private class BasicOS extends OutputStream {\r
+               private boolean first = true;\r
+               private ByteArrayOutputStream baos;\r
+               \r
+               public BasicOS(int size) {\r
+                       baos = new ByteArrayOutputStream(size);\r
+               }\r
+\r
+               @Override\r
+               public void write(int b) throws IOException {\r
+                       if(b==':' && first) {\r
+                               first = false;\r
+                               name = new String(baos.toByteArray());\r
+                               baos.reset(); // \r
+                       } else {\r
+                               baos.write(b);\r
+                       }\r
+               }\r
+               \r
+               private byte[] toCred() {\r
+                       return baos.toByteArray();\r
+               }\r
+       }\r
+       \r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       public String getShortName() {\r
+               return shortName;\r
+       }\r
+       \r
+       public byte[] getCred() {\r
+               return cred;\r
+       }\r
+       \r
+       public long created() {\r
+               return created;\r
+       }\r
+\r
+       public String toString() {\r
+               return "Basic Authorization for " + name + " evaluated on " + new Date(created).toString();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/BearerPrincipal.java b/core/src/main/java/com/att/cadi/principal/BearerPrincipal.java
new file mode 100644 (file)
index 0000000..11bc22a
--- /dev/null
@@ -0,0 +1,37 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.security.Principal;\r
+\r
+public abstract class BearerPrincipal implements Principal {\r
+       private String bearer = null;\r
+       public BearerPrincipal setBearer(String bearer) {\r
+               this.bearer = bearer;\r
+               return this;\r
+       }\r
+       public String getBearer() {\r
+               return bearer;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/CSPPrincipal_T.java b/core/src/main/java/com/att/cadi/principal/CSPPrincipal_T.java
new file mode 100644 (file)
index 0000000..36c75b8
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.security.Principal;\r
+\r
+/**\r
+ * Indicate a CSP Principal that is trusted as a CSPPrincipal.  \r
+ *\r
+ */\r
+public interface CSPPrincipal_T extends Principal {\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/CachedBasicPrincipal.java b/core/src/main/java/com/att/cadi/principal/CachedBasicPrincipal.java
new file mode 100644 (file)
index 0000000..37c6a83
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.io.IOException;\r
+\r
+import com.att.cadi.BasicCred;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.taf.HttpTaf;\r
+\r
+/**\r
+ * Cached Principals need to be able to revalidate in the Background\r
+ * \r
+ *\r
+ */\r
+public class CachedBasicPrincipal extends BasicPrincipal implements CachedPrincipal {\r
+       private final HttpTaf creator;\r
+       private long timeToLive;\r
+       private long expires;\r
+\r
+       public CachedBasicPrincipal(HttpTaf creator, BasicCred bc, String domain, long timeToLive) {\r
+               super(bc, domain);\r
+               this.creator = creator;\r
+               this.timeToLive = timeToLive;\r
+               expires = System.currentTimeMillis()+timeToLive;\r
+       }\r
+       \r
+       public CachedBasicPrincipal(HttpTaf creator, String content, String domain, long timeToLive) throws IOException {\r
+               super(content, domain);\r
+               this.creator = creator;\r
+               this.timeToLive = timeToLive;\r
+               expires = System.currentTimeMillis()+timeToLive;\r
+       }\r
+\r
+       public CachedPrincipal.Resp revalidate() {\r
+               Resp resp = creator.revalidate(this);\r
+               if(resp.equals(Resp.REVALIDATED))expires = System.currentTimeMillis()+timeToLive;\r
+               return resp;\r
+       }\r
+\r
+       public long expires() {\r
+               return expires;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/TGuardPrincipal.java b/core/src/main/java/com/att/cadi/principal/TGuardPrincipal.java
new file mode 100644 (file)
index 0000000..aa610d3
--- /dev/null
@@ -0,0 +1,81 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+public class TGuardPrincipal extends BearerPrincipal {\r
+\r
+       private String name, tresp;\r
+\r
+       public TGuardPrincipal(String tresp) {\r
+               this.tresp=tresp;\r
+       }\r
+\r
+       /**\r
+        * TODO Need to figure out what Organizations TGuard entities should be part of.  \r
+        * \r
+        */\r
+       public String getName() {\r
+               if(name==null) {\r
+                       String temp = get("iv-user");\r
+                       if(temp==null)return null;\r
+                       StringBuilder sb = new StringBuilder();\r
+                       int at = temp.indexOf('@');\r
+                       if(at<0) {\r
+                               sb.append(temp);\r
+                       } else {\r
+                               sb.append(temp.substring(0, at));\r
+                       }\r
+                       if(temp.endsWith("@uverse.com"))sb.append("@uverse.tguard.att.com");\r
+                       else if(temp.endsWith("@att.com"))sb.append("@com.tguard.att.com");\r
+                       else if(temp.endsWith("@att.net"))sb.append("@net.tguard.att.com");\r
+                       else sb.append("@tguard.att.com");\r
+                       name = sb.toString();\r
+               }\r
+               return name;\r
+       }\r
+\r
+       /**\r
+        * Get a value from a named TGuard Property\r
+        * \r
+        * TGuard response info is very dynamic.  They can add new properties at any time, so we dare not code field names for these values.\r
+        * @param key\r
+        * @return\r
+        */\r
+       public String get(String key) {\r
+               if(key==null)return null;\r
+               int idx=0,equal=0,amp=0;\r
+               while(idx>=0 && (equal = tresp.indexOf('=',idx))>=0) {\r
+                       amp = tresp.indexOf('&',equal);\r
+                       if(key.regionMatches(0, tresp, idx, equal-idx)) {\r
+                               return amp>=0?tresp.substring(equal+1, amp):tresp.substring(equal+1); \r
+                       }\r
+                       idx=amp+(amp>0?1:0);\r
+               }\r
+               return null;\r
+       }\r
+\r
+       public String info() {\r
+               return tresp;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/TGuardPrincipal_T.java b/core/src/main/java/com/att/cadi/principal/TGuardPrincipal_T.java
new file mode 100644 (file)
index 0000000..97907ac
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.security.Principal;\r
+\r
+/**\r
+ * Indicate a TGuard Principal that is trusted as a TGuardPrincipal.  \r
+ *\r
+ */\r
+public interface TGuardPrincipal_T extends Principal {\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/TrustPrincipal.java b/core/src/main/java/com/att/cadi/principal/TrustPrincipal.java
new file mode 100644 (file)
index 0000000..67b76c6
--- /dev/null
@@ -0,0 +1,68 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.UserChain;\r
+\r
+public class TrustPrincipal extends BearerPrincipal implements UserChain {\r
+       private final String name;\r
+       private final Principal original;\r
+       private String userChain;\r
+       \r
+       public TrustPrincipal(final Principal actual, final String asName) {\r
+               this.original = actual;\r
+               name = asName.trim();\r
+               if(actual instanceof UserChain) {\r
+                       UserChain uc = (UserChain)actual;\r
+                       userChain = uc.userChain();\r
+               } else if(actual instanceof X509Principal) {\r
+                       userChain="x509";\r
+               } else if(actual instanceof BasicPrincipal) {\r
+                       userChain="BAth";\r
+               } else {\r
+                       userChain = actual.getClass().getSimpleName();\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       public String getOrigName() {\r
+               return original.getName() + '[' + userChain + ']';\r
+       }\r
+\r
+       @Override\r
+       public String userChain() {\r
+               return userChain;\r
+       }\r
+       \r
+       public Principal original() {\r
+               return original;\r
+       }\r
+       \r
+}\r
diff --git a/core/src/main/java/com/att/cadi/principal/X509Principal.java b/core/src/main/java/com/att/cadi/principal/X509Principal.java
new file mode 100644 (file)
index 0000000..8e17033
--- /dev/null
@@ -0,0 +1,93 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.principal;\r
+\r
+import java.io.IOException;\r
+import java.security.cert.CertificateEncodingException;\r
+import java.security.cert.X509Certificate;\r
+import java.util.regex.Pattern;\r
+\r
+import com.att.cadi.GetCred;\r
+\r
+public class X509Principal extends BearerPrincipal implements GetCred {\r
+       private static final Pattern pattern = Pattern.compile("[a-zA-Z0-9]*\\@[a-zA-Z0-9.]*");\r
+       private byte[] content;  \r
+       private X509Certificate cert;\r
+       private String name;\r
+\r
+       public X509Principal(String identity, X509Certificate cert, byte[] content) {\r
+               name = identity;\r
+               this.content = content;\r
+               this.cert = cert;\r
+       }\r
+       \r
+       public X509Principal(X509Certificate cert, byte[] content) throws IOException {\r
+               this.content=content;\r
+               this.cert = cert;\r
+               String subj = cert.getSubjectDN().getName();\r
+               int cn = subj.indexOf("OU=");\r
+               if(cn>=0) {\r
+                       cn+=3;\r
+                       int space = subj.indexOf(',',cn);\r
+                       if(space>=0) {\r
+                               String id = subj.substring(cn, space);\r
+                               if(pattern.matcher(id).matches()) {\r
+                                       name = id;\r
+                               }\r
+                       }\r
+               }\r
+               if(name==null)\r
+                       throw new IOException("X509 does not have Identity as CN");\r
+               \r
+       }\r
+       \r
+       \r
+       public String getAsHeader() throws IOException {\r
+               try {\r
+                       if(content==null) \r
+                               content=cert.getEncoded();\r
+               } catch (CertificateEncodingException e) {\r
+                       throw new IOException(e);\r
+               }\r
+               return "X509 " + content;\r
+       }\r
+       \r
+       public String toString() {\r
+               return "X509 Authentication for " + name;\r
+       }\r
+\r
+\r
+       public byte[] getCred() {\r
+               try {\r
+                       return content==null?(content=cert.getEncoded()):content;\r
+               } catch (CertificateEncodingException e) {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+\r
+       public String getName() {\r
+               return name;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/AbsTafResp.java b/core/src/main/java/com/att/cadi/taf/AbsTafResp.java
new file mode 100644 (file)
index 0000000..94d2e5d
--- /dev/null
@@ -0,0 +1,117 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+\r
+/**\r
+ * AbsTafResp\r
+ * \r
+ * Base class for TafResp (TAF Response Objects)\r
+ *\r
+ */\r
+public abstract class AbsTafResp implements TafResp {\r
+\r
+       protected final String desc;\r
+       protected final Principal principal;\r
+       protected final Access access;\r
+\r
+       /**\r
+        * AbsTafResp\r
+        * \r
+        * Set and hold\r
+        * Description (for logging)\r
+        * Principal (as created by derived class)\r
+        * Access (for access to underlying container, i.e. for Logging, auditing, ClassLoaders, etc)\r
+        *  \r
+        * @param access\r
+        * @param principal\r
+        * @param description\r
+        */\r
+       public AbsTafResp(Access access, Principal principal, String description) {\r
+               this.access = access;\r
+               this.principal = principal;\r
+               this.desc = description;\r
+       }\r
+\r
+       /**\r
+        * isValid()\r
+        * \r
+        * Respond in the affirmative if the TAF was able to Authenticate\r
+        */\r
+       public boolean isValid() {\r
+               return principal!=null;\r
+       }\r
+\r
+       /**\r
+        * desc()\r
+        * \r
+        * Respond with description of response as given by the TAF  \r
+        */\r
+       public String desc() {\r
+               return desc;\r
+       }\r
+\r
+       /**\r
+        * isAuthenticated()\r
+        * \r
+        * Respond with the TAF's code of whether Authenticated, or suggested next steps\r
+        * default is either IS_AUTHENTICATED, or TRY_ANOTHER_TAF.  The TAF can overload\r
+        * and suggest others, such as "NO_FURTHER_PROCESSING", if it can detect that this\r
+        * is some sort of security breach (i.e. Denial of Service)  \r
+        */\r
+       public RESP isAuthenticated() {\r
+               return principal==null?RESP.TRY_ANOTHER_TAF:RESP.IS_AUTHENTICATED;\r
+       }\r
+\r
+       /**\r
+        * getPrincipal()\r
+        * \r
+        * Return the principal created by the TAF based on Authentication. \r
+        * \r
+        * Returns "null" if Authentication failed (no principal)\r
+        */\r
+       public Principal getPrincipal() {\r
+               return principal;\r
+       }\r
+\r
+       /**\r
+        * getAccess()\r
+        * \r
+        * Get the Access object from the TAF, so that appropriate Logging, etc can be coordinated.\r
+        */\r
+       public Access getAccess() {\r
+               return access;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.taf.TafResp#isFailedAttempt()\r
+        */\r
+       public boolean isFailedAttempt() {\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/EpiTaf.java b/core/src/main/java/com/att/cadi/taf/EpiTaf.java
new file mode 100644 (file)
index 0000000..d3f5493
--- /dev/null
@@ -0,0 +1,85 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Taf;\r
+\r
+/**\r
+ * EpiTAF\r
+ * \r
+ * Short for "Epic TAF". Be able to run through a series of TAFs to obtain the validation needed.\r
+ * \r
+ * OK, the name could probably be better as "Tafs", like it was originally, but the pun was too\r
+ * irresistible for this author to pass up.\r
+ * \r
+ *\r
+ */\r
+public class EpiTaf implements Taf {\r
+       private Taf[] tafs;\r
+       \r
+       /**\r
+        * EpiTaf constructor\r
+        * \r
+        * Construct the EpiTaf from variable TAF parameters\r
+        * @param tafs\r
+        * @throws CadiException\r
+        */\r
+       public EpiTaf(Taf ... tafs) throws CadiException{\r
+               this.tafs = tafs;\r
+               if(tafs.length==0) throw new CadiException("Need at least one Taf implementation in constructor");\r
+       }\r
+\r
+       /**\r
+        * validate\r
+        * \r
+        * Respond with the first TAF to authenticate user based on variable info and "LifeForm" (is it \r
+        * a human behind an interface, or a server behind a protocol).\r
+        * \r
+        * If there is no TAF that can authenticate, respond with the first TAF that suggests it can\r
+        * establish an Authentication conversation (TRY_AUTHENTICATING).\r
+        * \r
+        * If no TAF declares either, respond with NullTafResp (which denies all questions)\r
+        */\r
+       public TafResp validate(LifeForm reading, String... info) {\r
+               TafResp tresp,firstTryAuth=null;\r
+               for(Taf taf : tafs) {\r
+                       tresp = taf.validate(reading, info);\r
+                       switch(tresp.isAuthenticated()) {\r
+                               case TRY_ANOTHER_TAF:\r
+                                       break;\r
+                               case TRY_AUTHENTICATING:\r
+                                       if(firstTryAuth==null)firstTryAuth=tresp;\r
+                                       break;\r
+                               default:\r
+                                       return tresp;\r
+                       }\r
+               }\r
+\r
+               // No TAFs configured, at this point.  It is safer at this point to be "not validated", \r
+               // rather than "let it go"\r
+               return firstTryAuth == null?NullTafResp.singleton():firstTryAuth;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/HttpEpiTaf.java b/core/src/main/java/com/att/cadi/taf/HttpEpiTaf.java
new file mode 100644 (file)
index 0000000..7f6d9af
--- /dev/null
@@ -0,0 +1,186 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.net.URI;\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.TrustChecker;\r
+\r
+/**\r
+ * HttpEpiTaf\r
+ * \r
+ * An extension of the basic "EpiTAF" concept, check known HTTP Related TAFs for valid credentials\r
+ * \r
+ *\r
+ */\r
+public class HttpEpiTaf implements HttpTaf {\r
+       private HttpTaf[] tafs;\r
+       private Access access;\r
+       private Locator<URI> locator;\r
+       private TrustChecker trustChecker;\r
+       \r
+       /**\r
+        * HttpEpiTaf constructor\r
+        * \r
+        * Construct the HttpEpiTaf from variable Http specific TAF parameters\r
+\r
+        * @param tafs\r
+        * @throws CadiException\r
+        */\r
+       public HttpEpiTaf(Access access, Locator<URI> locator, TrustChecker tc, HttpTaf ... tafs) throws CadiException{\r
+               this.tafs = tafs;\r
+               this.access = access;\r
+               this.locator = locator;\r
+               this.trustChecker = tc;\r
+               // Establish what Header Property to look for UserChain/Trust Props \r
+//             trustChainProp = access.getProperty(Config.CADI_TRUST_PROP, Config.CADI_TRUST_PROP_DEFAULT);\r
+\r
+               if(tafs.length==0) throw new CadiException("Need at least one HttpTaf implementation in constructor");\r
+       }\r
+\r
+       /**\r
+        * validate\r
+        * \r
+        * Respond with the first Http specific TAF to authenticate user based on variable info \r
+        * and "LifeForm" (is it a human behind a browser, or a server utilizing HTTP Protocol).\r
+        * \r
+        * If there is no HttpTAF that can authenticate, respond with the first TAF that suggests it can\r
+        * establish an Authentication conversation (TRY_AUTHENTICATING) (Examples include a redirect to CSP\r
+        * Servers for CSP Cookie, or BasicAuth 401 response, suggesting User/Password for given Realm \r
+        * submission\r
+        * \r
+        * If no TAF declares either, respond with NullTafResp (which denies all questions)\r
+        */\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               // Given a LifeForm Neutral, for HTTP, we need to discover true Life-Form Readings\r
+               if(reading==LifeForm.LFN) {\r
+                       reading = tricorderScan(req);\r
+               }\r
+               TafResp tresp=null, firstTry = null;\r
+               List<Redirectable> redirectables = null;\r
+               \r
+               for(HttpTaf taf : tafs) {\r
+                       tresp = taf.validate(reading, req, resp);\r
+                       switch(tresp.isAuthenticated()) {\r
+                               case TRY_ANOTHER_TAF:\r
+                                       break; // and loop\r
+                               case TRY_AUTHENTICATING:\r
+                                       if(tresp instanceof Redirectable) {\r
+                                               if(redirectables==null) {\r
+                                                       redirectables = new ArrayList<Redirectable>();\r
+                                               }\r
+                                               redirectables.add((Redirectable)tresp);\r
+                                       } else if(firstTry==null) {\r
+                                               firstTry = tresp;\r
+                                       }\r
+                                       break; \r
+                               case IS_AUTHENTICATED:\r
+                                       tresp = trustChecker.mayTrust(tresp, req);\r
+                                       return tresp;\r
+                               default:\r
+                                       return tresp;\r
+                       }\r
+               }\r
+               \r
+               // If No TAFs configured, at this point.  It is safer at this point to be "not validated", \r
+               // rather than "let it go"\r
+               // Note: if exists, there will always be more than 0 entries, according to above code\r
+               if(redirectables==null) {\r
+                       return firstTry!=null?firstTry:NullTafResp.singleton();\r
+               }\r
+               \r
+               // If there is one Tryable entry then return it\r
+               if(redirectables.size()>1) {\r
+                       return LoginPageTafResp.create(access,locator,resp,redirectables);\r
+               } else {\r
+                       return redirectables.get(0);\r
+               }\r
+       }\r
+       \r
+       public boolean revalidate(Principal prin) throws Exception {\r
+               return false;\r
+       }\r
+\r
+       /*\r
+        * Since this is internal, we use a little Star Trek humor to indicate looking in the HTTP Request to see if we can determine what kind\r
+        * of "LifeForm" reading we can determine, i.e. is there a Human (CarbonBasedLifeForm) behind a browser, or is it mechanical \r
+        * id (SiliconBasedLifeForm)?  This makes a difference in some Authentication, i.e CSP, which doesn't work well for SBLFs\r
+        */\r
+       private LifeForm tricorderScan(HttpServletRequest req) {\r
+               // For simplicity's sake, we'll say Humans use FQDNs, not IPs.\r
+               \r
+               String auth = req.getParameter("Authentication");\r
+               if(auth!=null) {\r
+                       if("BasicAuth".equals(auth)) {\r
+                               return LifeForm.SBLF;\r
+                       }\r
+               }\r
+               // Current guess that only Browsers bother to set "Agent" codes that identify the kind of browser they are.\r
+               // If mechanical frameworks are found that populate this, then more advanced analysis may be required\r
+               //  1/22/2013\r
+               String agent = req.getHeader("User-Agent");\r
+               if(agent!=null && agent.startsWith("Mozilla")) // covers I.E./Firefox/Safari/probably any other "advanced" Browser see http://en.wikipedia.org/wiki/User_agent\r
+                       return LifeForm.CBLF;                      \r
+               return LifeForm.SBLF;                                                   // notably skips "curl","wget", (which is desired behavior.  We don't want to try CSP, etc on these)\r
+       }\r
+\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               Resp resp;\r
+               for(HttpTaf taf : tafs) {\r
+                       resp = taf.revalidate(prin);\r
+                       switch(resp) {\r
+                               case NOT_MINE:\r
+                                       break;\r
+                               default:\r
+                                       return resp;\r
+                       }\r
+               }\r
+               return Resp.NOT_MINE;\r
+       }\r
+\r
+       /**\r
+        * List HttpTafs with their "toString" representations... primarily useful for Debugging in an IDE\r
+        * like Eclipse.\r
+        */\r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder();\r
+               for(HttpTaf ht : tafs) {\r
+                       sb.append(ht.toString());\r
+                       sb.append(". ");\r
+               }\r
+               return sb.toString();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/HttpTaf.java b/core/src/main/java/com/att/cadi/taf/HttpTaf.java
new file mode 100644 (file)
index 0000000..4270a81
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.Taf.LifeForm;\r
+\r
+/**\r
+ * A TAF which is in a specific HTTP environment in which the engine implements \r
+ * javax Servlet.\r
+ * \r
+ * Using the Http Request and Response interfaces takes the effort out of implementing in almost any kind of\r
+ * HTTP Container or Engine.\r
+ *  \r
+ *\r
+ */\r
+public interface HttpTaf {\r
+       /**\r
+        * validate\r
+        * \r
+        * Validate the Request, and respond with created TafResp object.\r
+        * \r
+        * @param reading\r
+        * @param req\r
+        * @param resp\r
+        * @return\r
+        */\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp);\r
+       \r
+       /**\r
+        * Re-Validate Credential\r
+        * \r
+        * @param prin\r
+        * @return\r
+        */\r
+       public CachedPrincipal.Resp revalidate(CachedPrincipal prin);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/LoginPageTafResp.java b/core/src/main/java/com/att/cadi/taf/LoginPageTafResp.java
new file mode 100644 (file)
index 0000000..d9da3fa
--- /dev/null
@@ -0,0 +1,88 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.net.URI;\r
+import java.util.List;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.Locator;\r
+import com.att.cadi.Locator.Item;\r
+\r
+public class LoginPageTafResp extends AbsTafResp {\r
+       private final HttpServletResponse httpResp;\r
+       private final String loginPageURL;\r
+\r
+       private LoginPageTafResp(Access access, final HttpServletResponse resp, String loginPageURL) {\r
+               super(access, null, "Multiple Possible HTTP Logins available.  Redirecting to Login Choice Page");\r
+               httpResp = resp;\r
+               this.loginPageURL = loginPageURL;\r
+       }\r
+\r
+       @Override\r
+       public RESP authenticate() throws IOException {\r
+               httpResp.sendRedirect(loginPageURL);\r
+               return RESP.HTTP_REDIRECT_INVOKED;\r
+       }\r
+       \r
+       @Override\r
+       public RESP isAuthenticated() {\r
+               return RESP.TRY_AUTHENTICATING;\r
+       }\r
+       \r
+       public static TafResp create(Access access, Locator<URI> locator, final HttpServletResponse resp, List<Redirectable> redir) {\r
+               if(locator!=null) {\r
+                       try {\r
+                               Item item = locator.best();\r
+                               URI uri = locator.get(item);\r
+                               if(uri!=null) {\r
+                                       StringBuilder sb = new StringBuilder(uri.toString());\r
+                                       String query = uri.getQuery();\r
+                                       boolean first = query==null || query.length()==0;\r
+                                       int count=0;\r
+                                       for(Redirectable t : redir) {\r
+                                               if(first) {\r
+                                                       sb.append('?');\r
+                                                       first=false;\r
+                                               }\r
+                                               else sb.append('&');\r
+                                               sb.append(t.get());\r
+                                               ++count;\r
+                                       }\r
+                                       if(count>0)return new LoginPageTafResp(access, resp, sb.toString());\r
+                               }\r
+                       } catch (Exception e) {\r
+                               access.log(e, "Error deriving Login Page location");\r
+                       }\r
+               } else if(!redir.isEmpty()) { \r
+                       access.log(Level.DEBUG,"LoginPage Locator is not configured. Taking first Redirectable Taf");\r
+                       return redir.get(0);\r
+               }\r
+               return NullTafResp.singleton();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/NullTaf.java b/core/src/main/java/com/att/cadi/taf/NullTaf.java
new file mode 100644 (file)
index 0000000..ec4a15b
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.Taf;\r
+\r
+\r
+/**\r
+ * This TAF is set at the very beginning of Filters and Valves so that if any configuration issues hit while\r
+ * starting, the default behavior is to shut down traffic rather than leaving an open hole\r
+ * \r
+ *\r
+ */\r
+public class NullTaf implements Taf, HttpTaf {\r
+       // Singleton Pattern\r
+       public NullTaf() {}\r
+\r
+       /**\r
+        * validate \r
+        * \r
+        * Always Respond with a NullTafResp, which declares it is unauthenticated, and unauthorized\r
+        */\r
+       public TafResp validate(LifeForm reading, String... info) {\r
+               return NullTafResp.singleton();\r
+       }\r
+\r
+       /**\r
+        * validate \r
+        * \r
+        * Always Respond with a NullTafResp, which declares it is unauthenticated, and unauthorized\r
+        */\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               return NullTafResp.singleton();\r
+       }\r
+\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               return Resp.NOT_MINE;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/NullTafResp.java b/core/src/main/java/com/att/cadi/taf/NullTafResp.java
new file mode 100644 (file)
index 0000000..c95b195
--- /dev/null
@@ -0,0 +1,74 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+\r
+/**\r
+ * A Null Pattern for setting responses to "Deny" before configuration is setup.\r
+ *\r
+ */\r
+class NullTafResp implements TafResp {\r
+       private NullTafResp(){}\r
+       \r
+       private static TafResp singleton = new NullTafResp();\r
+       \r
+       public static TafResp singleton() {\r
+               return singleton;\r
+       }\r
+       \r
+       public boolean isValid() {\r
+               return false;\r
+       }\r
+       \r
+       public RESP isAuthenticated() {\r
+               return RESP.NO_FURTHER_PROCESSING;\r
+       }\r
+       \r
+       public String desc() {\r
+               return "All Authentication denied";\r
+       }\r
+       \r
+       public RESP authenticate() throws IOException {\r
+               return RESP.NO_FURTHER_PROCESSING;\r
+       }\r
+\r
+       public Principal getPrincipal() {\r
+               return null;\r
+       }\r
+\r
+       public Access getAccess() {\r
+               return Access.NULL;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see com.att.cadi.taf.TafResp#isFailedAttempt()\r
+        */\r
+       public boolean isFailedAttempt() {\r
+               return true;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/PuntTafResp.java b/core/src/main/java/com/att/cadi/taf/PuntTafResp.java
new file mode 100644 (file)
index 0000000..d9f9b67
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+\r
+/**\r
+ * A Punt Resp to make it fast and easy for a Taf to respond that it cannot handle a particular kind of\r
+ * request.  It is always the same object, so there is no cost for memory, etc.\r
+ *\r
+ */\r
+public class PuntTafResp implements TafResp {\r
+       private PuntTafResp(){}\r
+       \r
+       private static TafResp singleton = new PuntTafResp();\r
+       \r
+       public static TafResp singleton() {\r
+               return singleton;\r
+       }\r
+       \r
+       public boolean isValid() {\r
+               return false;\r
+       }\r
+       \r
+       public RESP isAuthenticated() {\r
+               return RESP.TRY_ANOTHER_TAF;\r
+       }\r
+       \r
+       public String desc() {\r
+               return "This Taf can or will not handle this authentication";\r
+       }\r
+       \r
+       public RESP authenticate() throws IOException {\r
+               return RESP.TRY_ANOTHER_TAF;\r
+       }\r
+\r
+       public Principal getPrincipal() {\r
+               return null;\r
+       }\r
+\r
+       public Access getAccess() {\r
+               return NullTafResp.singleton().getAccess();\r
+       }\r
+\r
+       public boolean isFailedAttempt() {\r
+               return false;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/Redirectable.java b/core/src/main/java/com/att/cadi/taf/Redirectable.java
new file mode 100644 (file)
index 0000000..e83e7ce
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+public interface Redirectable extends TafResp {\r
+       /**\r
+        * Create a Redirectable URL entry prefaced by a URLEncoder.String for a Menu\r
+        * example:\r
+        * "Global Login=https://xxxx....."\r
+        */\r
+       public String get();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/TafResp.java b/core/src/main/java/com/att/cadi/taf/TafResp.java
new file mode 100644 (file)
index 0000000..3a1a6f4
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CadiException;\r
+\r
+/**\r
+ * Response from Taf objects, which inform users what has happened and/or what should be done\r
+ * \r
+ *\r
+ */\r
+public interface TafResp {\r
+       public static enum RESP {\r
+               IS_AUTHENTICATED, \r
+               NO_FURTHER_PROCESSING, \r
+               TRY_AUTHENTICATING, \r
+               TRY_ANOTHER_TAF,\r
+               FAIL, \r
+               // A note was made to avoid the response REDIRECT.  However, I have deemed that it is \r
+               // unavoidable when the underlying TAF did do a REDIRECT, because it requires a HTTP\r
+               // Service code to exit without modifying the Response any further.\r
+               // Therefore, I have changed this to indicate what HAS happened, with should accommodate \r
+               // both positions.  JG 10/18/2012\r
+//             public static final int HTTP_REDIRECT_INVOKED = 11;\r
+               HTTP_REDIRECT_INVOKED,\r
+               HAS_PROCESSED};\r
+       \r
+       /**\r
+        * Basic success check\r
+        * @return\r
+        */\r
+       public boolean isValid();\r
+       \r
+       /**\r
+        *  String description of what has occurred (for logging/exceptions)\r
+        * @return\r
+        */\r
+       public String desc();\r
+       \r
+       /**\r
+        * Check Response\r
+        * @return\r
+        */\r
+       public RESP isAuthenticated();\r
+\r
+       /**\r
+        * Authenticate, returning FAIL or Other Valid indication\r
+        * \r
+        * HTTP implementations should watch for "HTTP_REDIRECT_INVOKED", and end the HTTP call appropriately.\r
+        * @return\r
+        * @throws CadiException \r
+        */\r
+       public RESP authenticate() throws IOException;\r
+\r
+       /**\r
+        * Once authenticated, this object should hold a Principal created from the authorization\r
+        * @return\r
+        */\r
+       public Principal getPrincipal();\r
+\r
+       /**\r
+        * get the Access object which created this object, allowing the responder to appropriate Log, etc\r
+        */\r
+       public Access getAccess();\r
+       \r
+       /**\r
+        * Be able to check if part of a Failed attempt\r
+        */\r
+       public boolean isFailedAttempt();\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/TrustNotTafResp.java b/core/src/main/java/com/att/cadi/taf/TrustNotTafResp.java
new file mode 100644 (file)
index 0000000..127450c
--- /dev/null
@@ -0,0 +1,78 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+\r
+public class TrustNotTafResp implements TafResp {\r
+       private final TafResp delegate;\r
+       private final String desc;\r
+       \r
+       public TrustNotTafResp(final TafResp delegate, final String desc) {\r
+               this.delegate = delegate;\r
+               this.desc = desc;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isValid() {\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public String desc() {\r
+               return desc;\r
+       }\r
+\r
+       @Override\r
+       public RESP isAuthenticated() {\r
+               return RESP.NO_FURTHER_PROCESSING;\r
+       }\r
+\r
+       @Override\r
+       public RESP authenticate() throws IOException {\r
+               return RESP.NO_FURTHER_PROCESSING;\r
+       }\r
+\r
+       @Override\r
+       public Principal getPrincipal() {\r
+               return delegate.getPrincipal();\r
+       }\r
+\r
+       @Override\r
+       public Access getAccess() {\r
+               return delegate.getAccess();\r
+       }\r
+\r
+       @Override\r
+       public boolean isFailedAttempt() {\r
+               return true;\r
+       }\r
+       \r
+       public String toString() {\r
+               return desc();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/TrustTafResp.java b/core/src/main/java/com/att/cadi/taf/TrustTafResp.java
new file mode 100644 (file)
index 0000000..27c6034
--- /dev/null
@@ -0,0 +1,80 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+\r
+public class TrustTafResp implements TafResp {\r
+       private final TafResp delegate;\r
+       private final Principal principal;\r
+       private final String desc;\r
+       \r
+       public TrustTafResp(final TafResp delegate, final Principal principal, final String desc) {\r
+               this.delegate = delegate;\r
+               this.principal = principal;\r
+               this.desc = desc + ' ' + delegate.desc();\r
+       }\r
+       \r
+       @Override\r
+       public boolean isValid() {\r
+               return delegate.isValid();\r
+       }\r
+\r
+       @Override\r
+       public String desc() {\r
+               return desc;\r
+       }\r
+\r
+       @Override\r
+       public RESP isAuthenticated() {\r
+               return delegate.isAuthenticated();\r
+       }\r
+\r
+       @Override\r
+       public RESP authenticate() throws IOException {\r
+               return delegate.authenticate();\r
+       }\r
+\r
+       @Override\r
+       public Principal getPrincipal() {\r
+               return principal;\r
+       }\r
+\r
+       @Override\r
+       public Access getAccess() {\r
+               return delegate.getAccess();\r
+       }\r
+\r
+       @Override\r
+       public boolean isFailedAttempt() {\r
+               return delegate.isFailedAttempt();\r
+       }\r
+       \r
+       public String toString() {\r
+               return principal.getName() + " by trust of " + desc();\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTaf.java b/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTaf.java
new file mode 100644 (file)
index 0000000..672c463
--- /dev/null
@@ -0,0 +1,160 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.basic;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.BasicCred;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CredVal;\r
+import com.att.cadi.CredVal.Type;\r
+import com.att.cadi.Taf;\r
+import com.att.cadi.principal.BasicPrincipal;\r
+import com.att.cadi.principal.CachedBasicPrincipal;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+import com.att.cadi.taf.dos.DenialOfServiceTaf;\r
+\r
+/**\r
+ * BasicHttpTaf\r
+ * \r
+ * This TAF implements the "Basic Auth" protocol.  \r
+ * \r
+ * WARNING! It is true for any implementation of "Basic Auth" that the password is passed unencrypted.  \r
+ * This is because the expectation, when designed years ago, was that it would only be used in \r
+ * conjunction with SSL (https).  It is common, however, for users to ignore this on the assumption that\r
+ * their internal network is secure, or just ignorance.  Therefore, a WARNING will be printed\r
+ * when the HTTP Channel is not encrypted (unless explicitly turned off).\r
+ * \r
+ *\r
+ */\r
+public class BasicHttpTaf implements HttpTaf {\r
+       private Access access;\r
+       private String realm;\r
+       private CredVal rbac;\r
+       private boolean warn;\r
+       private long timeToLive;\r
+       \r
+       public BasicHttpTaf(Access access, CredVal rbac, String realm, long timeToLive, boolean turnOnWarning) {\r
+               this.access = access;\r
+               this.realm = realm;\r
+               this.rbac = rbac;\r
+               this.warn = turnOnWarning;\r
+               this.timeToLive = timeToLive;\r
+       }\r
+\r
+       /**\r
+        * Note: BasicHttp works for either Carbon Based (Humans) or Silicon Based (machine) Lifeforms.  \r
+        * @see Taf\r
+        */\r
+       public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               // See if Request implements BasicCred (aka CadiWrap or other), and if User/Pass has already been set separately\r
+               if(req instanceof BasicCred) {\r
+                       BasicCred bc = (BasicCred)req;\r
+                       if(bc.getUser()!=null) { // CadiWrap, if set, makes sure User & Password are both valid, or both null\r
+                               if(DenialOfServiceTaf.isDeniedID(bc.getUser())!=null) {\r
+                                       return DenialOfServiceTaf.respDenyID(access,bc.getUser());\r
+                               }\r
+                               CachedBasicPrincipal bp = new CachedBasicPrincipal(this,bc,realm,timeToLive);\r
+                               // ONLY FOR Last Ditch DEBUGGING... \r
+                               // access.log(Level.WARN,bp.getName() + ":" + new String(bp.getCred()));\r
+                               if(rbac.validate(bp.getName(),Type.PASSWORD,bp.getCred())) {\r
+                                       return new BasicHttpTafResp(access,bp,bp.getName()+" authenticated by password",RESP.IS_AUTHENTICATED,resp,realm,false);\r
+                               } else {\r
+                                       //TODO may need timed retries in a given time period\r
+                                       return new BasicHttpTafResp(access,null,buildMsg(bp,req,"User/Pass combo invalid for ",bc.getUser()), \r
+                                                       RESP.TRY_AUTHENTICATING,resp,realm,true);\r
+                               }\r
+                       }\r
+               }\r
+               // Get User/Password from Authorization Header value\r
+               String authz = req.getHeader("Authorization");\r
+               if(authz != null && authz.startsWith("Basic ")) {\r
+                       if(warn&&!req.isSecure()) {\r
+                               access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");\r
+                       }\r
+                       try {\r
+                               CachedBasicPrincipal ba = new CachedBasicPrincipal(this,authz,realm,timeToLive);\r
+                               if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {\r
+                                       return DenialOfServiceTaf.respDenyID(access,ba.getName());\r
+                               }\r
+\r
+                               // ONLY FOR Last Ditch DEBUGGING... \r
+                               // access.log(Level.WARN,ba.getName() + ":" + new String(ba.getCred()));\r
+                               if(rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())) {\r
+                                       return new BasicHttpTafResp(access,ba, ba.getName()+" authenticated by BasicAuth password",RESP.IS_AUTHENTICATED,resp,realm,false);\r
+                               } else {\r
+                                       //TODO may need timed retries in a given time period\r
+                                       return new BasicHttpTafResp(access,null,buildMsg(ba,req,"User/Pass combo invalid"), \r
+                                                       RESP.TRY_AUTHENTICATING,resp,realm,true);\r
+                               }\r
+                       } catch (IOException e) {\r
+                               String msg = buildMsg(null,req,"Failed HTTP Basic Authorization (", e.getMessage(), ')');\r
+                               access.log(Level.INFO,msg);\r
+                               return new BasicHttpTafResp(access,null,msg, RESP.TRY_AUTHENTICATING, resp, realm,true);\r
+                       }\r
+               }\r
+               return new BasicHttpTafResp(access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,realm,false);\r
+       }\r
+       \r
+       protected String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {\r
+               StringBuilder sb = new StringBuilder();\r
+               for(Object s : msg) {\r
+                       sb.append(s.toString());\r
+               }\r
+               if(pr!=null) {\r
+                       sb.append(" for ");\r
+                       sb.append(pr.getName());\r
+               }\r
+               sb.append(" from ");\r
+               sb.append(req.getRemoteAddr());\r
+               sb.append(':');\r
+               sb.append(req.getRemotePort());\r
+               return sb.toString();\r
+       }\r
+\r
+       @Override\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               if(prin instanceof BasicPrincipal) {\r
+                       BasicPrincipal ba = (BasicPrincipal)prin;\r
+                       if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {\r
+                               return Resp.UNVALIDATED;\r
+                       }\r
+                       return rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())?Resp.REVALIDATED:Resp.UNVALIDATED;\r
+               }\r
+               return Resp.NOT_MINE;\r
+       }\r
+       \r
+       public String toString() {\r
+               return "Basic Auth enabled on realm: " + realm;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTafResp.java b/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTafResp.java
new file mode 100644 (file)
index 0000000..c768587
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.basic;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.taf.AbsTafResp;\r
+import com.att.cadi.taf.TafResp;\r
+\r
+public class BasicHttpTafResp extends AbsTafResp implements TafResp {\r
+       private HttpServletResponse httpResp;\r
+       private String realm;\r
+       private RESP status;\r
+       private final boolean wasFailed;\r
+       \r
+       public BasicHttpTafResp(Access access, Principal principal, String description, RESP status, HttpServletResponse resp, String realm, boolean wasFailed) {\r
+               super(access,principal, description);\r
+               httpResp = resp;\r
+               this.realm = realm;\r
+               this.status = status;\r
+               this.wasFailed = wasFailed;\r
+       }\r
+\r
+       public RESP authenticate() throws IOException {\r
+               httpResp.setStatus(401); // Unauthorized        \r
+               httpResp.setHeader("WWW-Authenticate", "Basic realm=\""+realm+'"');\r
+               return RESP.HTTP_REDIRECT_INVOKED;\r
+       }\r
+\r
+       public RESP isAuthenticated() {\r
+               return status;\r
+       }\r
+\r
+       public boolean isFailedAttempt() {\r
+               return wasFailed;\r
+       }\r
+\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/cert/CertIdentity.java b/core/src/main/java/com/att/cadi/taf/cert/CertIdentity.java
new file mode 100644 (file)
index 0000000..6e46481
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.cert;\r
+\r
+import java.security.Principal;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.X509Certificate;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+\r
+public interface CertIdentity {\r
+       /**\r
+        * identity from X509Certificate Object and/or certBytes\r
+        * \r
+        * If you have both, include them.  If you only have one, leave the other null, and it will be generated if needed\r
+        * \r
+        * The Request is there to obtain Header or Attribute info of ultimate user\r
+        * \r
+        * @param req\r
+        * @param cert\r
+        * @param certBytes\r
+        * @return\r
+        * @throws CertificateException \r
+        */\r
+       public Principal identity(HttpServletRequest req, X509Certificate cert, byte[] certBytes) throws CertificateException;\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/cert/X509HttpTafResp.java b/core/src/main/java/com/att/cadi/taf/cert/X509HttpTafResp.java
new file mode 100644 (file)
index 0000000..3435d52
--- /dev/null
@@ -0,0 +1,53 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.cert;\r
+\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.taf.AbsTafResp;\r
+import com.att.cadi.taf.TafResp;\r
+\r
+public class X509HttpTafResp extends AbsTafResp implements TafResp {\r
+       private RESP status;\r
+       \r
+       public X509HttpTafResp(Access access, Principal principal, String description, RESP status) {\r
+               super(access, principal, description);\r
+               this.status = status;\r
+       }\r
+\r
+       public RESP authenticate() throws IOException {\r
+               return RESP.TRY_ANOTHER_TAF;\r
+       }\r
+\r
+       public RESP isAuthenticated() {\r
+               return status;\r
+       }\r
+\r
+       public String toString() {\r
+               return status.name();\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/cert/X509Taf.java b/core/src/main/java/com/att/cadi/taf/cert/X509Taf.java
new file mode 100644 (file)
index 0000000..cb93046
--- /dev/null
@@ -0,0 +1,258 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.cert;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.security.GeneralSecurityException;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.security.Principal;\r
+import java.security.Signature;\r
+import java.security.cert.CertificateException;\r
+import java.security.cert.CertificateFactory;\r
+import java.security.cert.X509Certificate;\r
+import java.util.ArrayList;\r
+\r
+import javax.net.ssl.TrustManagerFactory;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.config.Config;\r
+import com.att.cadi.config.SecurityInfoC;\r
+import com.att.cadi.config.SecurityInfo;\r
+import com.att.cadi.lur.LocalPermission;\r
+import com.att.cadi.principal.TGuardPrincipal;\r
+import com.att.cadi.principal.X509Principal;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+import com.att.cadi.util.Split;\r
+\r
+public class X509Taf implements HttpTaf {\r
+       \r
+       public static final CertificateFactory certFactory;\r
+       public static final MessageDigest messageDigest;\r
+       public static final TrustManagerFactory tmf;\r
+       private Access access;\r
+       private CertIdentity[] certIdents;\r
+       private Lur lur;\r
+       private ArrayList<String> cadiIssuers;\r
+       private String env;\r
+       private SecurityInfo si;\r
+\r
+       static {\r
+               try {\r
+                       certFactory = CertificateFactory.getInstance("X.509");\r
+                       messageDigest = MessageDigest.getInstance("SHA-256"); // use this to clone\r
+                       tmf = TrustManagerFactory.getInstance(SecurityInfoC.SslKeyManagerFactoryAlgorithm);\r
+               } catch (Exception e) {\r
+                       throw new RuntimeException("X.509 and SHA-256 are required for X509Taf",e);\r
+               }\r
+       }\r
+       \r
+       public X509Taf(Access access, Lur lur, CertIdentity ... cis) throws CertificateException, NoSuchAlgorithmException, CadiException {\r
+               this.access = access;\r
+               env = access.getProperty(Config.AAF_ENV,null);\r
+               if(env==null) {\r
+                       throw new CadiException("X509Taf requires Environment ("+Config.AAF_ENV+") to be set.");\r
+               }\r
+               this.lur = lur;\r
+               this.cadiIssuers = new ArrayList<String>();\r
+               for(String ci : access.getProperty(Config.CADI_X509_ISSUERS, "CN=ATT CADI Issuing CA 01, OU=CSO, O=ATT, C=US:CN=ATT CADI Issuing CA 02, OU=CSO, O=ATT, C=US").split(":")) {\r
+                       cadiIssuers.add(ci);\r
+               }\r
+               try {\r
+                       Class<?> dci = access.classLoader().loadClass("com.att.authz.cadi.DirectCertIdentity");\r
+                       CertIdentity temp[] = new CertIdentity[cis.length+1];\r
+                       System.arraycopy(cis, 0, temp, 1, cis.length);\r
+                       temp[0] = (CertIdentity) dci.newInstance();\r
+                       certIdents=temp;\r
+               } catch (Exception e) {\r
+                       certIdents = cis;\r
+               }\r
+               \r
+               try {\r
+                       si = new SecurityInfo(access);\r
+               } catch (GeneralSecurityException | IOException e1) {\r
+                       throw new CadiException(e1);\r
+               }\r
+       }\r
+\r
+       public static final X509Certificate getCert(byte[] certBytes) throws CertificateException {\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);\r
+               return (X509Certificate)certFactory.generateCertificate(bais);\r
+       }\r
+\r
+       public static final byte[] getFingerPrint(byte[] ba) {\r
+               MessageDigest md;\r
+               try {\r
+                       md = (MessageDigest)messageDigest.clone();\r
+               } catch (CloneNotSupportedException e) {\r
+                       // should never get here\r
+                       return new byte[0];\r
+               }\r
+               md.update(ba);\r
+               return md.digest();\r
+       }\r
+\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               // Check for Mutual SSL\r
+               try {\r
+                       X509Certificate[] certarr = (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");\r
+                       if(certarr!=null && certarr.length>0) {\r
+                               si.checkClientTrusted(certarr);\r
+                               // Note: If the Issuer is not in the TrustStore, it's not added to the Cert list\r
+                               if(cadiIssuers.contains(certarr[0].getIssuerDN().toString())) {\r
+                                       String x500 = certarr[0].getSubjectDN().getName();\r
+                                       int ou=x500.indexOf("OU=");\r
+                                       if(ou>0) {\r
+                                               ou+=3;\r
+                                               int comma = x500.indexOf(',',ou);\r
+                                               if(comma>0) {\r
+                                                       String id= x500.substring(ou,comma);\r
+                                                       String idenv[] = id.split(":");\r
+                                                       if(idenv.length==1 || (idenv.length>1 && env.equals(idenv[1]))) {\r
+                                                               return new X509HttpTafResp(access, \r
+                                                                       new X509Principal(idenv[0], certarr[0],null), \r
+                                                                               id + " validated by CADI x509", RESP.IS_AUTHENTICATED);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       byte[] array = null;\r
+                       byte[] certBytes = null;\r
+                       X509Certificate cert=null;\r
+                       String responseText=null;\r
+                       String authHeader = req.getHeader("Authorization");\r
+\r
+                       if(certarr!=null) {  // If cert !=null, Cert is Tested by Mutual Protocol.\r
+                               if(authHeader!=null) { // This is only intended to be a Secure Connection, not an Identity\r
+                                       return new X509HttpTafResp(access, null, "Certificate verified, but another Identity is presented", RESP.TRY_ANOTHER_TAF);\r
+                               }\r
+                               cert = certarr[0];\r
+                               responseText = ", validated by Mutual SSL Protocol";\r
+                       } else {                 // If cert == null, Get Declared Cert (in header), but validate by having them sign something\r
+                               if(authHeader != null && authHeader.startsWith("x509 ")) {\r
+                                       ByteArrayOutputStream baos = new ByteArrayOutputStream(authHeader.length());\r
+                                       try {\r
+                                               array = authHeader.getBytes();\r
+                                               ByteArrayInputStream bais = new ByteArrayInputStream(array);\r
+                                               Symm.base64noSplit.decode(bais, baos, 5);\r
+                                               certBytes = baos.toByteArray();\r
+                                               cert = getCert(certBytes);\r
+                                               \r
+                                               /** \r
+                                                * Identity from CERT if well know CA and specific encoded information\r
+                                                */\r
+                                               // If found Identity doesn't work, try SignedStuff Protocol\r
+//                                                                     cert.checkValidity();\r
+//                                                                     cert.--- GET FINGERPRINT?\r
+                                               String stuff = req.getHeader("Signature");\r
+                                               if(stuff==null) \r
+                                                       return new X509HttpTafResp(access, null, "Header entry 'Signature' required to validate One way X509 Certificate", RESP.TRY_ANOTHER_TAF);\r
+                                               String data = req.getHeader("Data"); \r
+//                                                                     if(data==null) \r
+//                                                                             return new X509HttpTafResp(access, null, "No signed Data to validate with X509 Certificate", RESP.TRY_ANOTHER_TAF);\r
+\r
+                                               // Note: Data Pos shows is "<signatureType> <data>"\r
+//                                                                     int dataPos = (stuff.indexOf(' ')); // determine what is Algorithm\r
+                                               // Get Signature \r
+                                               bais = new ByteArrayInputStream(stuff.getBytes());\r
+                                               baos = new ByteArrayOutputStream(stuff.length());\r
+                                               Symm.base64noSplit.decode(bais, baos);\r
+                                               array = baos.toByteArray();\r
+//                                                                     Signature sig = Signature.getInstance(stuff.substring(0, dataPos)); // get Algorithm from first part of Signature\r
+                                               \r
+                                               Signature sig = Signature.getInstance(cert.getSigAlgName()); \r
+                                               sig.initVerify(cert.getPublicKey());\r
+                                               sig.update(data.getBytes());\r
+                                               if(!sig.verify(array)) {\r
+                                                       access.log(Level.ERROR, "Signature doesn't Match");\r
+                                                       return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
+                                               }\r
+                                               responseText = ", validated by Signed Data";\r
+                                       } catch (Exception e) {\r
+                                               access.log(e, "Exception while validating Cert");\r
+                                               return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
+                                       }\r
+                                       \r
+                               } else {\r
+                                       return new X509HttpTafResp(access, null, "No Certificate Info on Transaction", RESP.TRY_ANOTHER_TAF);\r
+                               }\r
+                       }\r
+\r
+                       // A cert has been found, match Identify\r
+                       Principal prin=null;\r
+                       \r
+                       for(int i=0;prin==null && i<certIdents.length;++i) {\r
+                               if((prin=certIdents[i].identity(req, cert, certBytes))!=null) {\r
+                                       responseText = prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText;\r
+//                                     xresp = new X509HttpTafResp(\r
+//                                                             access,\r
+//                                                             prin,\r
+//                                                             prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText,\r
+//                                                             RESP.IS_AUTHENTICATED);\r
+                                       \r
+                               }\r
+                       }\r
+\r
+                       // if Principal is found, check for "AS_USER" and whether this entity is trusted to declare\r
+                       if(prin!=null) {\r
+                               String as_user=req.getHeader(Config.CADI_USER_CHAIN);\r
+                               if(as_user!=null) {\r
+                                       if(as_user.startsWith("TGUARD ") && lur.fish(prin, new LocalPermission("com.att.aaf.trust|"+prin.getName()+"|tguard"))) {\r
+                                               prin = new TGuardPrincipal(as_user.substring(7));\r
+                                               responseText=prin.getName() + " set via trust of " + responseText;\r
+                                       }\r
+                               }\r
+                               return new X509HttpTafResp(\r
+                                       access,\r
+                                       prin,\r
+                                       responseText,\r
+                                       RESP.IS_AUTHENTICATED);\r
+                       }\r
+               } catch(Exception e) {\r
+                       return new X509HttpTafResp(access, null, e.getMessage(), RESP.TRY_ANOTHER_TAF); \r
+               }\r
+       \r
+               return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
+       }\r
+\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTaf.java b/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTaf.java
new file mode 100644 (file)
index 0000000..88a6721
--- /dev/null
@@ -0,0 +1,371 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.dos;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Taf.LifeForm;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.PuntTafResp;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+\r
+public class DenialOfServiceTaf implements HttpTaf {\r
+       private static Map<String, Counter> deniedIP=null, deniedID=null;\r
+       private Access access;\r
+       private static File dosIP, dosID;\r
+       \r
+       /**\r
+        * \r
+        * @param hostname\r
+        * @param prod\r
+        * @throws CadiException\r
+        */\r
+       public DenialOfServiceTaf(Access access) throws CadiException {\r
+               this.access = access;\r
+               if(dosIP==null || dosID == null) {\r
+                       String dirStr;\r
+                       if((dirStr = access.getProperty("aaf_data_dir", null))!=null) {\r
+                               dosIP = new File(dirStr+"/dosIP");\r
+                               readIP();\r
+                               dosID = new File(dirStr+"/dosID");\r
+                               readID();\r
+                       }\r
+               }\r
+       }\r
+\r
+       public TafResp validate(LifeForm reading, HttpServletRequest req, final HttpServletResponse resp) {\r
+               // Performance, when not needed\r
+               if(deniedIP != null) {\r
+                       String ip;\r
+                       Counter c = deniedIP.get(ip=req.getRemoteAddr());\r
+                       if(c!=null) {\r
+                               c.inc();\r
+                               return respDenyIP(access,ip);\r
+                       }\r
+               }\r
+               \r
+               // Note:  Can't process Principal, because this is the first TAF, and no Principal is created.\r
+               // Other TAFs use "isDenied()" on this Object to validate.\r
+               return PuntTafResp.singleton();\r
+       }\r
+\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               // We always return NOT MINE, because DOS Taf does not ever validate\r
+               return Resp.NOT_MINE;\r
+       }\r
+\r
+       /*\r
+        *  for use in Other TAFs, before they attempt backend validation of \r
+        */\r
+       public static Counter isDeniedID(String identity) {\r
+               if(deniedID!=null) {\r
+                       return deniedID.get(identity);\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       /**\r
+        *  \r
+        */\r
+       public static Counter isDeniedIP(String ipvX) {\r
+               if(deniedID!=null) {\r
+                       return deniedID.get(ipvX);\r
+               }\r
+               return null;\r
+       }\r
+\r
+       /**\r
+        * Return of "True" means IP has been added.\r
+        * Return of "False" means IP already added.\r
+        * \r
+        * @param ip\r
+        * @return\r
+        */\r
+       public static synchronized boolean denyIP(String ip) {\r
+               boolean rv = false;\r
+               if(deniedIP==null) {\r
+                       deniedIP = new HashMap<String,Counter>();\r
+                       deniedIP.put(ip, new Counter(ip)); // Noted duplicated for minimum time spent\r
+                       rv= true;\r
+               } else if(deniedIP.get(ip)==null) {\r
+                       deniedIP.put(ip, new Counter(ip));\r
+                       rv = true;\r
+               }\r
+               if(rv) {\r
+                       writeIP();\r
+               }\r
+               return rv;\r
+       }\r
+       \r
+       private static void writeIP() {\r
+               if(dosIP!=null && deniedIP!=null) {\r
+                       if(deniedIP.isEmpty()) {\r
+                               if(dosIP.exists()) {\r
+                                       dosIP.delete();\r
+                               }\r
+                       } else {\r
+                               PrintStream fos;\r
+                               try {\r
+                                       fos = new PrintStream(new FileOutputStream(dosIP,false));\r
+                                       try {\r
+                                               for(String ip: deniedIP.keySet()) {\r
+                                                       fos.println(ip);\r
+                                               }\r
+                                       } finally {\r
+                                               fos.close();\r
+                                       }\r
+                               } catch (IOException e) {\r
+                                       e.printStackTrace(System.err);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private static void readIP() {\r
+               if(dosIP!=null && dosIP.exists()) {\r
+                       BufferedReader br;\r
+                       try {\r
+                               br = new BufferedReader(new FileReader(dosIP));\r
+                               if(deniedIP==null) {\r
+                                       deniedIP=new HashMap<String,Counter>();\r
+                               }\r
+\r
+                               try {\r
+                                       String line;\r
+                                       while((line=br.readLine())!=null) {\r
+                                               deniedIP.put(line, new Counter(line));\r
+                                       }\r
+                               } finally {\r
+                                       br.close();\r
+                               }\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+        * Return of "True" means IP has was removed.\r
+        * Return of "False" means IP wasn't being denied.\r
+        * \r
+        * @param ip\r
+        * @return\r
+        */\r
+       public static synchronized boolean removeDenyIP(String ip) {\r
+               if(deniedIP!=null && deniedIP.remove(ip)!=null) {\r
+                       writeIP();\r
+                       if(deniedIP.isEmpty()) {\r
+                               deniedIP=null;\r
+                       }\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       /**\r
+        * Return of "True" means ID has been added.\r
+        * Return of "False" means ID already added.\r
+        * \r
+        * @param ip\r
+        * @return\r
+        */\r
+       public static synchronized boolean denyID(String id) {\r
+               boolean rv = false;\r
+               if(deniedID==null) {\r
+                       deniedID = new HashMap<String,Counter>();\r
+                       deniedID.put(id, new Counter(id)); // Noted duplicated for minimum time spent\r
+                       rv = true;\r
+               } else if(deniedID.get(id)==null) {\r
+                       deniedID.put(id, new Counter(id));\r
+                       rv = true;\r
+               }\r
+               if(rv) {\r
+                       writeID();\r
+               }\r
+               return rv;\r
+\r
+       }\r
+\r
+       private static void writeID() {\r
+               if(dosID!=null && deniedID!=null) {\r
+                       if(deniedID.isEmpty()) {\r
+                               if(dosID.exists()) {\r
+                                       dosID.delete();\r
+                               }\r
+                       } else {\r
+                               PrintStream fos;\r
+                               try {\r
+                                       fos = new PrintStream(new FileOutputStream(dosID,false));\r
+                                       try {\r
+                                               for(String ip: deniedID.keySet()) {\r
+                                                       fos.println(ip);\r
+                                               }\r
+                                       } finally {\r
+                                               fos.close();\r
+                                       }\r
+                               } catch (IOException e) {\r
+                                       e.printStackTrace(System.err);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static void readID() {\r
+               if(dosID!=null && dosID.exists()) {\r
+                       BufferedReader br;\r
+                       try {\r
+                               br = new BufferedReader(new FileReader(dosID));\r
+                               if(deniedID==null) {\r
+                                       deniedID=new HashMap<String,Counter>();\r
+                               }\r
+                               try {\r
+                                       String line;\r
+                                       while((line=br.readLine())!=null) {\r
+                                               deniedID.put(line, new Counter(line));\r
+                                       }\r
+                               } finally {\r
+                                       br.close();\r
+                               }\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace(System.err);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Return of "True" means ID has was removed.\r
+        * Return of "False" means ID wasn't being denied.\r
+        * \r
+        * @param ip\r
+        * @return\r
+        */\r
+       public static synchronized boolean removeDenyID(String id) {\r
+               if(deniedID!=null && deniedID.remove(id)!=null) { \r
+                       writeID();\r
+                       if(deniedID.isEmpty()) {\r
+                               deniedID=null;\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       public List<String> report() {\r
+               int initSize = 0;\r
+               if(deniedIP!=null)initSize+=deniedIP.size();\r
+               if(deniedID!=null)initSize+=deniedID.size();\r
+               ArrayList<String> al = new ArrayList<String>(initSize);\r
+               if(deniedID!=null) {\r
+                       for(Counter c : deniedID.values()) {\r
+                               al.add(c.toString());\r
+                       }\r
+               }\r
+               if(deniedIP!=null) {\r
+                       for(Counter c : deniedIP.values()) {\r
+                               al.add(c.toString());\r
+                       }\r
+               }\r
+               return al;\r
+       }\r
+       \r
+       public static class Counter {\r
+               private final String name; \r
+               private int count = 0;\r
+               private Date first;\r
+               private long last; // note, we use "last" as long, to avoid popping useless dates on Heap.\r
+               \r
+               public Counter(String name) {\r
+                       this.name = name;\r
+                       first = null;\r
+                       last = 0L;\r
+                       count = 0;\r
+               }\r
+               \r
+               public String getName() {\r
+                       return name;\r
+               }\r
+               \r
+               public int getCount() {\r
+                       return count;\r
+               }\r
+\r
+               public long getLast() {\r
+                       return last;\r
+               }\r
+               \r
+               /*\r
+                * Only allow Denial of ServiceTaf to increment\r
+                */\r
+               private synchronized void inc() {\r
+                       ++count;\r
+                       last = System.currentTimeMillis();\r
+                       if(first==null) {\r
+                               first = new Date(last);\r
+                       }\r
+               }\r
+               \r
+               public String toString() {\r
+                       if(count==0) \r
+                               return name + " is on the denied list, but has not attempted Access"; \r
+                       else \r
+                               return \r
+                                       name +\r
+                                       " has been denied " +\r
+                                       count +\r
+                                       " times since " +\r
+                                       first +\r
+                                       ".  Last denial was " +\r
+                                       new Date(last);\r
+               }\r
+       }\r
+\r
+       public static TafResp respDenyID(Access access, String identity) {\r
+               return new DenialOfServiceTafResp(access, RESP.NO_FURTHER_PROCESSING, identity + " is on the Identity Denial list");\r
+       }\r
+       \r
+       public static TafResp respDenyIP(Access access, String ip) {\r
+               return new DenialOfServiceTafResp(access, RESP.NO_FURTHER_PROCESSING, ip + " is on the IP Denial list");\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTafResp.java b/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTafResp.java
new file mode 100644 (file)
index 0000000..7cbbf73
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.dos;\r
+\r
+import java.io.IOException;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.taf.AbsTafResp;\r
+\r
+public class DenialOfServiceTafResp extends AbsTafResp  {\r
+       private RESP ect;  // Homage to Arethra Franklin\r
+\r
+       public DenialOfServiceTafResp(Access access, RESP resp, String description ) {\r
+               super(access, null, description);\r
+               ect = resp;\r
+       }\r
+\r
+       // Override base behavior of checking Principal and trying another TAF\r
+       @Override\r
+       public RESP isAuthenticated() {\r
+               return ect;\r
+       }\r
+       \r
+\r
+       public RESP authenticate() throws IOException {\r
+               return ect;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTaf.java b/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTaf.java
new file mode 100644 (file)
index 0000000..89500a6
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.localhost;\r
+\r
+import java.net.InetAddress;\r
+import java.net.NetworkInterface;\r
+import java.net.SocketException;\r
+import java.net.UnknownHostException;\r
+import java.util.Enumeration;\r
+import java.util.TreeSet;\r
+\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Access.Level;\r
+import com.att.cadi.CachedPrincipal;\r
+import com.att.cadi.CachedPrincipal.Resp;\r
+import com.att.cadi.Taf;\r
+import com.att.cadi.taf.HttpTaf;\r
+import com.att.cadi.taf.TafResp;\r
+import com.att.cadi.taf.TafResp.RESP;\r
+\r
+/**\r
+ * Implement the ability to utilize LocalHost as a TAF.\r
+ * \r
+ * Configure with two properties, \r
+ *     localhost.deny\r
+ *  localhost.accept\r
+ *  \r
+ * 1) If localhost.deny==true, then no localhost requests are allowed\r
+ * 2) If localhost.deny==false, but accept==false, return "Try Another TAF" (i.e. allow further checking of the\r
+ *   chain, but don't treat localhost as an acceptable credential)\r
+ * 3) If localhost.deny=false and accept=true, then the processes coming from the same machine, given logins are needed, \r
+ * to run, are treated as validated.  This is primarily for Developer purposes.\r
+ *   \r
+ * \r
+ *\r
+ */\r
+public class LocalhostTaf implements HttpTaf {\r
+       private TafResp isLocalHost,isNotLocalHost;\r
+       private static final TreeSet<String> addrSet;\r
+       \r
+       static {\r
+               addrSet = new TreeSet<String>();\r
+               try {\r
+                       for(Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();en.hasMoreElements();) {\r
+                               NetworkInterface ni = en.nextElement();\r
+                               for(Enumeration<InetAddress> eia = ni.getInetAddresses();eia.hasMoreElements();) {\r
+                                       InetAddress ia = eia.nextElement();\r
+                                       addrSet.add(ia.getHostAddress());\r
+                               }\r
+                       }\r
+               } catch (SocketException e) {\r
+               }\r
+               \r
+       }\r
+\r
+       public LocalhostTaf(Access access, boolean accept, boolean isDenied) {\r
+               String hostname = access.getProperty("hostname",null);\r
+               if(hostname !=null) {\r
+                       try {\r
+                               addrSet.add(InetAddress.getByName(hostname).getHostAddress());\r
+                       } catch (UnknownHostException e) {\r
+                               access.log(e,"Unknown Host");\r
+                       }\r
+               }\r
+               \r
+               if(isDenied) {\r
+                       access.log(Level.INFO,"LocalhostTaf will deny all localhost traffic");\r
+               } else {\r
+                       access.log(Level.INFO,"LocalhostTaf will not deny localhost requests, ",\r
+                                       (accept?"and will treat them as authenticated":"but will require other authentication"));\r
+               }\r
+               // Set the appropriate behavior for when ID coming in is from localhost\r
+               isLocalHost = isDenied? \r
+                       new LocalhostTafResp(access, RESP.NO_FURTHER_PROCESSING,"Localhost is denied"):\r
+                       accept?\r
+                               new LocalhostTafResp(access, RESP.IS_AUTHENTICATED,"Localhost is allowed"):\r
+                               new LocalhostTafResp(access, RESP.TRY_ANOTHER_TAF,"Localhost is allowed");\r
+               isNotLocalHost = new LocalhostTafResp(access, RESP.TRY_ANOTHER_TAF,"Address is not Localhost");\r
+       }\r
+\r
+//     @Override\r
+       public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
+               String remote = req.getRemoteAddr();\r
+               return addrSet.contains(remote)\r
+                       ?isLocalHost\r
+                       :isNotLocalHost;\r
+       }\r
+\r
+       /** \r
+        * This function used for other TAFs (i.e. CSP, which can't work on localhost address)\r
+        * \r
+        * @param address\r
+        * @return\r
+        */\r
+       public static boolean isLocalAddress(String address) {\r
+               return addrSet.contains(address);\r
+       }\r
+       \r
+       public String toString() {\r
+               return "Localhost TAF activated: " + isLocalHost.desc();\r
+       }\r
+\r
+       public Resp revalidate(CachedPrincipal prin) {\r
+               // shouldn't get here, since there's no need to Cache, but if so, LocalHost is always valid...\r
+               return Resp.REVALIDATED;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTafResp.java b/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTafResp.java
new file mode 100644 (file)
index 0000000..29ddf92
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.taf.localhost;\r
+\r
+import java.security.Principal;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.taf.TafResp;\r
+\r
+public class LocalhostTafResp implements TafResp {\r
+       private RESP action;\r
+       private String description;\r
+       private final static Principal principal = new Principal() {\r
+               private String name = System.getProperty("user.name")+"@localhost";\r
+//             @Override\r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       };\r
+\r
+       private Access access;\r
+       \r
+       public LocalhostTafResp(Access access, RESP state, String desc) {\r
+               action = state;\r
+               description = desc;\r
+               this.access = access;\r
+       }\r
+       \r
+//     @Override\r
+       public boolean isValid() {\r
+               return action == RESP.IS_AUTHENTICATED;\r
+       }\r
+\r
+//     @Override\r
+       public String desc() {\r
+               return description;\r
+       }\r
+\r
+//     @Override\r
+       public RESP authenticate() {\r
+               return action;\r
+       }\r
+       \r
+       public RESP isAuthenticated() {\r
+               return action;\r
+       }\r
+\r
+//     @Override\r
+       public Principal getPrincipal() {\r
+               return principal;\r
+       }\r
+\r
+       public Access getAccess() {\r
+               return access;\r
+       }\r
+\r
+       public boolean isFailedAttempt() {\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/Chmod.java b/core/src/main/java/com/att/cadi/util/Chmod.java
new file mode 100644 (file)
index 0000000..9991616
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+\r
+public interface Chmod {\r
+       public void chmod(File f) throws IOException;\r
+       \r
+       public static final Chmod to755 = new Chmod() {\r
+               public void chmod(File f) throws IOException {\r
+                       f.setExecutable(true, false);\r
+                       f.setExecutable(true, true);\r
+                       f.setReadable(true, false);\r
+                       f.setReadable(true, true);\r
+                       f.setWritable(false, false);\r
+                       f.setWritable(true, true);\r
+               }\r
+       };\r
+\r
+       public static final Chmod to644 = new Chmod() {\r
+               public void chmod(File f) throws IOException {\r
+                       f.setExecutable(false, false);\r
+                       f.setExecutable(false, true);\r
+                       f.setReadable(true, false);\r
+                       f.setReadable(true, true);\r
+                       f.setWritable(false, false);\r
+                       f.setWritable(true, true);\r
+               }\r
+       };\r
+\r
+       public static final Chmod to400 = new Chmod() {\r
+               public void chmod(File f) throws IOException {\r
+                       f.setExecutable(false, false);\r
+                       f.setExecutable(false, true);\r
+                       f.setReadable(false, false);\r
+                       f.setReadable(true, true);\r
+                       f.setWritable(false, false);\r
+                       f.setWritable(false, true);\r
+               }\r
+       };\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/JsonOutputStream.java b/core/src/main/java/com/att/cadi/util/JsonOutputStream.java
new file mode 100644 (file)
index 0000000..f85efa4
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+public class JsonOutputStream extends OutputStream {\r
+       private static final byte[] TWO_SPACE = "  ".getBytes();\r
+       private OutputStream os;\r
+       private boolean closeable;\r
+       private int indent = 0;\r
+       private int prev,ret=0;\r
+\r
+       public JsonOutputStream(OutputStream os) {\r
+               // Don't close these, or dire consequences.\r
+               closeable = !os.equals(System.out) && !os.equals(System.err);\r
+               this.os = os;\r
+       }\r
+\r
+       @Override\r
+       public void write(int b) throws IOException {\r
+               if(ret=='\n') {\r
+                       ret = 0;\r
+                       if(prev!=',' || (b!='{' && b!='[')) {\r
+                               os.write('\n');\r
+                               for(int i=0;i<indent;++i) {\r
+                                       os.write(TWO_SPACE);\r
+                               }\r
+                       }\r
+               }\r
+               switch(b) {\r
+                       case '{':\r
+                       case '[':       \r
+                                       ret = '\n';\r
+                                       ++indent;\r
+                                       break;\r
+                       case '}':\r
+                       case ']': \r
+                                       --indent;\r
+                                       os.write('\n');\r
+                                       for(int i=0;i<indent;++i) {\r
+                                               os.write(TWO_SPACE);\r
+                                       }\r
+                                       break;\r
+                       case ',':\r
+                                       ret = '\n';\r
+                                       break;\r
+                                       \r
+               }\r
+               os.write(b);\r
+               prev = b;\r
+       }\r
+       public void resetIndent() {\r
+               indent = 1;\r
+       }\r
+\r
+       @Override\r
+       public void flush() throws IOException {\r
+               os.flush();\r
+       }\r
+\r
+       @Override\r
+       public void close() throws IOException {\r
+               if(closeable) {\r
+                       os.close();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/MaskFormatException.java b/core/src/main/java/com/att/cadi/util/MaskFormatException.java
new file mode 100644 (file)
index 0000000..7a8c773
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+@SuppressWarnings("serial")\r
+public class MaskFormatException extends Exception {\r
+\r
+       public MaskFormatException(String string) {\r
+                       super(string);\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/MyConsole.java b/core/src/main/java/com/att/cadi/util/MyConsole.java
new file mode 100644 (file)
index 0000000..eb148ee
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+public interface MyConsole {\r
+       public String readLine(String fmt, Object ... args);\r
+       public char[] readPassword(String fmt, Object ... args);\r
+       public void printf(String fmt, Object ...args);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/NetMask.java b/core/src/main/java/com/att/cadi/util/NetMask.java
new file mode 100644 (file)
index 0000000..befed88
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+/* \r
+ * NetMask - a class to quickly validate whether a given IP is part of a mask, as defined by bytes or standard String format.\r
+ * \r
+ * Needs the IPV6 Mask Builder. \r
+ */\r
+public class NetMask {\r
+       private long mask;\r
+\r
+       public NetMask(byte[] inBytes) {\r
+               mask = derive(inBytes);\r
+       }\r
+       \r
+       public NetMask(String string) throws MaskFormatException {\r
+               mask = derive(string,true);\r
+       }\r
+       \r
+       public boolean isInNet(byte[] inBytes) {\r
+               long addr = derive(inBytes);\r
+               return (mask & addr) == addr;\r
+       }\r
+       \r
+       public boolean isInNet(String str) {\r
+               long addr;\r
+               try {\r
+                       addr = derive(str,false);\r
+                       return (mask & addr) == addr;\r
+               } catch (MaskFormatException e) {\r
+                       // will not hit this code;\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       public static long derive(byte[] inBytes) {\r
+               long addr = 0L;\r
+               int offset = inBytes.length*8;\r
+               for(int i=0;i<inBytes.length;++i) {\r
+                       addr&=(inBytes[i]<<offset);\r
+                       offset-=8;\r
+               }\r
+               return addr;\r
+       }\r
+\r
+       public static long derive(String str, boolean check) throws MaskFormatException {\r
+               long rv=0L;\r
+               int idx=str.indexOf(':');\r
+               int slash = str.indexOf('/');\r
+\r
+               if(idx<0) { // Not IPV6, so it's IPV4... Is there a mask of 123/254?\r
+                       idx=str.indexOf('.');\r
+                       int offset = 24;\r
+                       int end = slash>=0?slash:str.length();\r
+                       int bits = slash>=0?Integer.parseInt(str.substring(slash+1)):32;\r
+                       if(check && bits>32) {\r
+                               throw new MaskFormatException("Invalid Mask Offset in IPV4 Address");\r
+                       }\r
+                       int prev = 0;\r
+                       long lbyte;\r
+                       while(prev<end) {\r
+                               if(idx<0) {\r
+                                       idx = end;\r
+                               }\r
+                               lbyte = Long.parseLong(str.substring(prev, idx));\r
+                               if(check && (lbyte>255 || lbyte<0)) {\r
+                                       throw new MaskFormatException("Invalid Byte in IPV4 Address");\r
+                               }\r
+                               rv|=lbyte<<offset;\r
+                               prev = ++idx;\r
+                               idx=str.indexOf('.',prev);\r
+                               offset-=8;\r
+                       }\r
+                       rv|=0x00000000FFFFFFFFL>>bits;\r
+               }\r
+               return rv;\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/Split.java b/core/src/main/java/com/att/cadi/util/Split.java
new file mode 100644 (file)
index 0000000..4a695fb
--- /dev/null
@@ -0,0 +1,92 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+/**\r
+ * Split by Char, optional Trim\r
+ *\r
+ * Note: Copied from Inno to avoid linking issues.\r
+ * Note: I read the String split and Pattern split code, and we can do this more efficiently for a single Character\r
+ * \r
+ * 8/20/2015\r
+ */\r
+\r
+public class Split {\r
+         public static String[] split(char c, String value) {\r
+                 // Count items to preallocate Array (memory alloc is more expensive than counting twice)\r
+                 int count,idx;\r
+                 for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);\r
+                 String[] rv = new String[count];\r
+                 if(count==1) {\r
+                         rv[0]=value;\r
+                 } else {\r
+                         int last=0;\r
+                         count=-1;\r
+                         for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {\r
+                                 rv[++count]=value.substring(last,idx);\r
+                                 last = ++idx;\r
+                         }\r
+                         rv[++count]=value.substring(last);\r
+                 }\r
+                 return rv;\r
+         }\r
+\r
+         public static String[] splitTrim(char c, String value) {\r
+                 // Count items to preallocate Array (memory alloc is more expensive than counting twice)\r
+                 int count,idx;\r
+                 for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);\r
+                 String[] rv = new String[count];\r
+                 if(count==1) {\r
+                         rv[0]=value.trim();\r
+                 } else {\r
+                         int last=0;\r
+                         count=-1;\r
+                         for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {\r
+                                 rv[++count]=value.substring(last,idx).trim();\r
+                                 last = ++idx;\r
+                         }\r
+                         rv[++count]=value.substring(last).trim();\r
+                 }\r
+                 return rv;\r
+         }\r
+\r
+         public static String[] splitTrim(char c, String value, int size) {\r
+                 int idx;\r
+                 String[] rv = new String[size];\r
+                 if(size==1) {\r
+                         rv[0]=value.trim();\r
+                 } else {\r
+                         int last=0;\r
+                         int count=-1;\r
+                         size-=2;\r
+                         for(idx=value.indexOf(c);idx>=0 && count<size;idx=value.indexOf(c,idx)) {\r
+                                 rv[++count]=value.substring(last,idx).trim();\r
+                                 last = ++idx;\r
+                         }\r
+                         rv[++count]=value.substring(last).trim();\r
+                 }\r
+                 return rv;\r
+         }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/SubStandardConsole.java b/core/src/main/java/com/att/cadi/util/SubStandardConsole.java
new file mode 100644 (file)
index 0000000..3d57332
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.IOException;\r
+import java.io.InputStreamReader;\r
+\r
+// Substandard, because System.in doesn't do Passwords..\r
+public class SubStandardConsole implements MyConsole {\r
+       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));\r
+       @Override\r
+       public String readLine(String fmt, Object... args) {\r
+               String rv;\r
+               try {\r
+                       System.out.printf(fmt,args);\r
+                       rv = br.readLine();\r
+                       if(args.length==1 && rv.length()==0) {\r
+                               rv = args[0].toString();\r
+                       }\r
+               } catch (IOException e) {\r
+                       System.err.println("uh oh...");\r
+                       rv = "";\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       @Override\r
+       public char[] readPassword(String fmt, Object... args) {\r
+               try {\r
+                       System.out.printf(fmt,args);\r
+                       return br.readLine().toCharArray();\r
+               } catch (IOException e) {\r
+                       System.err.println("uh oh...");\r
+                       return new char[0];\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void printf(String fmt, Object... args) {\r
+               System.out.printf(fmt, args);\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/TheConsole.java b/core/src/main/java/com/att/cadi/util/TheConsole.java
new file mode 100644 (file)
index 0000000..60f3f79
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+public class TheConsole implements MyConsole {\r
+       @Override\r
+       public String readLine(String fmt, Object... args) {\r
+               String rv = System.console().readLine(fmt, args);\r
+               if(args.length>0 && args[0]!=null && rv.length()==0) {\r
+                       rv = args[0].toString();\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       @Override\r
+       public char[] readPassword(String fmt, Object... args) {\r
+               return System.console().readPassword(fmt, args);\r
+       }\r
+       \r
+       public static boolean implemented() {\r
+               return System.console()!=null;\r
+       }\r
+\r
+       @Override\r
+       public void printf(String fmt, Object... args) {\r
+               System.console().printf(fmt, args);\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/UserChainManip.java b/core/src/main/java/com/att/cadi/util/UserChainManip.java
new file mode 100644 (file)
index 0000000..89851aa
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+import com.att.cadi.UserChain;\r
+\r
+public class UserChainManip {\r
+       /** \r
+           Build an element in the correct format for UserChain.\r
+               Format:<APP>:<ID>:<protocol>[:AS][,<APP>:<ID>:<protocol>]*\r
+               @see UserChain\r
+       */ \r
+       public static StringBuilder build(StringBuilder sb, String app, String id, UserChain.Protocol proto, boolean as) {\r
+               boolean mayAs;\r
+               if(!(mayAs=sb.length()==0)) {\r
+                       sb.append(',');\r
+               }\r
+               sb.append(app);\r
+               sb.append(':');\r
+               sb.append(id);\r
+               sb.append(':');\r
+               sb.append(proto.name());\r
+               if(as && mayAs) {\r
+                       sb.append(":AS");\r
+               }\r
+               return sb;\r
+       }\r
+       \r
+       public static String idToNS(String id) {\r
+               if(id==null) {\r
+                       return "";\r
+               } else {\r
+                       StringBuilder sb = new StringBuilder();\r
+                       char c;\r
+                       int end;\r
+                       boolean first = true;\r
+                       for(int idx = end = id.length()-1;idx>=0;--idx) {\r
+                               if((c = id.charAt(idx))=='@' || c=='.')  {\r
+                                       if(idx<end) {\r
+                                               if(first) {\r
+                                                       first = false;\r
+                                               } else {\r
+                                                       sb.append('.');\r
+                                               }\r
+                                               for(int i=idx+1;i<=end;++i) {\r
+                                                       sb.append(id.charAt(i));\r
+                                               }\r
+                                       }\r
+                                       end=idx-1;\r
+                                       if(c=='@') {\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       return sb.toString();\r
+               }\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/util/Vars.java b/core/src/main/java/com/att/cadi/util/Vars.java
new file mode 100644 (file)
index 0000000..b712e31
--- /dev/null
@@ -0,0 +1,122 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.util;\r
+\r
+import java.util.List;\r
+\r
+public class Vars {\r
+       /**\r
+        * Simplified Conversion based on typical use of getting AT&T style RESTful Error Messages\r
+        * @param text\r
+        * @param vars\r
+        * @return\r
+        */\r
+       public static String convert(final String text, final List<String> vars) {\r
+               String[] array = new String[vars.size()];\r
+               StringBuilder sb = new StringBuilder();\r
+               convert(sb,text,vars.toArray(array));\r
+               return sb.toString();\r
+       }\r
+       /**\r
+        * Convert a format string with "%s" into AT&T RESTful Error %1 %2 (number) format\r
+        * If "holder" is passed in, it is built with full Message extracted (typically for Logging)\r
+        * @param holder\r
+        * @param text\r
+        * @param vars\r
+        * @return\r
+        */\r
+       public static String convert(final StringBuilder holder, final String text, final String ... vars) {\r
+               StringBuilder sb = null;\r
+               int idx,index=0,prev = 0;\r
+               \r
+               if(text.contains("%s")) {\r
+                       sb = new StringBuilder();\r
+               }\r
+               \r
+               StringBuilder[] sbs = new StringBuilder[] {sb,holder};\r
+               boolean replace, clearIndex = false;\r
+               int c;\r
+               while((idx=text.indexOf('%',prev))>=0) {\r
+                       replace = false;\r
+                       if(clearIndex) {\r
+                               index=0;\r
+                       }\r
+                       if(sb!=null) {\r
+                               sb.append(text,prev,idx);\r
+                       }\r
+                       if(holder!=null) {\r
+                               holder.append(text,prev,idx);\r
+                       }\r
+                       \r
+                       boolean go = true;\r
+                       while(go) {\r
+                               if(text.length()>++idx) {\r
+                                       switch(c=text.charAt(idx)) {\r
+                                               case '0': case '1': case '2': case '3': case '4': \r
+                                               case '5': case '6': case '7': case '8': case '9':\r
+                                                       index *=10;\r
+                                                       index +=(c-'0');\r
+                                                       clearIndex=replace=true;\r
+                                                       continue;\r
+                                               case 's':\r
+                                                       ++index;\r
+                                                       replace = true;\r
+                                                       continue;\r
+                                               default:\r
+                                                       break;\r
+                                       }\r
+                               }\r
+                               prev = idx;\r
+                               go=false;\r
+                               if(replace) {\r
+                                       if(sb!=null) {\r
+                                               sb.append('%');\r
+                                               sb.append(index);\r
+                                       }\r
+                                       if(index<=vars.length) {\r
+                                               if(holder!=null) {\r
+                                                       holder.append(vars[index-1]);\r
+                                               }\r
+                                       }\r
+                               } else {\r
+                                       for(StringBuilder s : sbs) {\r
+                                               if(s!=null) {\r
+                                                       s.append("%");\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               if(sb!=null) {\r
+                       sb.append(text,prev,text.length());\r
+               }\r
+               if(holder!=null) {\r
+                       holder.append(text,prev,text.length());\r
+               }\r
+\r
+               return sb==null?text:sb.toString();\r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/wsse/Action.java b/core/src/main/java/com/att/cadi/wsse/Action.java
new file mode 100644 (file)
index 0000000..a9b171c
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse;\r
+\r
+/**\r
+ * Interface to specify an action deep within a parsing tree on a local object\r
+ * \r
+ * We use a Generic so as to be flexible on create what that object actually is.  This is passed in at the\r
+ * root "parse" call of Match.  Similar to a "Visitor" Pattern, this object is passed upon reaching the right\r
+ * point in a parse tree.\r
+ * \r
+ *\r
+ * @param <OUTPUT>\r
+ */\r
+interface Action<OUTPUT> {\r
+       public boolean content(OUTPUT output, String text);\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/wsse/Match.java b/core/src/main/java/com/att/cadi/wsse/Match.java
new file mode 100644 (file)
index 0000000..657976a
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse;\r
+\r
+import javax.xml.namespace.QName;\r
+import javax.xml.stream.XMLStreamException;\r
+import javax.xml.stream.events.XMLEvent;\r
+\r
+/**\r
+ * Match Class allows you to build an automatic Tree of StAX (or StAX like) \r
+ * Objects for frequent use.\r
+ * \r
+ * OBJECT is a type which you which to do some end Actions on, similar to a Visitor pattern, see Action\r
+ * \r
+ * Note: We have implemented with XReader and XEvent, rather than StAX for performance reasons.\r
+ * \r
+ * @see Action\r
+ * @see Match\r
+ * @see XEvent\r
+ * @see XReader\r
+ * \r
+ *\r
+ * @param <OUTPUT>\r
+ */\r
+//@SuppressWarnings("restriction")\r
+public class Match<OUTPUT> {\r
+       private QName qname;\r
+       private Match<OUTPUT>[] next;\r
+       private Match<OUTPUT> prev;\r
+       private Action<OUTPUT> action = null;\r
+       private boolean stopAfter;\r
+       private boolean exclusive;\r
+       \r
+\r
+       @SafeVarargs\r
+       public Match(String ns, String name, Match<OUTPUT> ... next) {\r
+               this.qname = new QName(ns,name);\r
+               this.next = next;\r
+               stopAfter = exclusive = false;\r
+               for(Match<OUTPUT> m : next) { // add the possible tags to look for\r
+                       if(!m.stopAfter)m.prev = this;\r
+               }\r
+       }\r
+       \r
+       public Match<OUTPUT> onMatch(OUTPUT output, XReader reader) throws XMLStreamException {\r
+               while(reader.hasNext()) {\r
+                       XEvent event = reader.nextEvent();\r
+                       switch(event.getEventType()) {\r
+                               case XMLEvent.START_ELEMENT:\r
+                                       QName e_qname = event.asStartElement().getName();\r
+                                       //System.out.println("Start - " + e_qname);\r
+                                       boolean match = false;\r
+                                       for(Match<OUTPUT> m : next) {\r
+                                               if(e_qname.equals(m.qname)) {\r
+                                                       match=true;\r
+                                                       if(m.onMatch(output, reader)==null) {\r
+                                                               return null; // short circuit Parsing\r
+                                                       }\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       if(exclusive && !match) // When Tag MUST be present, i.e. the Root Tag, versus info we're not interested in\r
+                                               return null;\r
+                                       break;\r
+                               case XMLEvent.CHARACTERS:\r
+                                       //System.out.println("Data - " +event.asCharacters().getData());\r
+                                       if(action!=null) {\r
+                                               if(!action.content(output,event.asCharacters().getData())) {\r
+                                                       return null;\r
+                                               }\r
+                                       }\r
+                                       break;\r
+                               case XMLEvent.END_ELEMENT:\r
+                                       //System.out.println("End - " + event.asEndElement().getName());\r
+                                       if(event.asEndElement().getName().equals(qname)) {\r
+                                               return prev;\r
+                                       }\r
+                                       break;\r
+                               case XMLEvent.END_DOCUMENT:\r
+                                       return null; // Exit Chain\r
+                       }\r
+               }\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * When this Matched Tag has completed, Stop parsing and end\r
+        * @return\r
+        */\r
+       public Match<OUTPUT> stopAfter() {\r
+               stopAfter = true;\r
+               return this;\r
+       }\r
+       \r
+       /**\r
+        * Mark that this Object MUST be matched at this level or stop parsing and end\r
+        * \r
+        * @param action\r
+        * @return\r
+        */\r
+       public Match<OUTPUT> exclusive() {\r
+               exclusive = true;\r
+               return this;\r
+       }\r
+\r
+       public Match<OUTPUT> set(Action<OUTPUT> action) {\r
+               this.action = action;\r
+               return this;\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/wsse/WSSEParser.java b/core/src/main/java/com/att/cadi/wsse/WSSEParser.java
new file mode 100644 (file)
index 0000000..dd8af4d
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import javax.xml.stream.XMLStreamException;\r
+\r
+import com.att.cadi.BasicCred;\r
+\r
+\r
+/**\r
+ * WSSE Parser\r
+ * \r
+ * Read the User and Password from WSSE Formatted SOAP Messages \r
+ * \r
+ * This class uses StAX so that processing is stopped as soon as the Security User/Password are read into BasicCred, or the Header Ends\r
+ * \r
+ * This class is intended to be created once (or very few times) and reused as much as possible.\r
+ * \r
+ * It is as thread safe as StAX parsing is.\r
+ * \r
+ */\r
+public class WSSEParser {\r
+       private static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/";\r
+       private static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";\r
+       private Match<BasicCred> parseTree;\r
+       //private XMLInputFactory inputFactory;\r
+\r
+       public WSSEParser() {\r
+               // soap:Envelope/soap:Header/wsse:Security/wsse:UsernameToken/[wsse:Password&wsse:Username]\r
+               parseTree = new Match<BasicCred>(SOAP_NS,"root", // need a root level to start from... Doesn't matter what the tag is\r
+                       new Match<BasicCred>(SOAP_NS,"Envelope",\r
+                               new Match<BasicCred>(SOAP_NS,"Header",\r
+                                       new Match<BasicCred>(WSSE_NS,"Security",\r
+                                               new Match<BasicCred>(WSSE_NS,"UsernameToken",\r
+                                                       new Match<BasicCred>(WSSE_NS,"Password").set(new Action<BasicCred>() {\r
+                                                               public boolean content(BasicCred bc,String text) {\r
+                                                                       bc.setCred(text.getBytes());\r
+                                                                       return true;\r
+                                                               }\r
+                                                       }),\r
+                                                       new Match<BasicCred>(WSSE_NS,"Username").set(new Action<BasicCred>() {\r
+                                                               public boolean content(BasicCred bc,String text) {\r
+                                                                       bc.setUser(text);\r
+                                                                       return true;\r
+                                                               }\r
+                                                       })\r
+                                               ).stopAfter() // if found, end when UsernameToken ends (no further processing needed)\r
+                                       )\r
+                               ).stopAfter() // Stop Processing when Header Ends\r
+                       ).exclusive()// Envelope must match Header, and no other.  FYI, Body comes after Header short circuits (see above), so it's ok\r
+               ).exclusive(); // root must be Envelope\r
+               //inputFactory = XMLInputFactory.newInstance();\r
+       }\r
+       \r
+       public XMLStreamException parse(BasicCred bc, InputStream is) throws IOException {\r
+               try {\r
+                       parseTree.onMatch(bc, new XReader(is));\r
+                       return null;\r
+               } catch (XMLStreamException e) {\r
+                       return e;\r
+               }\r
+       }\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/wsse/XEvent.java b/core/src/main/java/com/att/cadi/wsse/XEvent.java
new file mode 100644 (file)
index 0000000..d023519
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse;\r
+\r
+import javax.xml.namespace.QName;\r
+import javax.xml.stream.events.XMLEvent;\r
+\r
+/**\r
+ * XEvent\r
+ * \r
+ * This mechanism mimics a minimal portion of StAX "XMLEvent", enough to work with minimal XReader.\r
+ * \r
+ * We implement the same interface, as much as minimally necessary, as XMLEvent for these small usages so as to\r
+ * be interchangeable in the future, if so desired\r
+ * \r
+ *\r
+ */\r
+// @SuppressWarnings("restriction")\r
+public abstract class XEvent {\r
+\r
+       public abstract int getEventType();\r
+\r
+       public StartElement asStartElement() {\r
+               return (StartElement)this;\r
+       }\r
+\r
+       public Characters asCharacters() {\r
+               return (Characters)this;\r
+       }\r
+\r
+       public EndElement asEndElement() {\r
+               return (EndElement)this;\r
+       }\r
+\r
+    public static abstract class NamedXEvent extends XEvent {\r
+       private QName qname;\r
+\r
+       public NamedXEvent(QName qname) {\r
+               this.qname = qname;\r
+       }\r
+       \r
+               public QName getName() {\r
+               return qname;\r
+       }\r
+    }\r
+       public static class StartElement extends NamedXEvent {\r
+\r
+               public StartElement(String ns, String tag) {\r
+                       super(new QName(ns,tag));\r
+               }\r
+\r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.START_ELEMENT;\r
+               }\r
+       }\r
+\r
+       public static class EndElement extends NamedXEvent {\r
+               public EndElement(String ns, String tag) {\r
+                       super(new QName(ns,tag));\r
+               }\r
+               \r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.END_ELEMENT;\r
+               }\r
+       }\r
+\r
+       public static class Characters extends XEvent {\r
+               private String data;\r
+\r
+               public Characters(String data) {\r
+                       this.data = data;\r
+               }\r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.CHARACTERS;\r
+               }\r
+\r
+               public String getData() {\r
+                       return data;\r
+               }\r
+       }\r
+       \r
+       public static class StartDocument extends XEvent {\r
+\r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.START_DOCUMENT;\r
+               }\r
+               \r
+       }\r
+\r
+       public static class EndDocument extends XEvent {\r
+\r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.END_DOCUMENT;\r
+               }\r
+               \r
+       }\r
+       public static class Comment extends XEvent {\r
+               public final String value;\r
+               public Comment(String value) {\r
+                       this.value = value;\r
+               }\r
+\r
+               @Override\r
+               public int getEventType() {\r
+                       return XMLEvent.COMMENT;\r
+               }\r
+       \r
+       }\r
+\r
+}\r
diff --git a/core/src/main/java/com/att/cadi/wsse/XReader.java b/core/src/main/java/com/att/cadi/wsse/XReader.java
new file mode 100644 (file)
index 0000000..135b28c
--- /dev/null
@@ -0,0 +1,417 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Stack;\r
+\r
+import javax.xml.stream.XMLStreamException;\r
+\r
+/**\r
+ * XReader\r
+ * This class works similarly as StAX, except StAX has more behavior than is needed.  That would be ok, but \r
+ * StAX also was Buffering in their code in such as way as to read most if not all the incoming stream into memory,\r
+ * defeating the purpose of pre-reading only the Header\r
+ * \r
+ * This Reader does no back-tracking, but is able to create events based on syntax and given state only, leaving the\r
+ * Read-ahead mode of the InputStream up to the other classes.\r
+ * \r
+ * At this time, we only implement the important events, though if this is good enough, it could be expanded, perhaps to \r
+ * replace the original XMLReader from StAX.\r
+ * \r
+ *\r
+ */\r
+// @SuppressWarnings("restriction")\r
+public class XReader {\r
+       private XEvent curr,another;\r
+       private InputStream is;\r
+       private ByteArrayOutputStream baos;\r
+       private int state, count, last;\r
+       \r
+       private Stack<Map<String,String>> nsses;\r
+       \r
+       public XReader(InputStream is) {\r
+               this.is = is;\r
+               curr = another = null;\r
+               baos = new ByteArrayOutputStream();\r
+               state = BEGIN_DOC; \r
+               count = 0;\r
+               nsses = new Stack<Map<String,String>>();\r
+       }\r
+       \r
+       public boolean hasNext() throws XMLStreamException {\r
+               if(curr==null) {\r
+                       curr = parse();\r
+               }\r
+               return curr!=null;\r
+       }\r
+\r
+       public XEvent nextEvent() {\r
+               XEvent xe = curr;\r
+               curr = null;\r
+               return xe;\r
+       }\r
+\r
+       // \r
+       // State Flags\r
+       //\r
+       // Note: The State of parsing XML can be complicated.  There are too many to cleanly keep in "booleans".  Additionally,\r
+       // there are certain checks that can be better made with Bitwise operations within switches\r
+       // Keeping track of state this way also helps us to accomplish logic without storing any back characters except one\r
+       private final static int BEGIN_DOC=  0x000001;\r
+       private final static int DOC_TYPE=   0x000002;\r
+       private final static int QUESTION_F= 0x000004;\r
+       private final static int QUESTION =  0x000008;\r
+       private final static int START_TAG = 0x000010;\r
+       private final static int END_TAG =       0x000020;\r
+       private final static int VALUE=          0x000040;\r
+       private final static int COMMENT =   0x001000;\r
+       private final static int COMMENT_E = 0x002000;\r
+       private final static int COMMENT_D1 =0x010000;\r
+       private final static int COMMENT_D2 =0x020000;\r
+       private final static int COMMENT_D3 =0x040000;\r
+       private final static int COMMENT_D4 =0x080000;\r
+       // useful combined Comment states\r
+       private final static int IN_COMMENT=COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2;\r
+       private final static int COMPLETE_COMMENT = COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3|COMMENT_D4;\r
+       \r
+       \r
+       private XEvent parse() throws XMLStreamException {\r
+               Map<String,String> nss = nsses.isEmpty()?null:nsses.peek();\r
+\r
+               XEvent rv;\r
+               if((rv=another)!=null) { // "another" is a tag that may have needed to be created, but not \r
+                                                                // immediately returned.  Save for next parse.  If necessary, this could be turned into\r
+                                                                // a FIFO storage, but a single reference is enough for now.\r
+                       another = null;      // "rv" is now set for the Event, and will be returned.  Set to Null.\r
+               } else {\r
+                       boolean go = true;\r
+                       int c=0;\r
+                       \r
+                       try {\r
+                               while(go && (c=is.read())>=0) {\r
+                                       ++count;\r
+                                       switch(c) {\r
+                                               case '<': // Tag is opening\r
+                                                       state|=~BEGIN_DOC; // remove BEGIN_DOC flag, this is possibly an XML Doc\r
+                                                       XEvent cxe = null;\r
+                                                       if(baos.size()>0) { // If there are any characters between tags, we send as Character Event\r
+                                                               String chars = baos.toString().trim();  // Trim out WhiteSpace before and after\r
+                                                               if(chars.length()>0) { // don't send if Characters were only whitespace\r
+                                                                       cxe = new XEvent.Characters(chars);\r
+                                                                       baos.reset();\r
+                                                                       go = false;\r
+                                                               }\r
+                                                       }\r
+                                                       last = c;  // make sure "last" character is set for use in "ParseTag"\r
+                                                       Tag t = parseTag(); // call subroutine to process the tag as a unit\r
+                                                       String ns;\r
+                                                       switch(t.state&(START_TAG|END_TAG)) {\r
+                                                               case START_TAG:\r
+                                                                               nss = getNss(nss,t);                    // Only Start Tags might have NS Attributes   \r
+                                                                                                                                               // Get any NameSpace elements from tag.  If there are, nss will become \r
+                                                                                                                                               // a new Map with all the previous NSs plus the new.  This provides \r
+                                                                                                                                               // scoping behavior when used with the Stack\r
+                                                                       // drop through on purpose\r
+                                                               case END_TAG:\r
+                                                                       ns = t.prefix==null?"":nss.get(t.prefix); // Get the namespace from prefix (if exists)\r
+                                                                       break;\r
+                                                               default:\r
+                                                                       ns = "";\r
+                                                       }\r
+                                                       if(ns==null)\r
+                                                               throw new XMLStreamException("Invalid Namespace Prefix at " + count);\r
+                                                       go = false;\r
+                                                       switch(t.state) { // based on \r
+                                                         case DOC_TYPE: \r
+                                                                 rv = new XEvent.StartDocument();\r
+                                                                 break;\r
+                                                         case COMMENT:\r
+                                                                 rv = new XEvent.Comment(t.value);\r
+                                                                 break;\r
+                                                         case START_TAG:\r
+                                                                 rv = new XEvent.StartElement(ns,t.name);\r
+                                                                 nsses.push(nss);                              // Change potential scope for Namespace\r
+                                                                 break;\r
+                                                         case END_TAG:\r
+                                                                 rv = new XEvent.EndElement(ns,t.name);\r
+                                                                 nss = nsses.pop();                    // End potential scope for Namespace\r
+                                                                 break;\r
+                                                         case START_TAG|END_TAG:                       // This tag is both start/end  aka <myTag/>\r
+                                                                 rv = new XEvent.StartElement(ns,t.name);\r
+                                                                 if(last=='/')another = new XEvent.EndElement(ns,t.name);\r
+                                                       }\r
+                                                       if(cxe!=null) {     // if there is a Character Event, it actually should go first.  ow.\r
+                                                               another = rv;   // Make current Event the "another" or next event, and \r
+                                                               rv = cxe;               // send Character Event now\r
+                                                       }\r
+                                                       break;\r
+                                               case ' ':\r
+                                               case '\t':\r
+                                               case '\n':\r
+                                                       if((state&BEGIN_DOC)==BEGIN_DOC) { // if Whitespace before doc, just ignore \r
+                                                               break;\r
+                                                       }\r
+                                                       // fallthrough on purpose\r
+                                               default:\r
+                                                       if((state&BEGIN_DOC)==BEGIN_DOC) { // if there is any data at the start other than XML Tag, it's not XML\r
+                                                               throw new XMLStreamException("Parse Error: This is not an XML Doc");\r
+                                                       }\r
+                                                       baos.write(c); // save off Characters\r
+                                       }\r
+                                       last = c; // Some processing needs to know what the last character was, aka Escaped characters... ex \"\r
+                               }\r
+                       } catch (IOException e) {\r
+                               throw new XMLStreamException(e); // all errors parsing will be treated as XMLStreamErrors (like StAX)\r
+                       }\r
+                       if(c==-1 && (state&BEGIN_DOC)==BEGIN_DOC) {                        // Normally, end of stream is ok, however, we need to know if the \r
+                               throw new XMLStreamException("Premature End of File"); // document isn't an XML document, so we throw exception if it \r
+                       }                                                                                                                  // hasn't yet been determined to be an XML Doc\r
+               }\r
+               return rv;\r
+       }\r
+       \r
+       /**\r
+        * parseTag\r
+        * \r
+        * Parsing a Tag is somewhat complicated, so it's helpful to separate this process from the \r
+        * higher level Parsing effort\r
+        * @return\r
+        * @throws IOException\r
+        * @throws XMLStreamException\r
+        */\r
+       private Tag parseTag() throws IOException, XMLStreamException {\r
+               Tag tag = null;\r
+               boolean go = true;\r
+               state = 0;\r
+               int c, quote=0; // If "quote" is 0, then we're not in a quote.  We set ' (in pretag) or " in attribs accordingly to denote quoted\r
+               String prefix=null,name=null,value=null;\r
+               baos.reset();\r
+               \r
+               while(go && (c=is.read())>=0) {\r
+                       ++count;\r
+                       if(quote!=0) { // If we're in a quote, we only end if we hit another quote of the same time, not preceded by \\r
+                               if(c==quote && last!='\\') {\r
+                                       quote=0;\r
+                               } else {\r
+                                       baos.write(c);\r
+                               }\r
+                       } else if((state&COMMENT)==COMMENT) { // similar to Quote is being in a comment\r
+                               switch(c) {\r
+                                       case '-':\r
+                                               switch(state) { // XML has a complicated Quote set... <!-- --> ... we keep track if each has been met with flags. \r
+                                                       case COMMENT|COMMENT_E:\r
+                                                               state|=COMMENT_D1;\r
+                                                               break;\r
+                                                       case COMMENT|COMMENT_E|COMMENT_D1:\r
+                                                               state|=COMMENT_D2;\r
+                                                               baos.reset();                           // clear out "!--", it's a Comment\r
+                                                               break;\r
+                                                       case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2:\r
+                                                               state|=COMMENT_D3;\r
+                                                               baos.write(c);\r
+                                                               break;\r
+                                                       case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3:\r
+                                                               state|=COMMENT_D4;\r
+                                                               baos.write(c);\r
+                                                               break;\r
+                                               }\r
+                                               break;\r
+                                       case '>': // Tag indicator has been found, do we have all the comment characters in line?\r
+                                               if((state&COMPLETE_COMMENT)==COMPLETE_COMMENT) {\r
+                                                       byte ba[] = baos.toByteArray();\r
+                                                       tag = new Tag(null,null, new String(ba,0,ba.length-2));\r
+                                                       baos.reset();\r
+                                                       go = false;\r
+                                                       break;\r
+                                               }\r
+                                               // fall through on purpose\r
+                                       default:\r
+                                               state&=~(COMMENT_D3|COMMENT_D4);\r
+                                               if((state&IN_COMMENT)!=IN_COMMENT) state&=~IN_COMMENT; // false alarm, it's not actually a comment\r
+                                               baos.write(c);\r
+                               }\r
+                       } else { // Normal Tag Processing loop\r
+                               switch(c) {\r
+                                       case '?': \r
+                                               switch(state & (QUESTION_F|QUESTION)) {  // Validate the state of Doc tag... <?xml ... ?>\r
+                                                       case QUESTION_F:\r
+                                                               state |= DOC_TYPE;\r
+                                                               state &= ~QUESTION_F;\r
+                                                               break;\r
+                                                       case 0:\r
+                                                               state |=QUESTION_F;\r
+                                                               break;\r
+                                                       default:\r
+                                                               throw new IOException("Bad character [?] at " + count);\r
+                                               }\r
+                                               break;\r
+                                       case '!':\r
+                                               if(last=='<') { \r
+                                                       state|=COMMENT|COMMENT_E; // likely a comment, continue processing in Comment Loop\r
+                                               }\r
+                                               baos.write(c);\r
+                                               break;\r
+                                       case '/':\r
+                                               state|=(last=='<'?END_TAG:(END_TAG|START_TAG));  // end tag indicator </xxx>, ,or both <xxx/>\r
+                                               break;\r
+                                       case ':':\r
+                                               prefix=baos.toString(); // prefix indicator\r
+                                               baos.reset();\r
+                                               break;\r
+                                       case '=':                                       // used in Attributes\r
+                                               name=baos.toString();\r
+                                               baos.reset();\r
+                                               state|=VALUE;\r
+                                               break;\r
+                                       case '>': // end the tag, which causes end of this subprocess as well as formulation of the found data\r
+                                               go = false;\r
+                                               // passthrough on purpose\r
+                                       case ' ':\r
+                                       case '\t':\r
+                                       case '\n': // white space indicates change in internal tag state, ex between name and between attributes\r
+                                               if((state&VALUE)==VALUE) {\r
+                                                       value = baos.toString();        // we're in VALUE state, add characters to Value\r
+                                               } else if(name==null) {\r
+                                                       name = baos.toString();         // we're in Name state (default) add characters to Name\r
+                                               }\r
+                                               baos.reset();                                   // we've assigned chars, reset buffer\r
+                                               if(name!=null) {                                // Name is not null, there's a tag in the offing here...\r
+                                                       Tag t = new Tag(prefix,name,value);\r
+                                                       if(tag==null) {                         // Set as the tag to return, if not exists\r
+                                                               tag = t;\r
+                                                       } else {                                        // if we already have a Tag, then we'll treat this one as an attribute\r
+                                                               tag.add(t);\r
+                                                       }\r
+                                               }\r
+                                               prefix=name=value=null;                 // reset these values in case we loop for attributes.\r
+                                               break;\r
+                                       case '\'':                                                      // is the character one of two kinds of quote?\r
+                                       case '"':\r
+                                               if(last!='\\') {\r
+                                                       quote=c;\r
+                                                       break;\r
+                                               }\r
+                                               // Fallthrough ok\r
+                                       default:\r
+                                               baos.write(c);                                  // write any unprocessed bytes into buffer\r
+                                               \r
+                               }\r
+                       }\r
+                       last = c;\r
+               }\r
+               int type = state&(DOC_TYPE|COMMENT|END_TAG|START_TAG); // get just the Tag states and turn into Type for Tag\r
+               if(type==0) {\r
+                       type=START_TAG;\r
+               }\r
+               tag.state|=type;        // add the appropriate Tag States\r
+               return tag;\r
+       }\r
+\r
+       /**\r
+        * getNSS\r
+        * \r
+        * If the tag contains some Namespace attributes, create a new nss from the passed in one, copy all into it, then add\r
+        * This provides Scoping behavior\r
+        * \r
+        * if Nss is null in the first place, create an new nss, so we don't have to deal with null Maps.\r
+        * \r
+        * @param nss\r
+        * @param t\r
+        * @return\r
+        */\r
+       private Map<String, String> getNss(Map<String, String> nss, Tag t) {\r
+               Map<String,String> newnss = null;\r
+               if(t.attribs!=null) {\r
+                       for(Tag tag : t.attribs) {\r
+                               if("xmlns".equals(tag.prefix)) {\r
+                                       if(newnss==null) {\r
+                                               newnss = new HashMap<String,String>();\r
+                                               if(nss!=null)newnss.putAll(nss);\r
+                                       }\r
+                                       newnss.put(tag.name, tag.value);\r
+                               }\r
+                       }\r
+               }\r
+               return newnss==null?(nss==null?new HashMap<String,String>():nss):newnss;\r
+       }\r
+\r
+       /**\r
+        * The result of the parseTag method\r
+        * \r
+        * Data is split up into prefix, name and value portions. "Tags" with Values that are inside a Tag are known in XLM\r
+        * as Attributes.  \r
+        * \r
+        *\r
+        */\r
+       public class Tag {\r
+               public int state;\r
+               public String prefix,name,value;\r
+               public List<Tag> attribs;\r
+\r
+               public Tag(String prefix, String name, String value) {\r
+                       this.prefix = prefix;\r
+                       this.name = name;\r
+                       this.value = value;\r
+                       attribs = null;  \r
+               }\r
+\r
+               /**\r
+                * add an attribute\r
+                * Not all tags need attributes... lazy instantiate to save time and memory\r
+                * @param tag\r
+                */\r
+               public void add(Tag attrib) {\r
+                       if(attribs == null) {\r
+                               attribs = new ArrayList<Tag>();\r
+                       }\r
+                       attribs.add(attrib);\r
+               }\r
+               \r
+               public String toString() {\r
+                       StringBuffer sb = new StringBuffer();\r
+                       if(prefix!=null) {\r
+                               sb.append(prefix);\r
+                               sb.append(':');\r
+                       }\r
+                       sb.append(name==null?"!!ERROR!!":name);\r
+\r
+                       char quote = ((state&DOC_TYPE)==DOC_TYPE)?'\'':'"';\r
+                       if(value!=null) {\r
+                               sb.append('=');\r
+                               sb.append(quote);\r
+                               sb.append(value);\r
+                               sb.append(quote);\r
+                       }\r
+                       return sb.toString();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/JU_AES.java b/core/src/test/java/com/att/cadi/JU_AES.java
new file mode 100644 (file)
index 0000000..2143e5b
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+\r
+import javax.crypto.CipherInputStream;\r
+import javax.crypto.CipherOutputStream;\r
+\r
+import org.junit.Test;\r
+\r
+import junit.framework.Assert;\r
+\r
+public class JU_AES {\r
+\r
+       @Test\r
+       public void test() throws Exception {\r
+               AES aes = new AES();\r
+               String orig = "I'm a password, really";\r
+               byte[] passin = orig.getBytes();\r
+               byte[] encrypted = aes.encrypt(passin);\r
+               byte[] b64enc = Symm.base64.encode(encrypted);\r
+               System.out.println(new String(b64enc));\r
+               \r
+               encrypted = Symm.base64.decode(b64enc);\r
+               passin = aes.decrypt(encrypted);\r
+               Assert.assertEquals(orig, new String(passin));\r
+       }\r
+\r
+       @Test\r
+       public void testInputStream() throws Exception {\r
+               AES aes = new AES();\r
+               String orig = "I'm a password, really";\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(orig.getBytes());\r
+               CipherInputStream cis = aes.inputStream(bais, true);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               Symm.base64.encode(cis, baos);\r
+               cis.close();\r
+\r
+               byte[] b64encrypted;\r
+               System.out.println(new String(b64encrypted=baos.toByteArray()));\r
+               \r
+               \r
+               baos.reset();\r
+               CipherOutputStream cos = aes.outputStream(baos, false);\r
+               Symm.base64.decode(new ByteArrayInputStream(b64encrypted),cos);\r
+               cos.close();\r
+               Assert.assertEquals(orig, new String(baos.toByteArray()));\r
+       }\r
+\r
+       @Test\r
+       public void testObtain() throws Exception {\r
+               byte[] keygen = Symm.baseCrypt().keygen();\r
+               \r
+               Symm symm = Symm.obtain(new ByteArrayInputStream(keygen));\r
+               \r
+               String orig ="Another Password, please";\r
+               String encrypted = symm.enpass(orig);\r
+               System.out.println(encrypted);\r
+               String decrypted = symm.depass(encrypted);\r
+               System.out.println(decrypted);\r
+               Assert.assertEquals(orig, decrypted);\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/lur/test/JU_LocalLur.java b/core/src/test/java/com/att/cadi/lur/test/JU_LocalLur.java
new file mode 100644 (file)
index 0000000..a4ada86
--- /dev/null
@@ -0,0 +1,102 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.test;\r
+\r
+import static junit.framework.Assert.assertEquals;\r
+import static junit.framework.Assert.assertFalse;\r
+import static junit.framework.Assert.assertTrue;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.security.Principal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.CredVal.Type;\r
+import com.att.cadi.Lur;\r
+import com.att.cadi.Permission;\r
+import com.att.cadi.PropAccess;\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.UsersDump;\r
+import com.att.cadi.lur.LocalLur;\r
+import com.att.cadi.lur.LocalPermission;\r
+\r
+public class JU_LocalLur {\r
+\r
+       @Test\r
+       public void test() throws IOException {\r
+               Symm symmetric = Symm.baseCrypt().obtain();\r
+               LocalLur up;\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               baos.write(Symm.ENC.getBytes());\r
+               symmetric.enpass("<pass>", baos);\r
+               PropAccess ta = new PropAccess();\r
+               Lur ml = up = new LocalLur(ta,"myname:groupA,groupB","admin:myname,yourname;suser:hisname,hername,m1234%"+baos.toString());\r
+               \r
+               Permission admin = new LocalPermission("admin");\r
+               Permission suser = new LocalPermission("suser");\r
+               \r
+               // Check User fish\r
+               assertTrue(ml.fish(new JUPrincipal("myname"),admin));\r
+               assertTrue(ml.fish(new JUPrincipal("hisname"),admin));\r
+               assertFalse(ml.fish(new JUPrincipal("noname"),admin));\r
+               assertTrue(ml.fish(new JUPrincipal("itsname"),suser));\r
+               assertTrue(ml.fish(new JUPrincipal("hername"),suser));\r
+               assertFalse(ml.fish(new JUPrincipal("myname"),suser));\r
+               \r
+               \r
+               // Check validate password\r
+               assertTrue(up.validate("m1234",Type.PASSWORD, "<pass>".getBytes()));\r
+               assertFalse(up.validate("m1234",Type.PASSWORD, "badPass".getBytes()));\r
+               \r
+               // Check fishAll\r
+               Set<String> set = new TreeSet<String>();\r
+               List<Permission> perms = new ArrayList<Permission>();\r
+               ml.fishAll(new JUPrincipal("myname"), perms);\r
+               for(Permission p : perms) {\r
+                       set.add(p.getKey());\r
+               }\r
+               assertEquals("[admin, groupA, groupB]",set.toString());\r
+               UsersDump.write(System.out, up);\r
+               System.out.flush();\r
+               \r
+       }\r
+       \r
+       // Simplistic Principal for testing purposes\r
+       private static class JUPrincipal implements Principal {\r
+               private String name;\r
+               public JUPrincipal(String name) {\r
+                       this.name = name;\r
+               }\r
+//             @Override\r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/lur/test/TestAccess.java b/core/src/test/java/com/att/cadi/lur/test/TestAccess.java
new file mode 100644 (file)
index 0000000..f8e911c
--- /dev/null
@@ -0,0 +1,92 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.lur.test;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import com.att.cadi.Access;\r
+import com.att.cadi.Symm;\r
+\r
+public class TestAccess implements Access {\r
+       private Symm symm;\r
+\r
+       public TestAccess() {\r
+               symm = Symm.obtain(this);\r
+       }\r
+       \r
+       public TestAccess(Symm symmetric) {\r
+               symm = symmetric;\r
+       }\r
+\r
+       public void log(Level level, Object... elements) {\r
+               boolean first = true;\r
+               for(int i=0;i<elements.length;++i) {\r
+                       if(first)first = false;\r
+                       else System.out.print(' ');\r
+                       System.out.print(elements[i].toString());\r
+               }\r
+               System.out.println();\r
+       }\r
+\r
+       public void log(Exception e, Object... elements) {\r
+               e.printStackTrace();\r
+               log(Level.ERROR,elements);\r
+       }\r
+\r
+       public void setLogLevel(Level level) {\r
+               \r
+       }\r
+\r
+       public ClassLoader classLoader() {\r
+               return ClassLoader.getSystemClassLoader();\r
+       }\r
+\r
+       public String getProperty(String string, String def) {\r
+               String rv = System.getProperty(string);\r
+               return rv==null?def:rv;\r
+       }\r
+\r
+       public void load(InputStream is) throws IOException {\r
+               \r
+       }\r
+\r
+       public String decrypt(String encrypted, boolean anytext) throws IOException {\r
+               return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))\r
+                       ? symm.depass(encrypted)\r
+                       : encrypted;\r
+       }\r
+\r
+       @Override\r
+       public boolean willLog(Level level) {\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public void printf(Level level, String fmt, Object[] elements) {\r
+               // TODO Auto-generated method stub\r
+               \r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_Base64.java b/core/src/test/java/com/att/cadi/test/JU_Base64.java
new file mode 100644 (file)
index 0000000..fdafb84
--- /dev/null
@@ -0,0 +1,158 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertNotSame;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.security.SecureRandom;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.Symm;\r
+import com.att.cadi.config.Config;\r
+\r
+\r
+public class JU_Base64 {\r
+       private static final String encoding = "Man is distinguished, not only by his reason, but by this singular " +\r
+                       "passion from other animals, which is a lust of the mind, that by a " + \r
+                       "perseverance of delight in the continued and indefatigable generation of " + \r
+                       "knowledge, exceeds the short vehemence of any carnal pleasure.";\r
+                \r
+       private static final String expected = \r
+                       "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\n" + \r
+                       "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\n" + \r
+                       "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\n" +\r
+                       "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\n" +\r
+                       "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";\r
+\r
+\r
+       @Test\r
+       public void test() throws Exception {\r
+               // Test with different Padding\r
+               encode("leas",    "bGVhcw==");\r
+               encode("leasu",   "bGVhc3U=");\r
+               encode("leasur",  "bGVhc3Vy");\r
+               encode("leasure", "bGVhc3VyZQ==");\r
+               encode("leasure.","bGVhc3VyZS4=");\r
+\r
+               // Test with line ends\r
+               encode(encoding, expected);\r
+               \r
+               int ITER = 2000;\r
+               System.out.println("Priming by Encoding Base64 " + ITER + " times");\r
+               long start = System.nanoTime();\r
+               for(int i=0;i<ITER;++i) {\r
+                       Symm.base64.encode(encoding);\r
+               }\r
+               Float ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/ITER + "ms");\r
+               \r
+               System.out.println("Priming by Decoding Base64 " + ITER + " times");\r
+               start = System.nanoTime();\r
+               for(int i=0;i<ITER;++i) {\r
+                       Symm.base64.decode(expected);\r
+               }\r
+               ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/ITER + "ms");\r
+\r
+               \r
+               ITER=30000;\r
+               System.out.println("Encoding Base64 " + ITER + " times");\r
+               start = System.nanoTime();\r
+               for(int i=0;i<ITER;++i) {\r
+                       Symm.base64.encode(encoding);\r
+               }\r
+               ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/ITER + "ms");\r
+               \r
+               System.out.println("Decoding Base64 " + ITER + " times");\r
+               start = System.nanoTime();\r
+               for(int i=0;i<ITER;++i) {\r
+                       Symm.base64.decode(expected);\r
+               }\r
+               ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/ITER + "ms");\r
+       }\r
+       \r
+       @Test\r
+       public void symmetric() throws IOException {\r
+               System.out.println("Validating Generated Key mechanisms works");\r
+               String symmetric = new String(Symm.base64.keygen());\r
+               System.out.println(symmetric);\r
+               Symm bsym = Symm.obtain(symmetric);\r
+               String result = bsym.encode(encoding);\r
+               System.out.println("\nResult:");\r
+               System.out.println(result);\r
+               assertEquals(encoding, bsym.decode(result));\r
+               \r
+               int ITER = 20000;\r
+               System.out.println("Generating keys " + ITER + " times");\r
+               long start = System.nanoTime();\r
+               for(int i=0;i<ITER;++i) {\r
+                       Symm.base64.keygen();\r
+               }\r
+               Float ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/ITER + "ms");\r
+\r
+               char[] manipulate = symmetric.toCharArray();\r
+               int spot = new SecureRandom().nextInt(manipulate.length);\r
+               manipulate[spot]|=0xFF;\r
+               String newsymmetric = new String(manipulate);\r
+               assertNotSame(newsymmetric, symmetric);\r
+               try {\r
+                       bsym = Symm.obtain(newsymmetric);\r
+                       result = bsym.decode(result);\r
+                       assertEquals(encoding, result);\r
+               } catch (IOException e) {\r
+                       // this is what we want to see if key wrong\r
+                       System.out.println(e.getMessage() + " (as expected)");\r
+               }\r
+       }\r
+\r
+       private void encode(String toEncode, String expected) throws IOException {\r
+               System.out.println("-------------------------------------------------");\r
+               System.out.println(toEncode);\r
+               System.out.println();\r
+               System.out.println(expected);\r
+               System.out.println();\r
+               String result = Symm.base64.encode(toEncode);\r
+               System.out.println(result);\r
+               assertEquals(expected,result);\r
+               \r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               Symm.base64.decode(new ByteArrayInputStream(result.getBytes()), baos);\r
+               result = baos.toString(Config.UTF_8);\r
+               System.out.println(result);\r
+               assertEquals(toEncode,result);\r
+               \r
+       }\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_BufferedServletInputStream.java b/core/src/test/java/com/att/cadi/test/JU_BufferedServletInputStream.java
new file mode 100644 (file)
index 0000000..c30d944
--- /dev/null
@@ -0,0 +1,192 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import static junit.framework.Assert.assertEquals;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.BufferedServletInputStream;\r
+\r
+public class JU_BufferedServletInputStream {\r
+\r
+       @Test\r
+       public void testByteRead() throws Exception {\r
+               FileInputStream fis = new FileInputStream("test/CBUSevent.xml");\r
+               BufferedServletInputStream bsis = new BufferedServletInputStream(fis);\r
+                       try {\r
+                       bsis.mark(0);\r
+                       int c;\r
+                       byte aa[] = new byte[260];\r
+                       for(int i=0;i<aa.length;++i) {\r
+                               c = bsis.read();\r
+                               if(c>=0) {\r
+                                       aa[i]=(byte)c;\r
+                               }\r
+                       }\r
+                       System.out.println(new String(aa));\r
+                       \r
+                       bsis.reset();\r
+\r
+                       byte bb[] = new byte[400];\r
+                       for(int i=0;i<bb.length;++i) {\r
+                               c = bsis.read();\r
+                               if(c>=0) {\r
+                                       bb[i]=(byte)c;\r
+                               }\r
+                       }\r
+                       System.out.println(new String(bb));\r
+\r
+               } finally {\r
+                       bsis.close();\r
+                       fis.close();\r
+               }\r
+       }\r
+       \r
+       @Test\r
+       public void testByteArray() throws Exception {\r
+               FileInputStream fis = new FileInputStream("test/CBUSevent.xml");\r
+               BufferedServletInputStream bsis = new BufferedServletInputStream(fis);\r
+               try {\r
+                       bsis.mark(0);\r
+                       byte aa[] = new byte[260];\r
+                       bsis.read(aa);\r
+                       System.out.println(new String(aa));\r
+                       \r
+                       bsis.reset();\r
+\r
+                       byte bb[] = new byte[400];\r
+                       bsis.read(bb);\r
+                       System.out.println(new String(bb));\r
+\r
+               } finally {\r
+                       bsis.close();\r
+                       fis.close();\r
+               }\r
+       }\r
+\r
+       @Test\r
+       public void testDoubleRead() throws Exception {\r
+               FileInputStream fis = new FileInputStream("test/CBUSevent.xml");\r
+               BufferedServletInputStream bsis = new BufferedServletInputStream(fis);\r
+               try {\r
+                       bsis.mark(0);\r
+                       byte aa[] = new byte[260];\r
+                       bsis.read(aa);\r
+                       System.out.println(new String(aa));\r
+                       \r
+                       bsis.reset();\r
+\r
+                       byte bb[] = new byte[400];\r
+                       bsis.read(bb);\r
+                       System.out.println(new String(bb));\r
+\r
+               } finally {\r
+                       bsis.close();\r
+                       fis.close();\r
+               }\r
+       }\r
+\r
+       @Test\r
+       public void testByteArray2() throws Exception {\r
+               FileInputStream fis = new FileInputStream("test/CBUSevent.xml");\r
+               try {\r
+                       BufferedServletInputStream bsis = new BufferedServletInputStream(fis);\r
+                       byte[] content = null;\r
+                       byte aa[] = new byte[500];\r
+                       for(int i=0;i<2000;++i) {\r
+                               bsis.mark(0);\r
+                               bsis.read(aa,0,260);\r
+                               if(i==0)System.out.println(new String(aa));\r
+                               \r
+                               bsis.reset();\r
+       \r
+                               bsis.read(aa,0,aa.length);\r
+                               if(i==0) {\r
+                                       System.out.println(new String(aa));\r
+                                       content = aa;\r
+                                       aa = new byte[400];\r
+                               }\r
+                               bsis = new BufferedServletInputStream(new ByteArrayInputStream(content));\r
+                               \r
+                       }\r
+                       \r
+                       System.out.println(new String(aa));\r
+\r
+               } finally {\r
+                       fis.close();\r
+               }\r
+       }\r
+\r
+       // "Bug" 4/22/2013 \r
+       // Some XML code expects Buffered InputStream can never return 0...  This isn't actually true, but we'll accommodate as far\r
+       // as we can. \r
+       // Here, we make sure we set and read the Buffered data, making sure the buffer is empty on the last test...\r
+       @Test\r
+       public void issue04_22_2013() throws IOException {\r
+               String testString = "We want to read in and get out with a Buffered Stream seamlessly.";\r
+               ByteArrayInputStream bais = new ByteArrayInputStream(testString.getBytes());\r
+               BufferedServletInputStream bsis = new BufferedServletInputStream(bais);\r
+                       try {\r
+                       bsis.mark(0);\r
+                       byte aa[] = new byte[testString.length()];  // 65 count... important for our test (divisible by 5);\r
+\r
+                       int read;\r
+                       for(int i=0;i<aa.length;i+=5) {\r
+                               read = bsis.read(aa, i, 5);\r
+                               assertEquals(5,read);\r
+                       }\r
+                       System.out.println(new String(aa));\r
+                       \r
+                       bsis.reset();\r
+\r
+                       byte bb[] = new byte[aa.length];\r
+                       read = 0;\r
+                       for(int i=0;read>=0;i+=read) {\r
+                               read = bsis.read(bb,i,5);\r
+                               switch(i) {\r
+                                       case 65:\r
+                                               assertEquals(read,-1);\r
+                                               break;\r
+                                       default:\r
+                                               assertEquals(read,5);\r
+                               }\r
+                       }\r
+                       System.out.println(new String(bb));\r
+                       assertEquals(testString,new String(aa));\r
+                       assertEquals(testString,new String(bb));\r
+\r
+               } finally {\r
+                       bsis.close();\r
+                       bais.close();\r
+               }\r
+               \r
+       }\r
+       \r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_Capacitor.java b/core/src/test/java/com/att/cadi/test/JU_Capacitor.java
new file mode 100644 (file)
index 0000000..c3f6d77
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import static junit.framework.Assert.assertEquals;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.Capacitor;\r
+\r
+public class JU_Capacitor {\r
+       @Test\r
+       public void testA() {\r
+               Capacitor cap = new Capacitor();\r
+               \r
+               for(int iter=0;iter<200;++iter) {\r
+                       for(int i=0;i<20;++i) {\r
+                               cap.put((byte)('a'+i));\r
+                       }\r
+                       cap.setForRead();\r
+                       byte[] array = new byte[20];\r
+                       for(int i=0;i<20;++i) {\r
+                               array[i]=(byte)cap.read();\r
+                       }\r
+                       assertEquals("abcdefghijklmnopqrst",new String(array));\r
+                       assertEquals(-1,cap.read());\r
+                       cap.done();\r
+               }\r
+       }\r
+\r
+       public final static String TEST_DATA = \r
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +\r
+                       "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +\r
+                       "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +\r
+                       "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +\r
+                       "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" +\r
+                       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";\r
+       @Test\r
+       public void testB() {\r
+               Capacitor cap = new Capacitor();\r
+               byte[] arrayA = TEST_DATA.getBytes();\r
+               System.out.println(arrayA.length);\r
+               for(int iter=0;iter<200;++iter) {\r
+                       for(int i=0;i<arrayA.length;++i) {\r
+                               cap.put(arrayA[i]);\r
+                       }\r
+                       cap.setForRead();\r
+                       assertEquals(TEST_DATA.length(),cap.available());\r
+                       byte[] arrayB = new byte[arrayA.length];\r
+                       for(int i=0;i<arrayB.length;++i) {\r
+                               arrayB[i]=(byte)cap.read();\r
+                       }\r
+                       assertEquals(TEST_DATA,new String(arrayB));\r
+                       assertEquals(-1,cap.read());\r
+                       cap.done();\r
+               }\r
+       }\r
+\r
+       @Test\r
+       public void testC() {\r
+               Capacitor cap = new Capacitor();\r
+               byte[] arrayA = TEST_DATA.getBytes();\r
+               System.out.println(arrayA.length);\r
+               for(int iter=0;iter<200;++iter) {\r
+                       cap.put(arrayA,0,arrayA.length);\r
+                       cap.setForRead();\r
+                       assertEquals(TEST_DATA.length(),cap.available());\r
+                       byte[] arrayB = new byte[arrayA.length];\r
+                       assertEquals(arrayA.length,cap.read(arrayB,0,arrayB.length));\r
+                       assertEquals(TEST_DATA,new String(arrayB));\r
+                       assertEquals(-1,cap.read());\r
+                       cap.done();\r
+               }\r
+       }\r
+\r
+       \r
+       @Test\r
+       public void testD() {\r
+               StringBuffer sb = new StringBuffer();\r
+               for(int i=0;i<300;++i) {\r
+                       sb.append(TEST_DATA);\r
+                       sb.append("###FILLER##");\r
+               }\r
+               String td = sb.toString();\r
+               Capacitor cap = new Capacitor();\r
+               byte[] arrayA = td.getBytes();\r
+               System.out.println(arrayA.length);\r
+               for(int iter=0;iter<200;++iter) {\r
+                       cap.put(arrayA,0,arrayA.length);\r
+                       cap.setForRead();\r
+                       assertEquals(td.length(),cap.available());\r
+                       byte[] arrayB = new byte[arrayA.length];\r
+                       assertEquals(arrayA.length,cap.read(arrayB,0,arrayB.length));\r
+                       assertEquals(td,new String(arrayB));\r
+                       assertEquals(-1,cap.read());\r
+                       cap.done();\r
+               }\r
+       }\r
+\r
+       @Test\r
+       public void testE() {\r
+               Capacitor cap = new Capacitor();\r
+               \r
+               String b = "This is some content that we want to read";\r
+               byte[] a = b.getBytes();\r
+               byte[] c = new byte[b.length()]; // we want to use this to test reading offsets, etc\r
+\r
+               for(int i=0;i<a.length;i+=11) {\r
+                       cap.put(a, i, Math.min(11,a.length-i));\r
+               }\r
+               cap.reset();\r
+               int read;\r
+               for(int i=0;i<c.length;i+=read) {\r
+                       read = cap.read(c, i, Math.min(3,c.length-i));\r
+                       if(read<0) break;\r
+               }\r
+               \r
+               assertEquals(b, new String(c));\r
+               \r
+               \r
+       }\r
+       \r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_Hash.java b/core/src/test/java/com/att/cadi/test/JU_Hash.java
new file mode 100644 (file)
index 0000000..85e4209
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.CadiException;\r
+import com.att.cadi.Hash;\r
+\r
+import junit.framework.Assert;\r
+\r
+public class JU_Hash {\r
+\r
+       @Test\r
+       public void test() throws CadiException {\r
+               String init = "m82347@csp.att.com:kumquat8rie@#Tomatos3";\r
+               String hashed = Hash.toHex(init.getBytes());\r
+               System.out.println(hashed);\r
+               byte[] ba = Hash.fromHex(hashed);\r
+               String recon = new String(ba);\r
+               System.out.println(recon);\r
+               Assert.assertEquals(init, recon);\r
+               \r
+               init =hashed.substring(1);\r
+               try {\r
+                       hashed = Hash.fromHex(init).toString();\r
+                       Assert.fail("Should have thrown Exception");\r
+               } catch (CadiException e) {\r
+                       \r
+               }\r
+               \r
+               init = hashed.replace('1', '~');\r
+               try {\r
+                       hashed = Hash.fromHex(init).toString();\r
+                       Assert.fail("Should have thrown Exception");\r
+               } catch (CadiException e) {\r
+                       \r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_Passcode.java b/core/src/test/java/com/att/cadi/test/JU_Passcode.java
new file mode 100644 (file)
index 0000000..68c7dc8
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.CmdLine;\r
+import com.att.cadi.Symm;\r
+\r
+import junit.framework.Assert;\r
+\r
+public class JU_Passcode {\r
+       @Test\r
+       public void test() throws Exception {\r
+               int iterations = 0;\r
+               long start = System.nanoTime();\r
+               int gens= 800, en_de=2000;\r
+               for(int j=0;j<gens;++j) {\r
+                       CmdLine.main(new String[] {"keygen","tempkey"});\r
+                       \r
+                       Symm symm;\r
+                       File fi = new File("tempkey");\r
+                       Assert.assertEquals(2074, fi.length());\r
+                       FileInputStream fis = new FileInputStream(fi);\r
+                       \r
+                       try {\r
+                               symm = Symm.obtain(fis);\r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+                       String samples[] = {"activevos","ThisIsATestPassword","I have spaces","I have 's, /s and &s and _s"};\r
+                       ByteArrayOutputStream baos;\r
+                       for(int i=0;i<en_de;++i) {\r
+                               String password = samples[i%samples.length];\r
+                               baos = new ByteArrayOutputStream();\r
+                               symm.enpass(password, baos);\r
+                               String pass = baos.toString();\r
+                               byte[] array = baos.toByteArray();\r
+                               for(int k=0;k<array.length;++k) {\r
+                                       byte ch = array[k];\r
+//                             for(int k=0;k<pass.length();++k) {\r
+//                                     char ch = pass.charAt(k);\r
+                                       if(!(Character.isLetter(ch) || Character.isDigit(ch) || ch=='-' || ch=='_' || ch=='=')) {\r
+                                               throw new Exception("Yikes, have a bad character..." + ch + '(' + (int)ch + ')');\r
+                                       }\r
+                               }\r
+                               baos = new ByteArrayOutputStream();\r
+                               symm.depass(pass, baos);\r
+                               Assert.assertEquals(password,baos.toString());\r
+                               Assert.assertEquals(password,symm.depass(pass));\r
+                               ++iterations;\r
+                       }\r
+                       symm.enpass("activevos", System.out);\r
+                       System.out.println();\r
+               }\r
+               float ms = (System.nanoTime()-start)/1000000F;\r
+               System.out.println("Ran " + iterations + " Encrypt/Decrypt cycles + " + gens + " keygens");\r
+\r
+               System.out.println("Total: " + ms + "ms");\r
+               System.out.println("Avg:   " + ms/iterations + "ms");\r
+               System.out.println("Avg Gen + " + en_de + " Encrypt/Decrypt cycles:  " + ms/gens + "ms");\r
+\r
+\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_UserChainManip.java b/core/src/test/java/com/att/cadi/test/JU_UserChainManip.java
new file mode 100644 (file)
index 0000000..40b9266
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import static org.junit.Assert.*;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.util.UserChainManip;\r
+\r
+public class JU_UserChainManip {\r
+\r
+       @Test\r
+       public void test() {\r
+               assertEquals("",UserChainManip.idToNS(null));\r
+               assertEquals("",UserChainManip.idToNS(""));\r
+               assertEquals("",UserChainManip.idToNS("something"));\r
+               assertEquals("",UserChainManip.idToNS("something@@"));\r
+               assertEquals("",UserChainManip.idToNS("something@@."));\r
+               assertEquals("com",UserChainManip.idToNS("something@com"));\r
+               assertEquals("com.random",UserChainManip.idToNS("something@random.com"));\r
+               assertEquals("com.random",UserChainManip.idToNS("@random.com"));\r
+               assertEquals("com.random",UserChainManip.idToNS("something@random.com."));\r
+               assertEquals("com.random",UserChainManip.idToNS("something@..random...com..."));\r
+               assertEquals("com.random.this",UserChainManip.idToNS("something@this.random.com"));\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/JU_Vars.java b/core/src/test/java/com/att/cadi/test/JU_Vars.java
new file mode 100644 (file)
index 0000000..daf2c0f
--- /dev/null
@@ -0,0 +1,127 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+import org.junit.AfterClass;\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.util.Vars;\r
+\r
+public class JU_Vars {\r
+\r
+       @AfterClass\r
+       public static void tearDownAfterClass() throws Exception {\r
+       }\r
+\r
+       @Test\r
+       public void test() {\r
+               StringBuilder holder = new StringBuilder();\r
+               String str,bstr;\r
+               assertEquals(str = "set %1 to %2",Vars.convert(holder,str, "a","b"));\r
+               assertEquals("set a to b",holder.toString());\r
+               assertEquals(str,Vars.convert(null,str, "a","b"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr="set %s to %s", "a","b"));\r
+               assertEquals("set a to b",holder.toString());\r
+               assertEquals(str,Vars.convert(null,bstr, "a","b"));\r
+               \r
+               holder.setLength(0);\r
+               assertEquals(str = "%1=%2",Vars.convert(holder,str, "a","b"));\r
+               assertEquals("a=b",holder.toString());\r
+               assertEquals(str,Vars.convert(null,str, "a","b"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr="%s=%s", "a","b"));\r
+               assertEquals("a=b",holder.toString());\r
+               assertEquals(str,Vars.convert(null,bstr, "a","b"));\r
+               \r
+               holder.setLength(0);\r
+               assertEquals(str = "%1%2",Vars.convert(holder,str, "a","b"));\r
+               assertEquals("ab",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,str, "a","b"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr="%s%s", "a","b"));\r
+               assertEquals("ab",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,bstr, "a","b"));\r
+\r
+\r
+               holder.setLength(0);\r
+               assertEquals(str = " %1=%2 ",Vars.convert(holder,str, "a","b"));\r
+               assertEquals(" a=b ",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,str, "a","b"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr = " %s=%s ", "a","b"));\r
+               assertEquals(" a=b ",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,bstr, "a","b"));\r
+\r
+               holder.setLength(0);\r
+               assertEquals(str = " %1%2%10 ",Vars.convert(holder,str, "a","b","c","d","e","f","g","h","i","j"));\r
+               assertEquals(" abj ",holder.toString());\r
+               assertEquals(str,Vars.convert(null,str, "a","b","c","d","e","f","g","h","i","j"));\r
+               holder.setLength(0);\r
+               assertEquals(str=" %1%2%3 ",Vars.convert(holder,bstr = " %s%s%s ", "a","b","c","d","e","f","g","h","i","j"));\r
+               assertEquals(" abc ",holder.toString());\r
+               assertEquals(str,Vars.convert(null,bstr, "a","b","c","d","e","f","g","h","i","j"));\r
+               \r
+\r
+               holder.setLength(0);\r
+               assertEquals(str = "set %1 to %2",Vars.convert(holder,str, "Something much","larger"));\r
+               assertEquals("set Something much to larger",holder.toString());\r
+               assertEquals(str,Vars.convert(null,str,"Something much","larger"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr="set %s to %s", "Something much","larger"));\r
+               assertEquals("set Something much to larger",holder.toString());\r
+               assertEquals(str,Vars.convert(null,bstr, "Something much","larger"));\r
+\r
+               holder.setLength(0);\r
+               assertEquals(str = "Text without Vars",Vars.convert(holder,str));\r
+               assertEquals(str,holder.toString());\r
+               assertEquals(str = "Text without Vars",Vars.convert(null,str));\r
+       \r
+               \r
+               holder.setLength(0);\r
+               assertEquals(str = "Not %1 Enough %2 Vars %3",Vars.convert(holder,str, "a","b"));\r
+               assertEquals("Not a Enough b Vars ",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,str, "a","b"));\r
+               holder.setLength(0);\r
+               assertEquals(str,Vars.convert(holder,bstr="Not %s Enough %s Vars %s", "a","b"));\r
+               assertEquals("Not a Enough b Vars ",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,bstr, "a","b"));\r
+\r
+               holder.setLength(0);\r
+               assertEquals(str = "!@#$%^*()-+?/,:;.",Vars.convert(holder,str, "a","b"));\r
+               assertEquals(str,holder.toString());\r
+               assertEquals(str ,Vars.convert(null,str, "a","b"));\r
+\r
+               holder.setLength(0);\r
+               bstr = "%s !@#$%^*()-+?/,:;.";\r
+               str = "%1 !@#$%^*()-+?/,:;.";\r
+               assertEquals(str,Vars.convert(holder,bstr, "Not Acceptable"));\r
+               assertEquals("Not Acceptable !@#$%^*()-+?/,:;.",holder.toString());\r
+               assertEquals(str ,Vars.convert(null,bstr, "Not Acceptable"));\r
+\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/test/Test.java b/core/src/test/java/com/att/cadi/test/Test.java
new file mode 100644 (file)
index 0000000..53729b4
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.test;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+\r
+/**\r
+ * A Class to run on command line to determine suitability of environment for certain TAFs.\r
+ * \r
+ * For instance, CSP supports services only in certain domains, and while dynamic host\r
+ * lookups on the machine work in most cases, sometimes, names and IPs are unexpected (and\r
+ * invalid) for CSP because of multiple NetworkInterfaces, etc\r
+ * \r
+ *\r
+ */\r
+public class Test {\r
+\r
+       /**\r
+        * @param args\r
+        */\r
+       public static void main(String[] args) {\r
+               try {\r
+                       System.out.println("CADI/TAF test");\r
+                       \r
+                       String hostName = InetAddress.getLocalHost().getCanonicalHostName();\r
+                       \r
+                       System.out.println("  Your automatic hostname is reported as \"" + hostName + "\"\n");\r
+                       String[] two;\r
+\r
+                       for(String str : args) {\r
+                               two = str.split("=");\r
+                               if(two.length==2) {\r
+                                       if("hostname".equals(two[0])) {\r
+                                               hostName = two[1];\r
+                                               System.out.println("  You have overlaid the automatic hostname with \"" + hostName + "\"\n");\r
+                                       }\r
+                               }\r
+                       }\r
+                       if(hostName.endsWith("vpn.cingular.net"))\r
+                               System.out.println("  This service appears to be an AT&T VPN address. These VPNs are typically\n" +\r
+                                               "    (and appropriately) firewalled against incoming traffic, and likely cannot be accessed.\n" +\r
+                                               "    For best results, choose a machine that is not firewalled on the ports you choose.\n");\r
+                       \r
+               } catch (UnknownHostException e) {\r
+                       e.printStackTrace();\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/wsse/test/JU_WSSE_Read.java b/core/src/test/java/com/att/cadi/wsse/test/JU_WSSE_Read.java
new file mode 100644 (file)
index 0000000..a262780
--- /dev/null
@@ -0,0 +1,192 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse.test;\r
+\r
+import static junit.framework.Assert.assertEquals;\r
+import static junit.framework.Assert.assertNotNull;\r
+import static junit.framework.Assert.assertNull;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+\r
+import javax.xml.stream.XMLStreamException;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.BasicCred;\r
+import com.att.cadi.BufferedServletInputStream;\r
+import com.att.cadi.wsse.WSSEParser;\r
+\r
+public class JU_WSSE_Read {\r
+\r
+       @Test\r
+       public void test() {\r
+               try {\r
+                       final BasicCred bc = new BasicCred() {\r
+\r
+                               private String user;\r
+                               private byte[] password;\r
+\r
+                               public void setUser(String user) {\r
+                                       this.user = user;\r
+                               }\r
+\r
+                               public void setCred(byte[] passwd) {\r
+                                       this.password = passwd;\r
+                               }\r
+\r
+                               public String getUser() {\r
+                                       return user;\r
+                               }\r
+\r
+                               public byte[] getCred() {\r
+                                       return password;\r
+                               }\r
+                       };\r
+\r
+                       WSSEParser wp = new WSSEParser();\r
+\r
+                       FileInputStream fis;\r
+                       fis = new FileInputStream("test/example.xml");\r
+                       BufferedServletInputStream is = new BufferedServletInputStream(fis);\r
+                       try {\r
+                               is.mark(1536);\r
+                               try {\r
+                                       assertNull(wp.parse(bc, is));\r
+                               } finally {\r
+                                       is.reset();\r
+                                       assertEquals(814,is.buffered());\r
+                               }\r
+                               String password = new String(bc.getCred());\r
+                               System.out.println("CadiWrap credentials are: " + bc.getUser() + ", " + password);\r
+                               assertEquals("some_user", bc.getUser());\r
+                               assertEquals("some_password", password);\r
+                               \r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+\r
+                       // CBUS (larger)\r
+                       fis = new FileInputStream("test/CBUSevent.xml");\r
+                       is = new BufferedServletInputStream(fis);\r
+                       try {\r
+                               is.mark(1536);\r
+                               try {\r
+                                       assertNull(wp.parse(bc, is));\r
+                               } finally {\r
+                                       is.reset();\r
+                                       assertEquals(667,is.buffered());\r
+                               }\r
+                               String password = new String(bc.getCred());\r
+                               System.out.println("CadiWrap credentials are: " + bc.getUser() + ", " + password);\r
+                               assertEquals("none", bc.getUser());\r
+                               assertEquals("none", password);\r
+                               \r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+\r
+                       // Closed Stream\r
+                       fis = new FileInputStream("test/example.xml");\r
+                       fis.close();\r
+                       bc.setCred(null);\r
+                       bc.setUser(null);\r
+                       XMLStreamException ex = wp.parse(bc, fis);\r
+                       assertNotNull(ex);\r
+                       assertNull(bc.getUser());\r
+                       assertNull(bc.getCred());\r
+\r
+\r
+                       fis = new FileInputStream("test/exampleNoSecurity.xml");\r
+                       try {\r
+                               bc.setCred(null);\r
+                               bc.setUser(null);\r
+                               assertNull(wp.parse(bc, fis));\r
+                               assertNull(bc.getUser());\r
+                               assertNull(bc.getCred());\r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+\r
+                       fis = new FileInputStream("test/exampleBad1.xml");\r
+                       try {\r
+                               bc.setCred(null);\r
+                               bc.setUser(null);\r
+                               assertNull(wp.parse(bc, fis));\r
+                               assertNull(bc.getUser());\r
+                               assertNull(bc.getCred());\r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+\r
+                       XMLStreamException e = wp.parse(bc, new ByteArrayInputStream("Not XML".getBytes())); // empty\r
+                       assertNotNull(e);\r
+\r
+                       e = wp.parse(bc, new ByteArrayInputStream("".getBytes())); // empty\r
+                       assertNotNull(e);\r
+                       \r
+                       \r
+                       long start, count = 0L;\r
+                       int iter = 30000;\r
+                       File f = new File("test/CBUSevent.xml");\r
+                       fis = new FileInputStream(f);\r
+                       is = new BufferedServletInputStream(fis);\r
+                       is.mark(0);\r
+                       try {\r
+                               while(is.read()>=0);\r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+\r
+                       for(int i=0;i<iter;++i) {\r
+                               start = System.nanoTime();\r
+                               is.reset();\r
+                               try {\r
+                                       assertNull(wp.parse(bc, is));\r
+                               } finally {\r
+                                       count += System.nanoTime()-start;\r
+                               }\r
+                       }\r
+                       float ms = count/1000000f;\r
+                       System.out.println("Executed " + iter + " WSSE reads from Memory Stream in " + ms + "ms.  " + ms/iter + "ms per trans");\r
+                       \r
+                       // SPECIFIC ISSUES\r
+                       \r
+                       fis = new FileInputStream("test/error2013_04_23.xml");\r
+                       try {\r
+                               bc.setCred(null);\r
+                               bc.setUser(null);\r
+                               assertNull(wp.parse(bc, fis));\r
+                               assertNull(bc.getUser());\r
+                               assertNull(bc.getCred());\r
+                       } finally {\r
+                               fis.close();\r
+                       }\r
+               } catch(Exception e) {\r
+                       e.printStackTrace(System.err);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/core/src/test/java/com/att/cadi/wsse/test/JU_XReader.java b/core/src/test/java/com/att/cadi/wsse/test/JU_XReader.java
new file mode 100644 (file)
index 0000000..7f38d94
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.cadi.wsse.test;\r
+\r
+import java.io.FileInputStream;\r
+\r
+import javax.xml.stream.events.XMLEvent;\r
+\r
+import org.junit.Test;\r
+\r
+import com.att.cadi.wsse.XEvent;\r
+import com.att.cadi.wsse.XReader;\r
+\r
+public class JU_XReader {\r
+       @Test\r
+       public void test() throws Exception {\r
+               FileInputStream fis = new FileInputStream("test/CBUSevent.xml");\r
+               try {\r
+                       XReader xr = new XReader(fis);\r
+                       while(xr.hasNext()) {\r
+                               XEvent xe = xr.nextEvent();\r
+                               switch(xe.getEventType()) {\r
+                                       case XMLEvent.START_DOCUMENT:\r
+                                               System.out.println("Start Document");\r
+                                               break;\r
+                                       case XMLEvent.START_ELEMENT:\r
+                                               System.out.println("Start Event: " + xe.asStartElement().getName());\r
+                                               break;\r
+                                       case XMLEvent.END_ELEMENT:\r
+                                               System.out.println("End Event: " + xe.asEndElement().getName());\r
+                                               break;\r
+                                       case XMLEvent.CHARACTERS:\r
+                                               System.out.println("Characters: " + xe.asCharacters().getData());\r
+                                               break;\r
+                                       case XMLEvent.COMMENT:\r
+                                               System.out.println("Comment: " + ((XEvent.Comment)xe).value);\r
+                                               break;\r
+                               }\r
+                       }\r
+               } finally {\r
+                       fis.close();\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..2d45047
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,480 @@
+<!--
+  ============LICENSE_START====================================================
+  * org.onap.aai
+  * ===========================================================================
+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+  * Copyright © 2017 Amdocs
+  * ===========================================================================
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at
+  * 
+   *      http://www.apache.org/licenses/LICENSE-2.0
+  * 
+   * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  * ============LICENSE_END====================================================
+  *
+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+  *
+-->
+<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>
+       <groupId>com.att.cadi</groupId>
+       <artifactId>parent</artifactId>
+       <name>CADI Parent POM (Code, Access, Data, Identity)</name>
+       <version>1.3.2</version>
+       <inceptionYear>2015-07-20</inceptionYear>       
+       <packaging>pom</packaging>
+       <url>https://github.com/att/AAF</url>
+       <description>CADI</description>
+       <licenses>
+               <license>
+               <name>BSD License</name>
+               <url> </url>
+               </license>
+       </licenses>
+       <developers>
+               <developer>
+               <name>Jonathan Gathman</name>
+               <email></email>
+       <organization>ATT</organization>
+       <organizationUrl></organizationUrl>
+               </developer>
+       </developers>
+       <properties>
+               <skipSigning>true</skipSigning>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <project.innoVersion>1.2.13</project.innoVersion>
+               <project.authClientVersion>2.6</project.authClientVersion>
+               <project.dme2Version>3.1.200</project.dme2Version>
+                               <!-- version>2.8.5.8</version -->
+                               <!-- version>2.6.20</version -->
+                               <!-- version>2.6.29</version -->
+                               <!-- version>2.8.1</version -->
+                               <!--  version>2.8.2.5</version -->
+               <!-- jetty-version>8.1.7.v20120910</jetty-version -->
+               <!-- jetty-version>7.2.0.v20101020</jetty-version -->
+               <!-- project.jettyVersion>9.0.3.v20130506</project.jettyVersion -->
+       </properties>
+
+       <!-- ============================================================== -->
+       <!-- Define the major contributors and developers of CADI -->
+       <!-- ============================================================== -->
+       <contributors>
+               <contributor>
+                       <name>Jonathan Gathman</name>
+                       <email></email>
+                       <timezone>CST</timezone>
+               </contributor>
+       </contributors>
+
+       <dependencies>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.10</version>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+
+       <!-- ============================================================== -->
+       <!-- Define sub-projects (modules) -->
+       <!-- ============================================================== -->
+       <modules>
+               <module>core</module>
+               <module>client</module>
+               <module>aaf</module> 
+               <module>cass</module>
+               <!-- module>jetty</module -->
+               <!-- module>weblogic</module -->
+               <!-- always build last -->
+               <!--module>swm</module -->
+       </modules>
+
+       <!-- ============================================================== -->
+       <!-- Define project-wide dependencies -->
+       <!-- ============================================================== -->
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>com.att.authz</groupId>
+                               <artifactId>authz-client</artifactId>
+                               <version>${project.authClientVersion}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-core</artifactId>
+                               <version>${project.version}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-core</artifactId>
+                               <version>${project.version}</version>
+                               <classifier>tests</classifier>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-cass</artifactId>
+                               <version>${project.version}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-aaf</artifactId>
+                               <version>${project.version}</version>
+                       </dependency> 
+
+                   <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-aaf</artifactId>
+                               <version>${project.version}</version>
+                               <classifier>full</classifier>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-client</artifactId>
+                               <version>${project.version}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-tomcat</artifactId>
+                               <version>${project.version}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.cadi</groupId>
+                               <artifactId>cadi-tguard</artifactId>
+                               <version>${project.version}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.inno</groupId>
+                               <artifactId>env</artifactId>
+                               <version>${project.innoVersion}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.inno</groupId>
+                               <artifactId>rosetta</artifactId>
+                               <version>${project.innoVersion}</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-servlet</artifactId>
+                               <version>9.0.3.v20130506</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-webapp</artifactId>
+                               <version>9.0.3.v20130506</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>org.eclipse.jetty.aggregate</groupId>
+                               <artifactId>jetty-all</artifactId>
+                               <version>9.0.3.v20130506</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>javax.servlet</groupId>
+                               <artifactId>servlet-api</artifactId>
+                               <version>2.5</version>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>com.att.aft</groupId>
+                               <artifactId>dme2</artifactId>
+                               <version>${project.dme2Version}</version>
+                               <exclusions>
+                                       <exclusion>
+                                               <groupId>org.slf4j</groupId>
+                                               <artifactId>slf4j-log4j12</artifactId>
+                                       </exclusion>
+                                       <exclusion>
+                                               <groupId>log4j</groupId>
+                                               <artifactId>log4j</artifactId>
+                                       </exclusion>
+                                       <exclusion>
+                                               <groupId>com.att.javax.servlet</groupId>
+                                               <artifactId>servlet-api</artifactId>
+                                       </exclusion>
+                                       <exclusion>
+                                               <groupId>javax.mail</groupId>
+                                               <artifactId>mail</artifactId>
+                                       </exclusion>
+
+                               </exclusions>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>org.slf4j</groupId>
+                               <artifactId>slf4j-api</artifactId>
+                               <version>1.7.5</version>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+
+       <!-- ============================================================== -->
+       <!-- Define common plugins and make them available for all modules -->
+       <!-- ============================================================== -->
+       <build>
+               <testSourceDirectory>src/test/java</testSourceDirectory>
+               <plugins>
+
+                               <plugin>
+                                       <inherited>true</inherited>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-compiler-plugin</artifactId>
+                                       <version>2.3.2</version>
+                                       <configuration>
+                                               <source>1.7</source>
+                                               <target>1.7</target>
+                                       </configuration>
+                               </plugin>
+       
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <version>2.4</version>
+                                       <artifactId>maven-jar-plugin</artifactId>
+                                       <configuration>
+                                               <outputDirectory>target</outputDirectory>
+                                               <archive>
+                                                       <manifestEntries>
+                                                               <Sealed>true</Sealed>
+                                                       </manifestEntries>
+                                               </archive>
+                                       </configuration>
+                               </plugin>
+                               
+                               <plugin>
+                                 <groupId>org.apache.maven.plugins</groupId>
+                                 <artifactId>maven-surefire-plugin</artifactId>
+                                 <version>2.17</version>
+                                 <configuration>
+                                       <skipTests>false</skipTests>
+                                       <includes>
+                                         <include>**/JU*.java</include>
+                                       </includes>
+                                       <excludes>
+                                               <exclude>**/JU_LocalLur.java</exclude>
+                                               <exclude>**/JU_BufferedServletInputStream.java</exclude>
+                                               <exclude>**/JU_Passcode.java</exclude>
+                                               <exclude>**/JU_XReader.java</exclude>
+                                               <exclude>**/JU_CASS.java</exclude>
+                                               <exclude>**/JU_PropertyLocator.java</exclude>
+                                               <exclude>**/JU_PermEval.java</exclude>
+                                               <exclude>**/JU_JMeter.java</exclude>
+                                               <exclude>**/JU_Lur2_0Call.java</exclude>
+                                       </excludes>
+                                 </configuration>
+                               </plugin>
+
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-jarsigner-plugin</artifactId>
+                                       <version>1.2</version>
+                                       <executions>
+                                               <execution>
+                                                       <id>sign</id>
+                                                       <goals>
+                                                               <goal>sign</goal>
+                                                       </goals>
+                                                       <configuration>
+                                                               <!--  skip>${skipSigning}</skip -->
+                                                               <archive>target/${project.artifactId}-${project.version}.jar</archive>
+                                                       </configuration>
+                                               </execution>
+                                               <execution>
+                                                       <id>verify</id>
+                                                       <goals>
+                                                               <goal>verify</goal>
+                                                       </goals>
+                                                       <configuration>
+                                                               <archive>target/${project.artifactId}-${project.version}.jar</archive>
+                                                       </configuration>
+                                               </execution>
+                                       </executions>
+                                       <configuration>
+                                               <skip>true</skip>
+                                               <alias>cadi</alias>
+                                               <keystore>/Volumes/Data/src/cadi/keys/aaf_cadi.jks</keystore>
+                                               <storepass>Surprise!</storepass>
+                                               <keypass>Surprise!</keypass>
+                                               <verbose>true</verbose>
+                                               <certs>true</certs>
+                                       </configuration>
+                               </plugin>
+               
+       
+       
+                               <!-- Define the javadoc plugin -->
+                               <!-- <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-javadoc-plugin</artifactId>
+                                       <version>2.10</version>
+                                       <configuration>
+                                               <excludePackageNames>org.opendaylight.*</excludePackageNames>
+                                       </configuration>
+                               </plugin> -->
+       
+                               <plugin>
+                                       <artifactId>maven-release-plugin</artifactId>
+                                       <version>2.5.2</version>
+                                       <configuration>
+                                               <goals>-s ${mvn.settings} deploy</goals>
+                                       </configuration>
+                               </plugin>
+       
+                               <plugin>
+                                       <artifactId>maven-assembly-plugin</artifactId>
+                                       <version>2.5.5</version>
+                               </plugin>
+       
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-deploy-plugin</artifactId>
+                                       <version>2.8.1</version>
+                                       <configuration>
+                                               <skip>false</skip>
+                                       </configuration>
+       
+                               </plugin>
+       
+                               <plugin>
+                                       <groupId>org.apache.maven.plugins</groupId>
+                                       <artifactId>maven-dependency-plugin</artifactId>
+                                       <version>2.10</version>
+                               </plugin>
+                               
+                               <plugin>
+                       <groupId>org.apache.maven.plugins</groupId>
+                       <artifactId>maven-javadoc-plugin</artifactId>
+                                       <configuration>
+                       <failOnError>false</failOnError>
+                       </configuration>
+                       <executions>
+                               <execution>
+                                       <id>attach-javadocs</id>
+                                       <goals>
+                                               <goal>jar</goal>
+                                       </goals>
+                               </execution>
+                       </executions>
+               </plugin> 
+          
+          
+              <plugin>
+                     <groupId>org.apache.maven.plugins</groupId>
+                     <artifactId>maven-source-plugin</artifactId>
+                     <version>2.2.1</version>
+                     <executions>
+                       <execution>
+                         <id>attach-sources</id>
+                         <goals>
+                           <goal>jar-no-fork</goal>
+                         </goals>
+                       </execution>
+                     </executions>
+                   </plugin>
+       
+               <plugin>
+                       <groupId>org.sonatype.plugins</groupId>
+                       <artifactId>nexus-staging-maven-plugin</artifactId>
+                       <version>1.6.7</version>
+                       <extensions>true</extensions>
+                       <configuration>
+                       <serverId>ossrhdme</serverId>
+                       <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+                       <autoReleaseAfterClose>true</autoReleaseAfterClose>
+                       </configuration>
+               </plugin>
+                       
+               <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>cobertura-maven-plugin</artifactId>
+                               <version>2.7</version>
+                               <configuration>
+                                       <formats>
+                                       <format>html</format>
+                                       <format>xml</format>
+                                 </formats>
+                               </configuration>
+                </plugin>
+       
+                               <!-- Maven surefire plugin for testing -->
+                               <plugin>
+                                       <artifactId>maven-surefire-plugin</artifactId>
+                                       <version>2.17</version>
+                               </plugin>
+                               
+                               
+                               
+                               <!--This plugin's configuration is used to store Eclipse m2e settings 
+                                       only. It has no influence on the Maven build itself. -->
+                               <plugin>
+                                       <groupId>org.eclipse.m2e</groupId>
+                                       <artifactId>lifecycle-mapping</artifactId>
+                                       <version>1.0.0</version>
+                                       <configuration>
+                                               <lifecycleMappingMetadata>
+                                                       <pluginExecutions>
+                                                               <pluginExecution>
+                                                                       <pluginExecutionFilter>
+                                                                               <groupId>
+                                                                                       org.codehaus.mojo
+                                                                               </groupId>
+                                                                               <artifactId>
+                                                                                       jaxb2-maven-plugin
+                                                                               </artifactId>
+                                                                               <versionRange>
+                                                                                       [1.3,)
+                                                                               </versionRange>
+                                                                               <goals>
+                                                                                       <goal>xjc</goal>
+                                                                               </goals>
+                                                                       </pluginExecutionFilter>
+                                                                       <action>
+                                                                               <ignore />
+                                                                       </action>
+                                                               </pluginExecution>
+                                                       </pluginExecutions>
+                                               </lifecycleMappingMetadata>
+                                       </configuration>
+                               </plugin>
+                               
+                       </plugins>                      
+       </build>
+
+
+       <!-- ============================================================== -->
+       <!-- Maven Central Repository Information -->
+       <!-- ============================================================== -->
+       
+       <scm>
+               <connection>https://github.com/att/AAF.git</connection>
+               <developerConnection>${project.scm.connection}</developerConnection>
+               <url>http://github.com/att/AAF/tree/master</url>
+       </scm>
+<distributionManagement>
+               <snapshotRepository>
+                       <id>ossrhdme</id>
+                       <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+               </snapshotRepository>
+               <repository>
+                       <id>ossrhdme</id>
+                       <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+               </repository>
+       </distributionManagement>
+</project>