summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsg481n <sg481n@att.com>2017-08-03 17:39:12 -0400
committersg481n <sg481n@att.com>2017-08-03 17:39:12 -0400
commit4a51a8f96715ffb2a42189b93b9fa91b453b8530 (patch)
treeb028ce9e44920addba4194643db5b1c115a00e1a
parent81ad32335f59a3169c032139fb77148b247ed7f0 (diff)
 [AAF-21] Initial code import
Change-Id: Ia1dd196befd061f6ba0c2be6bf4456a30ea50f97 Signed-off-by: sg481n <sg481n@att.com>
-rw-r--r--aaf/.gitignore5
-rw-r--r--aaf/pom.xml189
-rw-r--r--aaf/src/assemble/cadi-aaf-test.xml110
-rw-r--r--aaf/src/assemble/cadi-aaf.xml53
-rw-r--r--aaf/src/main/java/Examples.java42
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java106
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java88
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java459
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/PermEval.java150
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java179
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java98
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/client/Examples.java445
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java67
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java46
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java207
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java396
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java224
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java187
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java221
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java168
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java116
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java269
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java288
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/CertException.java47
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/CmAgent.java711
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/Factory.java449
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java34
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java54
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java130
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java53
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java139
-rw-r--r--aaf/src/main/java/com/att/cadi/sso/AAFSSO.java286
-rw-r--r--aaf/src/src/assemble/cadi-aaf-test.xml110
-rw-r--r--aaf/src/src/assemble/cadi-aaf.xml53
-rw-r--r--aaf/src/src/main/java/Examples.java42
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/AAFPermission.java107
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/AAFTransmutate.java84
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/PermEval.java145
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/client/ErrMessage.java98
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/client/Examples.java445
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java67
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java46
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java197
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java279
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java158
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java148
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java199
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java199
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java91
-rw-r--r--aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java275
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/ArtifactDir.java273
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/CertException.java47
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/CmAgent.java787
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/Factory.java447
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifact.java34
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java54
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java150
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java53
-rw-r--r--aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java124
-rw-r--r--aaf/src/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java117
-rw-r--r--aaf/src/src/test/resources/cadi.properties53
-rw-r--r--aaf/src/src/test/resources/log4j.properties58
-rw-r--r--aaf/src/src/test/resources/logging.props38
-rw-r--r--aaf/src/test/java/com/att/aaf/content/JU_Content.java84
-rw-r--r--aaf/src/test/java/com/att/aaf/example/CadiTest.java59
-rw-r--r--aaf/src/test/java/com/att/aaf/example/ExampleAuthCheck.java58
-rw-r--r--aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0.java114
-rw-r--r--aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0_DME2.java114
-rw-r--r--aaf/src/test/java/com/att/aaf/example/X509Test.java90
-rw-r--r--aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_JMeter.java146
-rw-r--r--aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_Lur2_0Call.java576
-rw-r--r--aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_PermEval.java109
-rw-r--r--aaf/src/test/java/com/att/cadi/lur/aaf/test/MultiThreadPermHit.java146
-rw-r--r--aaf/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java123
-rw-r--r--aaf/src/test/resources/cadi.properties53
-rw-r--r--aaf/src/test/resources/log4j.properties58
-rw-r--r--aaf/src/test/resources/logging.props38
-rw-r--r--cass/.gitignore5
-rw-r--r--cass/etc/cadi.properties69
-rw-r--r--cass/pom.xml115
-rw-r--r--cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticatedUser.java112
-rw-r--r--cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticator.java176
-rw-r--r--cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthorizer.java228
-rw-r--r--cass/src/main/java/com/att/cadi/aaf/cass/AAFBase.java193
-rw-r--r--cass/src/test/java/com/att/aaf/cass/JU_CASS.java108
-rw-r--r--cass/src/test/java/com/att/cadi/aaf/cass/test/JU_CASS.java108
-rw-r--r--client/.gitignore5
-rw-r--r--client/pom.xml108
-rw-r--r--client/src/main/java/com/att/cadi/client/AAFClient.java199
-rw-r--r--client/src/main/java/com/att/cadi/client/AbsBasicAuth.java94
-rw-r--r--client/src/main/java/com/att/cadi/client/AbsTransferSS.java74
-rw-r--r--client/src/main/java/com/att/cadi/client/Delete.java71
-rw-r--r--client/src/main/java/com/att/cadi/client/EClient.java53
-rw-r--r--client/src/main/java/com/att/cadi/client/EnvAccess.java168
-rw-r--r--client/src/main/java/com/att/cadi/client/Future.java35
-rw-r--r--client/src/main/java/com/att/cadi/client/Get.java49
-rw-r--r--client/src/main/java/com/att/cadi/client/Holder.java45
-rw-r--r--client/src/main/java/com/att/cadi/client/Post.java50
-rw-r--r--client/src/main/java/com/att/cadi/client/PropertyLocator.java144
-rw-r--r--client/src/main/java/com/att/cadi/client/Put.java65
-rw-r--r--client/src/main/java/com/att/cadi/client/RawClient.java159
-rw-r--r--client/src/main/java/com/att/cadi/client/Rcli.java697
-rw-r--r--client/src/main/java/com/att/cadi/client/Result.java58
-rw-r--r--client/src/main/java/com/att/cadi/client/Retryable.java72
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DEClient.java223
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java64
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java65
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2Locator.java349
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java56
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2x509SS.java68
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DRcli.java142
-rw-r--r--client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java168
-rw-r--r--client/src/main/java/com/att/cadi/http/HBasicAuthSS.java77
-rw-r--r--client/src/main/java/com/att/cadi/http/HClient.java434
-rw-r--r--client/src/main/java/com/att/cadi/http/HMangr.java236
-rw-r--r--client/src/main/java/com/att/cadi/http/HRcli.java134
-rw-r--r--client/src/main/java/com/att/cadi/http/HTransferSS.java66
-rw-r--r--client/src/main/java/com/att/cadi/http/HX509SS.java168
-rw-r--r--client/src/main/java/com/att/cadi/locator/DME2Locator.java346
-rw-r--r--client/src/main/java/com/att/cadi/locator/DNSLocator.java164
-rw-r--r--client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java62
-rw-r--r--client/src/main/java/com/att/cadi/locator/HotPeerLocator.java304
-rw-r--r--client/src/main/java/com/att/cadi/locator/PropertyLocator.java282
-rw-r--r--client/src/main/java/com/att/cadi/routing/GreatCircle.java190
-rw-r--r--client/src/test/java/com/client/test/BasicDME2Client.java62
-rw-r--r--client/src/test/java/com/client/test/JU_DNSLocator.java58
-rw-r--r--client/src/test/java/com/client/test/JU_PropertyLocator.java99
-rw-r--r--client/src/test/java/com/client/test/PaulUzee.java146
-rw-r--r--client/src/test/java/com/client/test/TestAccess.java91
-rw-r--r--client/src/test/java/com/client/test/TestDME2Client.java98
-rw-r--r--client/src/test/java/com/client/test/TestDME2RcliClient.java79
-rw-r--r--client/src/test/java/com/client/test/TestHClient.java84
-rw-r--r--core/.gitignore5
-rw-r--r--core/conf/cadi.properties60
-rw-r--r--core/pom.xml131
-rw-r--r--core/src/assemble/cadi.xml47
-rw-r--r--core/src/assemble/poll.xml47
-rw-r--r--core/src/main/java/com/att/cadi/AES.java128
-rw-r--r--core/src/main/java/com/att/cadi/AbsCachedPrincipal.java34
-rw-r--r--core/src/main/java/com/att/cadi/AbsUserCache.java409
-rw-r--r--core/src/main/java/com/att/cadi/Access.java173
-rw-r--r--core/src/main/java/com/att/cadi/BasicCred.java37
-rw-r--r--core/src/main/java/com/att/cadi/BufferedCadiWrap.java81
-rw-r--r--core/src/main/java/com/att/cadi/BufferedServletInputStream.java215
-rw-r--r--core/src/main/java/com/att/cadi/CachedPrincipal.java48
-rw-r--r--core/src/main/java/com/att/cadi/CachingLur.java36
-rw-r--r--core/src/main/java/com/att/cadi/CadiException.java51
-rw-r--r--core/src/main/java/com/att/cadi/CadiWrap.java194
-rw-r--r--core/src/main/java/com/att/cadi/Capacitor.java241
-rw-r--r--core/src/main/java/com/att/cadi/CmdLine.java357
-rw-r--r--core/src/main/java/com/att/cadi/Connector.java28
-rw-r--r--core/src/main/java/com/att/cadi/CredVal.java43
-rw-r--r--core/src/main/java/com/att/cadi/GetCred.java28
-rw-r--r--core/src/main/java/com/att/cadi/Hash.java203
-rw-r--r--core/src/main/java/com/att/cadi/Locator.java37
-rw-r--r--core/src/main/java/com/att/cadi/LocatorException.java48
-rw-r--r--core/src/main/java/com/att/cadi/Lur.java95
-rw-r--r--core/src/main/java/com/att/cadi/Permission.java30
-rw-r--r--core/src/main/java/com/att/cadi/PropAccess.java321
-rw-r--r--core/src/main/java/com/att/cadi/Revalidator.java36
-rw-r--r--core/src/main/java/com/att/cadi/SLF4JAccess.java101
-rw-r--r--core/src/main/java/com/att/cadi/SecuritySetter.java45
-rw-r--r--core/src/main/java/com/att/cadi/ServletContextAccess.java70
-rw-r--r--core/src/main/java/com/att/cadi/StrLur.java57
-rw-r--r--core/src/main/java/com/att/cadi/Symm.java812
-rw-r--r--core/src/main/java/com/att/cadi/Taf.java58
-rw-r--r--core/src/main/java/com/att/cadi/Transmutate.java46
-rw-r--r--core/src/main/java/com/att/cadi/TrustChecker.java54
-rw-r--r--core/src/main/java/com/att/cadi/User.java145
-rw-r--r--core/src/main/java/com/att/cadi/UserChain.java44
-rw-r--r--core/src/main/java/com/att/cadi/config/Config.java815
-rw-r--r--core/src/main/java/com/att/cadi/config/Get.java98
-rw-r--r--core/src/main/java/com/att/cadi/config/GetAccess.java64
-rw-r--r--core/src/main/java/com/att/cadi/config/MultiGet.java44
-rw-r--r--core/src/main/java/com/att/cadi/config/SecurityInfo.java244
-rw-r--r--core/src/main/java/com/att/cadi/config/SecurityInfoC.java45
-rw-r--r--core/src/main/java/com/att/cadi/config/UsersDump.java159
-rw-r--r--core/src/main/java/com/att/cadi/filter/AUTHZ.java38
-rw-r--r--core/src/main/java/com/att/cadi/filter/AUTHZServlet.java101
-rw-r--r--core/src/main/java/com/att/cadi/filter/AccessGetter.java38
-rw-r--r--core/src/main/java/com/att/cadi/filter/CadiAccess.java244
-rw-r--r--core/src/main/java/com/att/cadi/filter/CadiFilter.java306
-rw-r--r--core/src/main/java/com/att/cadi/filter/CadiHTTPManip.java228
-rw-r--r--core/src/main/java/com/att/cadi/filter/FCGet.java78
-rw-r--r--core/src/main/java/com/att/cadi/filter/MapPermConverter.java56
-rw-r--r--core/src/main/java/com/att/cadi/filter/NullPermConverter.java44
-rw-r--r--core/src/main/java/com/att/cadi/filter/PathFilter.java184
-rw-r--r--core/src/main/java/com/att/cadi/filter/PermConverter.java33
-rw-r--r--core/src/main/java/com/att/cadi/filter/RolesAllowed.java56
-rw-r--r--core/src/main/java/com/att/cadi/filter/ServletImpl.java56
-rw-r--r--core/src/main/java/com/att/cadi/lur/ConfigPrincipal.java71
-rw-r--r--core/src/main/java/com/att/cadi/lur/EpiLur.java168
-rw-r--r--core/src/main/java/com/att/cadi/lur/LocalLur.java202
-rw-r--r--core/src/main/java/com/att/cadi/lur/LocalPermission.java52
-rw-r--r--core/src/main/java/com/att/cadi/lur/NullLur.java89
-rw-r--r--core/src/main/java/com/att/cadi/principal/BasicPrincipal.java118
-rw-r--r--core/src/main/java/com/att/cadi/principal/BearerPrincipal.java37
-rw-r--r--core/src/main/java/com/att/cadi/principal/CSPPrincipal_T.java34
-rw-r--r--core/src/main/java/com/att/cadi/principal/CachedBasicPrincipal.java66
-rw-r--r--core/src/main/java/com/att/cadi/principal/TGuardPrincipal.java81
-rw-r--r--core/src/main/java/com/att/cadi/principal/TGuardPrincipal_T.java34
-rw-r--r--core/src/main/java/com/att/cadi/principal/TrustPrincipal.java68
-rw-r--r--core/src/main/java/com/att/cadi/principal/X509Principal.java93
-rw-r--r--core/src/main/java/com/att/cadi/taf/AbsTafResp.java117
-rw-r--r--core/src/main/java/com/att/cadi/taf/EpiTaf.java85
-rw-r--r--core/src/main/java/com/att/cadi/taf/HttpEpiTaf.java186
-rw-r--r--core/src/main/java/com/att/cadi/taf/HttpTaf.java61
-rw-r--r--core/src/main/java/com/att/cadi/taf/LoginPageTafResp.java88
-rw-r--r--core/src/main/java/com/att/cadi/taf/NullTaf.java65
-rw-r--r--core/src/main/java/com/att/cadi/taf/NullTafResp.java74
-rw-r--r--core/src/main/java/com/att/cadi/taf/PuntTafResp.java72
-rw-r--r--core/src/main/java/com/att/cadi/taf/Redirectable.java33
-rw-r--r--core/src/main/java/com/att/cadi/taf/TafResp.java95
-rw-r--r--core/src/main/java/com/att/cadi/taf/TrustNotTafResp.java78
-rw-r--r--core/src/main/java/com/att/cadi/taf/TrustTafResp.java80
-rw-r--r--core/src/main/java/com/att/cadi/taf/basic/BasicHttpTaf.java160
-rw-r--r--core/src/main/java/com/att/cadi/taf/basic/BasicHttpTafResp.java64
-rw-r--r--core/src/main/java/com/att/cadi/taf/cert/CertIdentity.java47
-rw-r--r--core/src/main/java/com/att/cadi/taf/cert/X509HttpTafResp.java53
-rw-r--r--core/src/main/java/com/att/cadi/taf/cert/X509Taf.java258
-rw-r--r--core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTaf.java371
-rw-r--r--core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTafResp.java49
-rw-r--r--core/src/main/java/com/att/cadi/taf/localhost/LocalhostTaf.java131
-rw-r--r--core/src/main/java/com/att/cadi/taf/localhost/LocalhostTafResp.java82
-rw-r--r--core/src/main/java/com/att/cadi/util/Chmod.java64
-rw-r--r--core/src/main/java/com/att/cadi/util/JsonOutputStream.java91
-rw-r--r--core/src/main/java/com/att/cadi/util/MaskFormatException.java33
-rw-r--r--core/src/main/java/com/att/cadi/util/MyConsole.java30
-rw-r--r--core/src/main/java/com/att/cadi/util/NetMask.java101
-rw-r--r--core/src/main/java/com/att/cadi/util/Split.java92
-rw-r--r--core/src/main/java/com/att/cadi/util/SubStandardConsole.java64
-rw-r--r--core/src/main/java/com/att/cadi/util/TheConsole.java49
-rw-r--r--core/src/main/java/com/att/cadi/util/UserChainManip.java79
-rw-r--r--core/src/main/java/com/att/cadi/util/Vars.java122
-rw-r--r--core/src/main/java/com/att/cadi/wsse/Action.java38
-rw-r--r--core/src/main/java/com/att/cadi/wsse/Match.java131
-rw-r--r--core/src/main/java/com/att/cadi/wsse/WSSEParser.java87
-rw-r--r--core/src/main/java/com/att/cadi/wsse/XEvent.java136
-rw-r--r--core/src/main/java/com/att/cadi/wsse/XReader.java417
-rw-r--r--core/src/test/java/com/att/cadi/JU_AES.java87
-rw-r--r--core/src/test/java/com/att/cadi/lur/test/JU_LocalLur.java102
-rw-r--r--core/src/test/java/com/att/cadi/lur/test/TestAccess.java92
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_Base64.java158
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_BufferedServletInputStream.java192
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_Capacitor.java145
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_Hash.java62
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_Passcode.java91
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_UserChainManip.java49
-rw-r--r--core/src/test/java/com/att/cadi/test/JU_Vars.java127
-rw-r--r--core/src/test/java/com/att/cadi/test/Test.java71
-rw-r--r--core/src/test/java/com/att/cadi/wsse/test/JU_WSSE_Read.java192
-rw-r--r--core/src/test/java/com/att/cadi/wsse/test/JU_XReader.java67
-rw-r--r--pom.xml480
253 files changed, 34674 insertions, 0 deletions
diff --git a/aaf/.gitignore b/aaf/.gitignore
new file mode 100644
index 0000000..cf85207
--- /dev/null
+++ b/aaf/.gitignore
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/aaf/pom.xml b/aaf/pom.xml
new file mode 100644
index 0000000..9673067
--- /dev/null
+++ b/aaf/pom.xml
@@ -0,0 +1,189 @@
+<!--
+ ============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">
+ <parent>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.3.2</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <name>CADI AAF (Application Authorization Framework) LUR</name>
+ <packaging>jar</packaging>
+ <url>https://github.com/att/AAF</url>
+ <description>CADI</description>
+ <artifactId>cadi-aaf</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>com.att.authz</groupId>
+ <artifactId>authz-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>cadi-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>cadi-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.att.aft</groupId>
+ <artifactId>dme2</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.0.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.7.5</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ </plugin>
+
+ <!-- We want to create a Jar with Rosetta built in (since I don't want
+ a separate deployment at this time Use this one as the jar to put in SWM
+ packages -->
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <classifier>tests</classifier>
+ <archive>
+ <manifest>
+ <mainClass>com.att.cadi.cm.CmAgent</mainClass>
+ </manifest>
+
+ <manifestEntries>
+ <Sealed>true</Sealed>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>full</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>src/assemble/cadi-aaf.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </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>
+ <!-- Also sign "full" -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jarsigner-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <id>sign-full</id>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ <configuration>
+ <archive>target/${project.artifactId}-${project.version}-full.jar</archive>
+ </configuration>
+ </execution>
+ <execution>
+ <id>verify-full</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <archive>target/${project.artifactId}-${project.version}-full.jar</archive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/aaf/src/assemble/cadi-aaf-test.xml b/aaf/src/assemble/cadi-aaf-test.xml
new file mode 100644
index 0000000..a6671ba
--- /dev/null
+++ b/aaf/src/assemble/cadi-aaf-test.xml
@@ -0,0 +1,110 @@
+<!--
+ ============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.
+ *
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>test</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.cadi:cadi-core</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.cadi:cadi-aaf</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>org.eclipse.jetty.aggregate:jetty-all</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>org.eclipse.jetty.orbit:javax.servlet</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>javax:servlet</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.aft:dme2</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.aft.discovery:discovery-clt</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>compile</scope>
+ <includes>
+ <include>com.att.cssa:rosetta</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>run</directory>
+ <includes>
+ <include>cadi.properties</include>
+ <include>keyfile</include>
+ <include>start.sh</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <includes>
+ <include>../cadi/target/cadi-core*tests.jar</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/aaf/src/assemble/cadi-aaf.xml b/aaf/src/assemble/cadi-aaf.xml
new file mode 100644
index 0000000..578037b
--- /dev/null
+++ b/aaf/src/assemble/cadi-aaf.xml
@@ -0,0 +1,53 @@
+<!--
+ ============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.
+ *
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>full</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <unpack>true</unpack>
+ <scope>compile</scope>
+ <includes>
+ <include>com.att.authz:authz-client</include>
+ <include>com.att.cadi:cadi-aaf</include>
+ <include>com.att.cadi:cadi-core</include>
+ <include>com.att.cadi:cadi-client</include>
+ <include>com.att.inno:env</include>
+ <include>com.att.inno:rosetta</include>
+ </includes>
+ </dependencySet>
+
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>src/main/xsd</directory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/aaf/src/main/java/Examples.java b/aaf/src/main/java/Examples.java
new file mode 100644
index 0000000..91f313f
--- /dev/null
+++ b/aaf/src/main/java/Examples.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+import com.att.rosetta.env.RosettaEnv;
+
+public class Examples {
+ public static void main(String[] args) {
+ if(args.length<1) {
+ System.out.println("Usage: Examples <name> [\"optional\" - will show optional fields]");
+ } else {
+ boolean options = args.length>1&&"optional".equals(args[1]);
+ try {
+ RosettaEnv env = new RosettaEnv();
+ System.out.println(com.att.cadi.aaf.client.Examples.print(env, args[0], options));
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ }
+
+
+}
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
index 0000000..e604053
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import com.att.cadi.Permission;
+
+/**
+ * A Class that understands the AAF format of Permission (name/type/action)
+ * or String "name|type|action"
+ *
+ *
+ */
+public class AAFPermission implements Permission {
+ protected String type,instance,action,key;
+
+ protected AAFPermission() {}
+
+ public AAFPermission(String type, String instance, String action) {
+ this.type = type;
+ this.instance = instance;
+ this.action = action;
+ key = type + '|' + instance + '|' + action;
+ }
+
+ /**
+ * Match a Permission
+ * if Permission is Fielded type "Permission", we use the fields
+ * otherwise, we split the Permission with '|'
+ *
+ * when the type or action starts with REGEX indicator character ( ! ),
+ * then it is evaluated as a regular expression.
+ *
+ * If you want a simple field comparison, it is faster without REGEX
+ */
+ public boolean match(Permission p) {
+ if(p instanceof AAFPermission) {
+ AAFPermission ap = (AAFPermission)p;
+ // Note: In AAF > 1.0, Accepting "*" from name would violate multi-tenancy
+ // Current solution is only allow direct match on Type.
+ // 8/28/2014 - added REGEX ability
+ if(type.equals(ap.getName()))
+ if(PermEval.evalInstance(instance,ap.getInstance()))
+ if(PermEval.evalAction(action,ap.getAction()))
+ return true;
+ } else {
+ // Permission is concatenated together: separated by |
+ String[] aaf = p.getKey().split("[\\s]*\\|[\\s]*",3);
+ if(aaf.length>0 && type.equals(aaf[0]))
+ if(PermEval.evalInstance(instance,aaf.length>1?aaf[1]:"*"))
+ if(PermEval.evalAction(action,aaf.length>2?aaf[2]:"*"))
+ return true;
+ }
+ return false;
+ }
+
+ public String getName() {
+ return type;
+ }
+
+ public String getInstance() {
+ return instance;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Permission#permType()
+ */
+ public String permType() {
+ return "AAF";
+ }
+
+ public String toString() {
+ return "AAFPermission:\n\tType: " + type +
+ "\n\tInstance: " + instance +
+ "\n\tAction: " + action +
+ "\n\tKey: " + key;
+ }
+}
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
index 0000000..a6a9bb7
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import java.security.Principal;
+import java.util.regex.Pattern;
+
+import com.att.cadi.Transmutate;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CSPPrincipal_T;
+
+/**
+ * AAFTransmutate
+ *
+ * Each System determines the mechanisms for which one Principal is transmutated to another, such as whether it is created
+ * independently, etc.
+ *
+ * For AAF, the only important thing is that these are valid ATTUID/mechIDs, to avoid unnecessary user hits
+ *
+ * attUIDs look like ab1234 or AB1234 or AZ123a
+ * mechids look like m12345
+ *
+ *
+ */
+public final class AAFTransmutate implements Transmutate<Principal> {
+ private Pattern pattern = Pattern.compile("[a-zA-Z]\\w\\d\\d\\d\\w");
+
+ public Principal mutate(Principal p) {
+ // Accept these three internal kinds of Principals
+ if(p instanceof CSPPrincipal_T
+ || p instanceof BasicPrincipal
+ || p instanceof ConfigPrincipal) {
+ return p;
+ } else {
+
+ final String name = p.getName();
+ final int idx = name.indexOf('@');
+ String shortName;
+ if(idx>0) { // strip off any domain
+ shortName = name.substring(0,idx);
+ } else {
+ shortName = name;
+ }
+
+ // Check for ATTUID specs before creating CSP_T
+ return pattern.matcher(shortName).matches()?
+ new CSP_T(name): // Note: use REAL name, short name for CSP_T
+ null;
+ }
+ }
+
+ /**
+ * Essential Principal reflecting CSP Principal
+ *
+ *
+ */
+ private final class CSP_T implements CSPPrincipal_T {
+ private String name;
+ public CSP_T(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return name;
+ }
+ }
+}
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
index 0000000..070d48d
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.Date;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConDME2;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HClient;
+import com.att.cadi.http.HX509SS;
+import com.att.cadi.locator.DME2Locator;
+import com.att.cadi.locator.PropertyLocator;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Perms;
+
+public class ConnectivityTest {
+ private static final String PROD = "PROD";
+ private static final String SRV_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=%s/routeOffer=%s";
+ private static final String GW_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.authz-gw/version=2.0/envContext=%s/routeOffer=%s";
+
+ public static void main(String[] args) {
+ if(args.length<2) {
+ System.out.println("Usage: ConnectivityTester <TEST|IST|PROD> <cadi_prop_files>");
+ } else {
+ print(true,"START OF CONNECTIVITY TESTS",new Date().toString(),System.getProperty("user.name"),
+ "Note: All API Calls are /authz/perms/user/<MechID/Alias of the caller>");
+
+ final String aaf_env = args[0];
+ args[1]=Config.CADI_PROP_FILES+'='+args[1];
+
+ PropAccess pa = new PropAccess(args);
+ String user = pa.getProperty(Config.AAF_MECHID);
+ String pass = pa.getProperty(Config.AAF_MECHPASS);
+ String alias = pa.getProperty(Config.CADI_ALIAS);
+ if(user==null) {
+ user=alias;
+ }
+ RosettaEnv env = new RosettaEnv(pa.getProperties());
+
+ try {
+ RosettaDF<Perms> permsDF = env.newDataFactory(Perms.class);
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(pa);
+ HBasicAuthSS hbass = new HBasicAuthSS(pa,si);
+ if(hbass.getID()==null) {
+ hbass=null; // not configured with ID.
+ }
+ HX509SS hxss=null;
+ AAFCon<?> aafcon;
+
+ try {
+ hxss = new HX509SS(user,si);
+ } catch(Exception e) {
+ e.printStackTrace();
+ print(false,"Continuing");
+ }
+ String aafurl;
+ if(user==null || (pass==null && alias==null)) {
+ System.out.printf("ERROR: DME2 Client cannot be tested with out %s and %s properties"
+ , Config.AAF_MECHID, Config.AAF_MECHPASS );
+ } else {
+ if("TEST".equals(aaf_env) || "IST".equals(aaf_env) || "PROD".equals(aaf_env)) {
+ DME2Manager dm = null;
+ print(false,"Attempt DME2Manager Load");
+ if(Class.forName("com.att.aft.dme2.api.DME2Manager")==null) {
+ print(true,"DME2 jar is not available: Skipping DME2 Tests");
+ } else { // DME2 Client Tests
+ pass=pa.decrypt(pass,false);
+ // Out of the box DME2
+ aafurl = String.format(SRV_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");
+ print(true,"TEST CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ print(true,"Find and TEST Connections with DME2Locator",aafurl);
+ DME2Locator dl = new DME2Locator(pa,dm,aafurl);
+ connectTest(dl);
+
+ dm = new DME2Manager("DME2Manager",pa.getProperties());
+
+ dme2RawTest(dm, aafurl,user,pass);
+
+ // URL specific Variant
+ if((aafurl = specificDME2URL(dl, aafurl))!=null) {
+ print(true,"TEST Specific DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ dme2RawTest(dm,aafurl,user,pass);
+ }
+
+ print(true,"CADI Direct AAFConDME2 Object Usage",aafurl);
+ try {
+ pa.setProperty(Config.AAF_URL,aafurl);
+ aafcon = new AAFConDME2(pa);
+ test(aafcon,permsDF,user);
+ } catch(Throwable t) {
+ t.printStackTrace();
+ }
+
+ // find a direct client to code a Direct HTTP with
+ //
+ if(hbass!=null) {
+ print(true,"CADI Http DME2Locator Client Coding Methodology BasicAuth",aafurl);
+ hClientTest(dl,hbass,user);
+ }
+ if(hxss!=null) {
+ print(true,"CADI Http DME2Locator Client Coding Methodology X509",aafurl);
+ hClientTest(dl,hxss,user);
+ }
+
+ // ##### PROXY CHECKS
+ aafurl = String.format(GW_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");
+ print(true,"TEST PROXY DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+
+ dme2RawTest(dm, aafurl,user,pass);
+
+ // URL specific Variant
+ dl = new DME2Locator(pa,dm,aafurl);
+ if((aafurl = specificDME2URL(dl, aafurl))!=null) {
+ print(true,"TEST PROXY Specific DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ dme2RawTest(dm,aafurl,user,pass);
+ }
+ }
+ }
+
+ // Prop Locator
+ PropertyLocator pl = servicePropLocator(aaf_env);
+ connectTest(pl);
+ URI uri = pl.get(pl.best());
+ if(uri!=null) {
+ aafurl = uri.toString();
+ print(true,"TEST Service PropertyLocator based Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ if(hbass!=null) {
+ print(true,"CADI Service Http PropLocator Client Coding Methodology Basic Auth",aafurl);
+ hClientTest(pl,hbass, user);
+ print(true,"CADI Service Http PropLocator Client Coding Methodology /authn/basicAuth",aafurl);
+ basicAuthTest(pl,hbass);
+ }
+ if(hxss!=null) {
+ print(true,"CADI Service Http PropLocator Client Coding Methodology X509",aafurl);
+ hClientTest(pl,hxss, user);
+ }
+ }
+ pl = proxyPropLocator(aaf_env);
+ connectTest(pl);
+ uri = pl.get(pl.best());
+ if(uri!=null) {
+ aafurl = uri.toString();
+ print(true,"TEST PROXY PropertyLocator based Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ if(hbass!=null) {
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology Basic Auth",aafurl);
+ hClientTest(pl,hbass, user);
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology /proxy/authn/basicAuth",aafurl);
+ basicAuthTest(pl,hbass);
+ }
+ if(hxss!=null) {
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology X509",aafurl);
+ hClientTest(pl,hxss, user);
+ }
+ }
+ }
+
+ } catch(Exception e) {
+ e.printStackTrace(System.err);
+ } finally {
+ print(true,"END OF TESTS");
+ }
+ }
+ }
+
+ private static void print(Boolean strong, String ... args) {
+ PrintStream out = System.out;
+ out.println();
+ if(strong) {
+ for(int i=0;i<70;++i) {
+ out.print('=');
+ }
+ out.println();
+ }
+ for(String s : args) {
+ out.print(strong?"== ":"------ ");
+ out.print(s);
+ if(!strong) {
+ out.print(" ------");
+ }
+ out.println();
+ }
+ if(strong) {
+ for(int i=0;i<70;++i) {
+ out.print('=');
+ }
+ }
+ out.println();
+ }
+
+ private static void test(AAFCon<?> aafcon,RosettaDF<Perms> permsDF,String user) {
+ if(aafcon==null) {
+ print(false,"AAFCon is null");
+ } else {
+ try {
+ print(false,"Calling with AAFCon");
+ Future<Perms> fp = aafcon.client("2.0").read("/authz/perms/user/"+user, Perms.class, permsDF);
+ if(fp.get(4000)) {
+ System.out.printf("Found %d Permission(s)\n",fp.value.getPerm().size());
+ } else {
+ System.out.printf("Error: %d %s\n",fp.code(),fp.body());
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ private static AAFCon<?> testConfig(PropAccess pa, String aafurl) {
+ try {
+ pa.setProperty(Config.AAF_URL, aafurl);
+ Lur lur = Config.configLur(pa);
+ Config.configHttpTaf(pa, TrustChecker.NOTRUST, null, lur);
+ if(lur != null) {
+ Field f = null;
+ try {
+ f = lur.getClass().getField("aaf");
+ return (AAFCon<?>)f.get(lur);
+ } catch (Exception nsfe) {
+ }
+ }
+
+ } catch(Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+
+ private static String specificDME2URL(Locator<URI> loc, String aafurl) throws LocatorException {
+ Item item = loc.best();
+ if(item!=null) {
+ URI uri = loc.get(item);
+ return aafurl.replace("DME2RESOLVE", String.format("%s:%d",uri.getHost(),uri.getPort()));
+ }
+ return null;
+ }
+
+ private static void connectTest(Locator<URI> dl) throws LocatorException {
+ URI uri;
+ Socket socket;
+ print(false,"TCP/IP Connect test to all Located Services");
+ for(Item li = dl.first();li!=null;li=dl.next(li)) {
+ if((uri = dl.get(li)) == null) {
+ System.out.println("Locator Item empty");
+ } else {
+ try {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress(uri.getHost(), uri.getPort()),3000);
+ System.out.printf("Can Connect a Socket to %s %d\n",uri.getHost(),uri.getPort());
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.printf("Could not close Socket Connection: %s\n",e1.getMessage());
+ }
+ } catch (IOException e) {
+ System.out.printf("Cannot Connect a Socket to %s %d: %s\n",uri.getHost(),uri.getPort(),e.getMessage());
+ }
+ }
+ }
+ }
+
+ private static PropertyLocator servicePropLocator(String env) throws LocatorException {
+ String purls;
+ switch(env) {
+ case "LOCAL":
+ try {
+ purls="https://"+InetAddress.getLocalHost().getHostName()+":8100";
+ } catch (UnknownHostException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ case "DEV":
+ purls="https://aaf.dev.att.com:8100,https://aaf.dev.att.com:8101";
+ break;
+ case "TEST":
+ purls="https://aaftest.test.att.com:8100,https://aaftest.test.att.com:8101";
+ break;
+ case "IST":
+ purls="https://aafist.test.att.com:8100,https://aafist.test.att.com:8101";
+ break;
+ case PROD:
+ purls="https://aaf.it.att.com:8100,https://aaf.it.att.com:8101";
+ break;
+ default:
+ if(env.contains(".")) {
+ purls="https://"+env+":8100";
+ } else {
+ throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");
+ }
+ }
+ System.out.printf("Creating a PropertyLocator for %s\n",purls);
+ return new PropertyLocator(purls);
+ }
+
+ private static PropertyLocator proxyPropLocator(String env) throws LocatorException {
+ String purls;
+ switch(env) {
+ case "LOCAL":
+ try {
+ purls="https://"+InetAddress.getLocalHost().getHostAddress()+":8100";
+ } catch (UnknownHostException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ case "DEV":
+ purls="https://aaf.dev.att.com:8095/proxy";
+ break;
+ case "TEST":
+ purls="https://aaftest.test.att.com:8095/proxy";
+ break;
+ case "IST":
+ purls="https://aafist.test.att.com:8095/proxy";
+ break;
+ case PROD:
+ purls="https://aaf.it.att.com:8095/proxy";
+ break;
+ default:
+ if(env.contains(".")) {
+ purls="https://"+env+":8095/proxy";
+ } else {
+ throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");
+ }
+
+ }
+ System.out.printf("Creating a PropertyLocator for %s\n",purls);
+ return new PropertyLocator(purls);
+ }
+
+
+
+
+ private static void hClientTest(Locator<URI> dl, SecuritySetter<HttpURLConnection> ss, String user) {
+ try {
+ URI uri = dl.get(dl.best());
+ System.out.println("Resolved to: " + uri);
+ HClient client = new HClient(ss, uri, 3000);
+ client.setMethod("GET");
+ client.setPathInfo("/authz/perms/user/"+user);
+ client.send();
+ Future<String> future = client.futureReadString();
+ if(future.get(7000)) {
+ System.out.println(future.body());
+ } else {
+ System.out.println(future.code() + ":" + future.body());
+ }
+ } catch (CadiException | LocatorException | APIException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static void basicAuthTest(PropertyLocator dl, SecuritySetter<HttpURLConnection> ss) {
+ try {
+ URI uri = dl.get(dl.best());
+ System.out.println("Resolved to: " + uri);
+ HClient client = new HClient(ss, uri, 3000);
+ client.setMethod("GET");
+ client.setPathInfo("/authn/basicAuth");
+ client.addHeader("Accept", "text/plain");
+ client.send();
+
+
+ Future<String> future = client.futureReadString();
+ if(future.get(7000)) {
+ System.out.println("BasicAuth Validated");
+ } else {
+ System.out.println("Failure " + future.code() + ":" + future.body());
+ }
+ } catch (CadiException | LocatorException | APIException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Regular DME2Client Coding Style
+ private static void dme2RawTest(DME2Manager dm, String aafurl, String user, String pass) {
+ try {
+ if(dm==null) {
+ return;
+ }
+ URI uri = new URI(aafurl);
+ print(true,"DME2 Direct Client Coding Methodology",uri.toString());
+ DME2Client client = dm.newClient( uri, 3000);
+ client.setMethod("GET"); // FYI, DME2 defaults to "POST"
+ client.setContext("/authz/perms/user/"+user); // DME2 direct requires separate setting of Context from URI
+ if(pass!=null) { // rely on Cert if no pass
+ client.setCredentials(user, pass);
+ }
+ client.setPayload(""); // DME2 will not send without something
+ String resp = client.sendAndWait(7000);
+ System.out.println(resp);
+ } catch(Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
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
index 0000000..b661df4
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/PermEval.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import com.att.inno.env.util.Split;
+
+
+public class PermEval {
+ public static final char START_REGEX_CHAR = '!';
+ public static final char START_INST_KEY_CHAR=':';
+ public static final char ALT_START_INST_KEY_CHAR='/';
+
+ public static final char LIST_SEP = ',';
+ public static final String INST_KEY_REGEX = new StringBuilder().append(START_INST_KEY_CHAR).toString();
+ public static final String ASTERIX = "*";
+
+ /**
+ * Evaluate Instance
+ *
+ * Instance can be more complex. It can be a string, a Regular Expression, or a ":" separated Key
+ * who's parts can also be a String, Regular Expression.
+ *
+ * sInst = Server's Instance
+ * In order to prevent false matches, keys must be the same length to count as equal
+ * Changing this will break existing users, like Cassandra. 9-4-2015
+ */
+ public static boolean evalInstance(String sInst, String pInst) {
+ if(sInst==null || pInst == null) {
+ return false;
+ }
+ if(ASTERIX.equals(sInst)) {
+ return true; // If Server's String is "*", then it accepts every Instance
+ }
+ char firstChar = pInst.charAt(0);
+ char startChar = firstChar==ALT_START_INST_KEY_CHAR?ALT_START_INST_KEY_CHAR:START_INST_KEY_CHAR;
+ switch(pInst.charAt(0)) { // First char
+ case START_REGEX_CHAR: // Evaluate as Regular Expression
+ String pItem = pInst.substring(1);
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," definition in Action
+ return sItem.matches(pItem);
+ }
+
+ case START_INST_KEY_CHAR: // Evaluate a special Key field, i.e.:xyz:*:!df.*
+ case ALT_START_INST_KEY_CHAR: // Also allow '/' as special Key Field, i.e. /xyz/*/!.*
+ if(sInst.charAt(0)==startChar) { // To compare key-to-key, both strings must be keys
+ String[] skeys=Split.split(startChar,sInst);
+ String[] pkeys=Split.split(startChar,pInst);
+ if(skeys.length!=pkeys.length) return false;
+
+ boolean pass = true;
+ for(int i=1;pass && i<skeys.length;++i) { // We start at 1, because the first one, being ":" is always ""
+ if(ASTERIX.equals(skeys[i]))continue; // Server data accepts all for this key spot
+ pass = false;
+ for(String sItem : Split.split(LIST_SEP,skeys[i])) { // allow for "," definition in Action
+ if(pkeys[i].length()==0) {
+ if(pass=sItem.length()==0) {
+ break; // Both Empty, keep checking
+ }
+// } else if(pkeys[i].charAt(0)==START_REGEX_CHAR) {
+// if(pass=sItem.matches(pkeys[i].substring(1))) {
+// break; // Matches, keep checking
+// }
+ } else if(sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like *
+ if(pass=pkeys[i].matches(sItem.substring(1))) {
+ break; // Matches, keep checking
+ }
+ } else if(skeys[i].endsWith(ASTERIX)) {
+ if(pass=endAsterixCompare(skeys[i],pkeys[i])) {
+ break;
+ }
+ } else {
+ if(pass=sItem.equals(pkeys[i]))
+ break; // Equal, keep checking
+ }
+ }
+ }
+ return pass; // return whether passed all key checks
+ }
+ return false; // if first chars aren't the same, further String compare not necessary
+ default: // Evaluate as String Compare
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," separator //TODO is this only for actions?
+ if(sItem.endsWith(ASTERIX)) {
+ if(endAsterixCompare(sInst, pInst));
+ } else if(sItem.equals(pInst)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static boolean endAsterixCompare(String sInst, String pInst) {
+ final int len = sInst.length()-1;
+ if(pInst.length()<len) {
+ return false;
+ }
+ for(int j=0;j<len;++j) {
+ if(pInst.charAt(j)!=sInst.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Evaluate Action
+ *
+ * sAction = Stored Action...
+ * pAction = Present Action... the Permission to validate against.
+ * Action is not quite as complex. But we write it in this function so it can be consistent
+ */
+ public static boolean evalAction(String sAction,String pAction) {
+ if(ASTERIX.equals(sAction))return true; // If Server's String is "*", then it accepts every Action
+ for(String sItem : Split.split(LIST_SEP,sAction)) { // allow for "," definition in Action
+ if (pAction.charAt(0)==START_REGEX_CHAR? // First char
+ sItem.matches(pAction.substring(1)): // Evaluate as Regular Expression
+ sItem.equals(pAction)) // Evaluate as String Compare
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Split.split by Char
+ *
+ * Note: I read the String Split.split and Pattern Split.split code, and we can do this more efficiently for a single Character
+ */
+
+}
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
index 0000000..ecdaf24
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cert;
+
+
+import java.security.Principal;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Hash;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.principal.X509Principal;
+import com.att.cadi.taf.cert.CertIdentity;
+import com.att.cadi.taf.cert.X509Taf;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
+
+public class AAFListedCertIdentity implements CertIdentity {
+ //TODO should 8 hours be configurable?
+ private static final long EIGHT_HOURS = 1000*60*60*8;
+ private static final String AAF_VERSION = "2.0";
+
+ private static Map<ByteArrayHolder,String> certs = null;
+
+ // Did this to add other Trust Mechanisms
+ // Trust mechanism set by Property:
+ private static final String[] authMechanisms = new String[] {"tguard","basicAuth","csp"};
+ private static String[] certIDs;
+
+ private static Map<String,Set<String>> trusted =null;
+
+ public AAFListedCertIdentity(Access access, AAFCon<?> aafcon) throws APIException {
+ synchronized(AAFListedCertIdentity.class) {
+ if(certIDs==null) {
+ String cip = access.getProperty(Config.AAF_CERT_IDS, null);
+ if(cip!=null) {
+ certIDs = Split.split(',',cip);
+ }
+ }
+ if(certIDs!=null && certs==null) {
+ TimerTask cu = new CertUpdate(aafcon);
+ cu.run(); // want this to run in this thread first...
+ new Timer("AAF Identity Refresh Timer",true).scheduleAtFixedRate(cu, EIGHT_HOURS,EIGHT_HOURS);
+ }
+ }
+ }
+
+ public static Set<String> trusted(String authMech) {
+ return trusted.get(authMech);
+ }
+
+ public Principal identity(HttpServletRequest req, X509Certificate cert, byte[] certBytes) throws CertificateException {
+ if(cert==null && certBytes==null)return null;
+ if(certBytes==null)certBytes = cert.getEncoded();
+ byte[] fingerprint = X509Taf.getFingerPrint(certBytes);
+ String id = certs.get(new ByteArrayHolder(fingerprint));
+ if(id!=null) { // Caller is Validated
+ return new X509Principal(id,cert,certBytes);
+ }
+ return null;
+ }
+
+ private static class ByteArrayHolder implements Comparable<ByteArrayHolder> {
+ private byte[] ba;
+ public ByteArrayHolder(byte[] ba) {
+ this.ba = ba;
+ }
+ public int compareTo(ByteArrayHolder b) {
+ return Hash.compareTo(ba, b.ba);
+ }
+ }
+
+ private class CertUpdate extends TimerTask {
+
+ private AAFCon<?> aafcon;
+ public CertUpdate(AAFCon<?> con) {
+ aafcon = con;
+ }
+
+ @Override
+ public void run() {
+ try {
+ TreeMap<ByteArrayHolder, String> newCertsMap = new TreeMap<ByteArrayHolder,String>();
+ Map<String,Set<String>> newTrustMap = new TreeMap<String,Set<String>>();
+ Set<String> userLookup = new HashSet<String>();
+ for(String s : certIDs) {
+ userLookup.add(s);
+ }
+ for(String authMech : authMechanisms) {
+ Future<Users> fusr = aafcon.client(AAF_VERSION).read("/authz/users/perm/com.att.aaf.trust/"+authMech+"/authenticate", Users.class, aafcon.usersDF);
+ if(fusr.get(5000)) {
+ List<User> users = fusr.value.getUser();
+ if(users.isEmpty()) {
+ aafcon.access.log(Level.WARN, "AAF Lookup-No IDs in Role com.att.aaf.trustForID <> "+authMech);
+ } else {
+ aafcon.access.log(Level.INFO,"Loading Trust Authentication Info for",authMech);
+ Set<String> hsUser = new HashSet<String>();
+ for(User u : users) {
+ userLookup.add(u.getId());
+ hsUser.add(u.getId());
+ }
+ newTrustMap.put(authMech,hsUser);
+ }
+ } else {
+ aafcon.access.log(Level.WARN, "Could not get Users in Perm com.att.trust|tguard|authenticate",fusr.code(),fusr.body());
+ }
+
+ }
+
+ for(String u : userLookup) {
+ Future<Certs> fc = aafcon.client(AAF_VERSION).read("/authn/cert/id/"+u, Certs.class, aafcon.certsDF);
+ XMLGregorianCalendar now = Chrono.timeStamp();
+ if(fc.get(5000)) {
+ List<Cert> certs = fc.value.getCert();
+ if(certs.isEmpty()) {
+ aafcon.access.log(Level.WARN, "No Cert Associations for",u);
+ } else {
+ for(Cert c : fc.value.getCert()) {
+ XMLGregorianCalendar then =c.getExpires();
+ if(then !=null && then.compare(now)>0) {
+ newCertsMap.put(new ByteArrayHolder(c.getFingerprint()), c.getId());
+ aafcon.access.log(Level.INIT,"Associating "+ c.getId() + " expiring " + Chrono.dateOnlyStamp(c.getExpires()) + " with " + c.getX500());
+ }
+ }
+ }
+ } else {
+ aafcon.access.log(Level.WARN, "Could not get Certificates for",u);
+ }
+ }
+
+ certs = newCertsMap;
+ trusted = newTrustMap;
+ } catch(Exception e) {
+ aafcon.access.log(e, "Failure to update Certificate Identities from AAF");
+ }
+ }
+ }
+}
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
index 0000000..7fc776a
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.client;
+
+import java.io.PrintStream;
+
+import aaf.v2_0.Error;
+
+import com.att.cadi.client.Future;
+import com.att.cadi.util.Vars;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class ErrMessage {
+ private RosettaDF<Error> errDF;
+
+ public ErrMessage(RosettaEnv env) throws APIException {
+ errDF = env.newDataFactory(Error.class);
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param ps
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public void printErr(PrintStream ps, String attErrJson) throws APIException {
+ StringBuilder sb = new StringBuilder();
+ Error err = errDF.newData().in(TYPE.JSON).load(attErrJson).asObject();
+ ps.println(toMsg(sb,err));
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param sb
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public StringBuilder toMsg(StringBuilder sb, String attErrJson) throws APIException {
+ return toMsg(sb,errDF.newData().in(TYPE.JSON).load(attErrJson).asObject());
+ }
+
+ public StringBuilder toMsg(Future<?> future) {
+ return toMsg(new StringBuilder(),future);
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Future<?> future) {
+ try {
+ toMsg(sb,errDF.newData().in(TYPE.JSON).load(future.body()).asObject());
+ } catch(Exception e) {
+ //just print what we can
+ sb.append(future.code());
+ sb.append(": ");
+ sb.append(future.body());
+ }
+ return sb;
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Error err) {
+ sb.append(err.getMessageId());
+ sb.append(' ');
+ String[] vars = new String[err.getVariables().size()];
+ err.getVariables().toArray(vars);
+ Vars.convert(sb, err.getText(),vars);
+ return sb;
+ }
+}
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
index 0000000..e8a4756
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java
@@ -0,0 +1,445 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.client;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.GregorianCalendar;
+
+import aaf.v2_0.Approval;
+import aaf.v2_0.Approvals;
+import aaf.v2_0.CredRequest;
+import aaf.v2_0.Keys;
+import aaf.v2_0.NsRequest;
+import aaf.v2_0.Nss;
+import aaf.v2_0.Nss.Ns;
+import aaf.v2_0.Perm;
+import aaf.v2_0.PermKey;
+import aaf.v2_0.PermRequest;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Pkey;
+import aaf.v2_0.Request;
+import aaf.v2_0.Role;
+import aaf.v2_0.RoleKey;
+import aaf.v2_0.RolePermRequest;
+import aaf.v2_0.RoleRequest;
+import aaf.v2_0.Roles;
+import aaf.v2_0.UserRole;
+import aaf.v2_0.UserRoleRequest;
+import aaf.v2_0.UserRoles;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Chrono;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class Examples {
+ public static <C> String print(RosettaEnv env, String nameOrContentType, boolean optional) throws APIException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ // Discover ClassName
+ String className = null;
+ String version = null;
+ TYPE type = TYPE.JSON; // default
+ if(nameOrContentType.startsWith("application/")) {
+ for(String ct : nameOrContentType.split("\\s*,\\s*")) {
+ for(String elem : ct.split("\\s*;\\s*")) {
+ if(elem.endsWith("+json")) {
+ type = TYPE.JSON;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-5);
+ } else if(elem.endsWith("+xml")) {
+ type = TYPE.XML;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-4);
+ } else if(elem.startsWith("version=")) {
+ version = elem.substring(8);
+ }
+ }
+ if(className!=null && version!=null)break;
+ }
+ if(className==null) {
+ throw new APIException(nameOrContentType + " does not contain Class Information");
+ }
+ } else {
+ className = nameOrContentType;
+ }
+
+ // No Void.class in aaf.v2_0 package causing errors when trying to use a newVoidv2_0
+ // method similar to others in this class. This makes it work, but is it right?
+ if ("Void".equals(className)) return "";
+
+ if("1.1".equals(version)) {
+ version = "v1_0";
+ } else if(version!=null) {
+ version = "v" + version.replace('.', '_');
+ } else {
+ version = "v2_0";
+ }
+
+ Class<?> cls;
+ try {
+ cls = Examples.class.getClassLoader().loadClass("aaf."+version+'.'+className);
+ } catch (ClassNotFoundException e) {
+ throw new APIException(e);
+ }
+
+ Method meth;
+ try {
+ meth = Examples.class.getDeclaredMethod("new"+cls.getSimpleName()+version,boolean.class);
+ } catch (Exception e) {
+ throw new APIException("ERROR: " + cls.getName() + " does not have an Example in Code. Request from AAF Developers");
+ }
+
+ RosettaDF<C> df = env.newDataFactory(cls);
+ df.option(Data.PRETTY);
+
+ Object data = meth.invoke(null,optional);
+
+ @SuppressWarnings("unchecked")
+ String rv = df.newData().load((C)data).out(type).asString();
+// Object obj = df.newData().in(type).load(rv).asObject();
+ return rv;
+ }
+
+ /*
+ * Set Base Class Request (easier than coding over and over)
+ */
+ private static void setOptional(Request req) {
+ GregorianCalendar gc = new GregorianCalendar();
+ req.setStart(Chrono.timeStamp(gc));
+ gc.add(GregorianCalendar.MONTH, 6);
+ req.setEnd(Chrono.timeStamp(gc));
+// req.setForce("false");
+
+ }
+
+ @SuppressWarnings("unused")
+ private static Request newRequestv2_0(boolean optional) {
+ Request r = new Request();
+ setOptional(r);
+ return r;
+ }
+ @SuppressWarnings("unused")
+ private static RolePermRequest newRolePermRequestv2_0(boolean optional) {
+ RolePermRequest rpr = new RolePermRequest();
+ Pkey pkey = new Pkey();
+ pkey.setType("com.att.myns.mytype");
+ pkey.setInstance("myInstance");
+ pkey.setAction("myAction");
+ rpr.setPerm(pkey);
+ rpr.setRole("com.att.myns.myrole");
+ if(optional)setOptional(rpr);
+ return rpr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Roles newRolesv2_0(boolean optional) {
+ Role r;
+ Pkey p;
+ Roles rs = new Roles();
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myOtherRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOthertype");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ return rs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermRequest newPermRequestv2_0(boolean optional) {
+ PermRequest pr = new PermRequest();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+
+ setOptional(pr);
+ }
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perm newPermv2_0(boolean optional) {
+ Perm pr = new Perm();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ pr.getRoles().add("com.att.myns.myRole");
+ pr.getRoles().add("com.att.myns.myRole2");
+ pr.setDescription("This is my description, and I'm sticking with it");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+ }
+ return pr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermKey newPermKeyv2_0(boolean optional) {
+ PermKey pr = new PermKey();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perms newPermsv2_0(boolean optional) {
+ Perms perms = new Perms();
+ Perm p;
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+ return perms;
+
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoleRequest newUserRoleRequestv2_0(boolean optional) {
+ UserRoleRequest urr = new UserRoleRequest();
+ urr.setRole("com.att.myns.myRole");
+ urr.setUser("ab1234@csp.att.com");
+ if(optional) setOptional(urr);
+ return urr;
+ }
+
+ @SuppressWarnings("unused")
+ private static NsRequest newNsRequestv2_0(boolean optional) {
+ NsRequest nr = new NsRequest();
+ nr.setName("com.att.myns");
+ nr.getResponsible().add("ab1234@csp.att.com");
+ nr.getResponsible().add("cd5678@csp.att.com");
+ nr.getAdmin().add("zy9876@csp.att.com");
+ nr.getAdmin().add("xw5432@csp.att.com");
+ if(optional) {
+ nr.setDescription("This is my Namespace to set up");
+ nr.setType("APP");
+ setOptional(nr);
+ }
+ return nr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Nss newNssv2_0(boolean optional) {
+ Ns ns;
+
+ Nss nss = new Nss();
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myns");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+ ns.setDescription("This is my Namespace to set up");
+
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myOtherNs");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+
+ return nss;
+ }
+ @SuppressWarnings("unused")
+ private static RoleRequest newRoleRequestv2_0(boolean optional) {
+ RoleRequest rr = new RoleRequest();
+ rr.setName("com.att.myns.myRole");
+ if(optional) {
+ rr.setDescription("This is my Role");
+ setOptional(rr);
+ }
+ return rr;
+ }
+
+ @SuppressWarnings("unused")
+ private static CredRequest newCredRequestv2_0(boolean optional) {
+ CredRequest cr = new CredRequest();
+ cr.setId("myID@fully.qualified.domain");
+ if(optional) {
+ cr.setType(2);
+ cr.setEntry("0x125AB256344CE");
+ } else {
+ cr.setPassword("This is my provisioned password");
+ }
+
+ return cr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Users newUsersv2_0(boolean optional) {
+ User user;
+
+ Users users = new Users();
+ users.getUser().add(user = new Users.User());
+ user.setId("ab1234@csp.att.com");
+ GregorianCalendar gc = new GregorianCalendar();
+ user.setExpires(Chrono.timeStamp(gc));
+
+ users.getUser().add(user = new Users.User());
+ user.setId("zy9876@csp.att.com");
+ user.setExpires(Chrono.timeStamp(gc));
+
+ return users;
+ }
+
+ @SuppressWarnings("unused")
+ private static Role newRolev2_0(boolean optional) {
+ Role r = new Role();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static RoleKey newRoleKeyv2_0(boolean optional) {
+ RoleKey r = new RoleKey();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static Keys newKeysv2_0(boolean optional) {
+ Keys ks = new Keys();
+ ks.getKey().add("Reponse 1");
+ ks.getKey().add("Response 2");
+ return ks;
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoles newUserRolesv2_0(boolean optional) {
+ UserRoles urs = new UserRoles();
+ UserRole ur = new UserRole();
+ ur.setUser("xy1234");
+ ur.setRole("com.test.myapp.myRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+
+ ur = new UserRole();
+ ur.setUser("yx4321");
+ ur.setRole("com.test.yourapp.yourRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+ return urs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Approvals newApprovalsv2_0(boolean optional) {
+ Approvals as = new Approvals();
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ as.getApprovals().add(a);
+ a = new Approval();
+ a.setApprover("MyApprover2");
+ a.setId("MyID2");
+ a.setMemo("My memo (and then some)2");
+ a.setOperation("MyOperation2");
+ a.setStatus("MyStatus2");
+ a.setTicket("MyTicket2");
+ a.setType("MyType2");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser2");
+ as.getApprovals().add(a);
+ return as;
+ }
+
+ @SuppressWarnings("unused")
+ private static Approval newApprovalv2_0(boolean optional) {
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ return a;
+ }
+
+
+
+ @SuppressWarnings("unused")
+ private static aaf.v2_0.Error newErrorv2_0(boolean optional) {
+ aaf.v2_0.Error err = new aaf.v2_0.Error();
+ err.setMessageId("SVC1403");
+ err.setText("MyText %s, %s: The last three digits are usually the HTTP Code");
+ err.getVariables().add("Variable 1");
+ err.getVariables().add("Variable 2");
+ return err;
+ }
+
+}
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
index 0000000..4193d43
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.marshal;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.FieldDateTime;
+import com.att.rosetta.marshal.FieldHexBinary;
+import com.att.rosetta.marshal.FieldString;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertMarshal extends ObjMarshal<Cert> {
+ public CertMarshal() {
+ add(new FieldHexBinary<Cert>("fingerprint") {
+ @Override
+ protected byte[] data(Cert t) {
+ return t.getFingerprint();
+ }
+ });
+
+ add(new FieldString<Cert>("id") {
+ @Override
+ protected String data(Cert t) {
+ return t.getId();
+ }
+ });
+
+ add(new FieldString<Cert>("x500") {
+ @Override
+ protected String data(Cert t) {
+ return t.getX500();
+ }
+ });
+
+ add(new FieldDateTime<Cert>("expires") {
+ @Override
+ protected XMLGregorianCalendar data(Cert t) {
+ return t.getExpires();
+ }
+ });
+
+
+ }
+}
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
index 0000000..16fc580
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.marshal;
+
+import java.util.List;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.ObjArray;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertsMarshal extends ObjMarshal<Certs> {
+
+ public CertsMarshal() {
+ add(new ObjArray<Certs,Cert>("cert",new CertMarshal()) {
+ @Override
+ protected List<Cert> data(Certs t) {
+ return t.getCert();
+ }
+ });
+ }
+
+
+}
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
index 0000000..db60495
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CadiException;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.config.Config;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
+ private AAFCon<CLIENT> con;
+ private String realm;
+
+ /**
+ * Configure with Standard AAF properties, Stand alone
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con) throws Exception {
+ super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);
+ this.con = con;
+
+ try {
+ setRealm();
+ } catch (APIException e) {
+ if(e.getCause() instanceof DME2Exception) {
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ /**
+ * Configure with Standard AAF properties, but share the Cache (with AAF Lur)
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {
+ super(cache);
+ this.con = con;
+ try {
+ setRealm();
+ } catch (Exception e) {
+ if(e.getCause() instanceof DME2Exception) {
+ access.log(e);
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ private void setRealm() throws Exception {
+ // Make a call without security set to get the 401 response, which
+ // includes the Realm of the server
+ // This also checks on Connectivity early on.
+ Future<String> fp = con.client(AAFCon.AAF_LATEST_VERSION).read("/authn/basicAuth", "text/plain");
+ if(fp.get(con.timeout)) {
+ throw new Exception("Do not preset Basic Auth Information for AAFAuthn");
+ } else {
+ if(fp.code()==401) {
+ realm = fp.header("WWW-Authenticate");
+ if(realm!=null && realm.startsWith("Basic realm=\"")) {
+ realm = realm.substring(13, realm.length()-1);
+ } else {
+ realm = "unknown.com";
+ }
+ }
+ }
+ }
+
+ /**
+ * Return Native Realm of AAF Instance.
+ *
+ * @return
+ */
+ public String getRealm() {
+ return realm;
+ }
+
+ /**
+ * Returns null if ok, or an Error String;
+ *
+ * @param user
+ * @param password
+ * @return
+ * @throws IOException
+ * @throws CadiException
+ * @throws Exception
+ */
+ public String validate(String user, String password) throws IOException, CadiException {
+ User<AAFPermission> usr = getUser(user);
+ if(password.startsWith("enc:???")) {
+ password = access.decrypt(password, true);
+ }
+
+ byte[] bytes = password.getBytes();
+ if(usr != null && usr.principal != null && usr.principal.getName().equals(user)
+ && usr.principal instanceof GetCred) {
+
+ if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {
+ return null;
+ } else {
+ remove(usr);
+ usr = null;
+ }
+ }
+
+ AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);
+ // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch
+ // Statement
+ switch(cp.revalidate()) {
+ case REVALIDATED:
+ if(usr!=null) {
+ usr.principal = cp;
+ } else {
+ addUser(new User<AAFPermission>(cp,con.timeout));
+ }
+ return null;
+ case INACCESSIBLE:
+ return "AAF Inaccessible";
+ case UNVALIDATED:
+ return "User/Pass combo invalid for " + user;
+ case DENIED:
+ return "AAF denies API for " + user;
+ default:
+ return "AAFAuthn doesn't handle Principal " + user;
+ }
+ }
+
+ private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {
+ private long expires,timeToLive;
+
+ public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {
+ super(name,pass);
+ this.timeToLive = timeToLive;
+ expires = timeToLive + System.currentTimeMillis();
+ }
+
+ public Resp revalidate() {
+ if(con.isDisabled()) {
+ return Resp.DENIED;
+ }
+ try {
+ Miss missed = missed(getName());
+ if(missed==null || missed.mayContinue(getCred())) {
+ Rcli<CLIENT> client = con.client(AAFCon.AAF_LATEST_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));
+ Future<String> fp = client.read(
+ "/authn/basicAuth",
+ "text/plain"
+ );
+ if(fp.get(con.timeout)) {
+ expires = System.currentTimeMillis() + timeToLive;
+ addUser(new User<AAFPermission>(this, expires));
+ return Resp.REVALIDATED;
+ } else {
+ addMiss(getName(), getCred());
+ return Resp.UNVALIDATED;
+ }
+ } else {
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ con.access.log(e);
+ return Resp.INACCESSIBLE;
+ }
+ }
+
+ public long expires() {
+ return expires;
+ }
+ };
+
+}
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
index 0000000..573c85e
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.URI;
+import java.security.Principal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.CadiException;
+import com.att.cadi.CadiWrap;
+import com.att.cadi.Connector;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.marshal.CertsMarshal;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.util.Vars;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Error;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Users;
+
+public abstract class AAFCon<CLIENT> implements Connector {
+ public static final String AAF_LATEST_VERSION = "2.0";
+
+ final public PropAccess access;
+ // Package access
+ final public int timeout, cleanInterval, connTimeout;
+ final public int highCount, userExpires, usageRefreshTriggerCount;
+ private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();
+ final public RosettaDF<Perms> permsDF;
+ final public RosettaDF<Certs> certsDF;
+ final public RosettaDF<Users> usersDF;
+ final public RosettaDF<Error> errDF;
+ private String realm;
+ public final String app;
+ protected SecuritySetter<CLIENT> ss;
+ protected SecurityInfoC<CLIENT> si;
+
+ private DisableCheck disableCheck;
+
+ private AAFLurPerm lur;
+
+ private RosettaEnv env;
+ protected abstract URI initURI();
+ protected abstract void setInitURI(String uriString) throws CadiException;
+
+ /**
+ * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)
+ *
+ * @param apiVersion
+ * @return
+ * @throws CadiException
+ */
+ public Rcli<CLIENT> client(String apiVersion) throws CadiException {
+ Rcli<CLIENT> client = clients.get(apiVersion);
+ if(client==null) {
+ client = rclient(initURI(),ss);
+ client.apiVersion(apiVersion)
+ .readTimeout(connTimeout);
+ clients.put(apiVersion, client);
+ }
+ return client;
+ }
+
+ /**
+ * Use this API when you have permission to have your call act as the end client's ID.
+ *
+ * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
+ *
+ * @param apiVersion
+ * @param req
+ * @return
+ * @throws CadiException
+ */
+ public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {
+ Rcli<CLIENT> cl = client(apiVersion);
+ return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));
+ }
+
+ protected AAFCon(AAFCon<CLIENT> copy) {
+ access = copy.access;
+ timeout = copy.timeout;
+ cleanInterval = copy.cleanInterval;
+ connTimeout = copy.connTimeout;
+ highCount = copy.highCount;
+ userExpires = copy.userExpires;
+ usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
+ permsDF = copy.permsDF;
+ certsDF = copy.certsDF;
+ usersDF = copy.usersDF;
+ errDF = copy.errDF;
+ app = copy.app;
+ ss = copy.ss;
+ si = copy.si;
+ env = copy.env;
+ disableCheck = copy.disableCheck;
+ realm = copy.realm;
+ }
+
+ protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
+ if(tag==null) {
+ throw new CadiException("AAFCon cannot be constructed with a tag=null");
+ }
+ try {
+ this.access = access;
+ this.si = si;
+ this.ss = si.defSS;
+ if(ss==null) {
+ String mechid = access.getProperty(Config.AAF_MECHID, null);
+ String encpass = access.getProperty(Config.AAF_MECHPASS, null);
+ if(encpass==null) {
+ String alias = access.getProperty(Config.CADI_ALIAS, mechid);
+ if(alias==null) {
+ throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");
+ }
+ set(si.defSS=x509Alias(alias));
+ } else {
+ if(mechid!=null && encpass !=null) {
+ set(si.defSS=basicAuth(mechid, encpass));
+ } else {
+ set(si.defSS=new SecuritySetter<CLIENT>() {
+
+ @Override
+ public String getID() {
+ return "";
+ }
+
+ @Override
+ public void setSecurity(CLIENT client) throws CadiException {
+ throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+ });
+ }
+ }
+ }
+
+ timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));
+ cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
+ highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
+ connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
+ userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
+ usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
+
+ String str = access.getProperty(tag,null);
+ if(str==null) {
+ throw new CadiException(tag + " property is required.");
+ }
+ setInitURI(str);
+
+ app=reverseDomain(ss.getID());
+ realm="openecomp.org";
+
+ env = new RosettaEnv();
+ permsDF = env.newDataFactory(Perms.class);
+ usersDF = env.newDataFactory(Users.class);
+ certsDF = env.newDataFactory(Certs.class);
+ certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
+ errDF = env.newDataFactory(Error.class);
+ } catch (APIException e) {
+ throw new CadiException("AAFCon cannot be configured",e);
+ }
+ }
+
+ public RosettaEnv env() {
+ return env;
+ }
+
+ /**
+ * Return the backing AAFCon, if there is a Lur Setup that is AAF.
+ *
+ * If there is no AAFLur setup, it will return "null"
+ * @param servletRequest
+ * @return
+ */
+ public static final AAFCon<?> obtain(Object servletRequest) {
+ if(servletRequest instanceof CadiWrap) {
+ Lur lur = ((CadiWrap)servletRequest).getLur();
+ if(lur != null) {
+ if(lur instanceof EpiLur) {
+ AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
+ if(aal!=null) {
+ return aal.aaf;
+ }
+ } else {
+ if(lur instanceof AbsAAFLur) {
+ return ((AbsAAFLur<?>)lur).aaf;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public abstract AAFCon<CLIENT> clone(String url) throws CadiException;
+
+ public AAFAuthn<CLIENT> newAuthn() throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFLurPerm newLur() throws CadiException {
+ try {
+ if(lur==null) {
+ return new AAFLurPerm(this);
+ } else {
+ return new AAFLurPerm(this,lur);
+ }
+ } catch (CadiException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFLurPerm(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ /**
+ * Take a Fully Qualified User, and get a Namespace from it.
+ * @param user
+ * @return
+ */
+ public static String reverseDomain(String user) {
+ StringBuilder sb = null;
+ String[] split = Split.split('.',user);
+ int at;
+ for(int i=split.length-1;i>=0;--i) {
+ if(sb == null) {
+ sb = new StringBuilder();
+ } else {
+ sb.append('.');
+ }
+
+ if((at = split[i].indexOf('@'))>0) {
+ sb.append(split[i].subSequence(at+1, split[i].length()));
+ } else {
+ sb.append(split[i]);
+ }
+ }
+
+ return sb==null?"":sb.toString();
+ }
+
+ protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
+
+ public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
+
+
+ public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
+
+
+ public String getRealm() {
+ return realm;
+
+ }
+
+ public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
+ this.ss = ss;
+ if(ss instanceof AbsBasicAuth) {
+ disableCheck = (ss instanceof AbsBasicAuth)?
+ new DisableCheck() {
+ AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;
+ @Override
+ public boolean isDisabled() {
+ return aba.isDenied();
+ }
+ }:
+ new DisableCheck() {
+ @Override
+ public boolean isDisabled() {
+ return this.isDisabled();
+ }
+ };
+ }
+ for(Rcli<CLIENT> client : clients.values()) {
+ client.setSecuritySetter(ss);
+ }
+ return ss;
+ }
+
+ public SecurityInfoC<CLIENT> securityInfo() {
+ return si;
+ }
+
+ public String defID() {
+ if(ss!=null) {
+ return ss.getID();
+ }
+ return "unknown";
+ }
+
+ public void invalidate() throws CadiException {
+ for(Rcli<CLIENT> client : clients.values()) {
+ client.invalidate();
+ clients.remove(client);
+ }
+ }
+
+ public String readableErrMsg(Future<?> f) {
+ String text = f.body();
+ if(text==null || text.length()==0) {
+ text = f.code() + ": **No Message**";
+ } else if(text.contains("%")) {
+ try {
+ Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
+ return Vars.convert(err.getText(),err.getVariables());
+ } catch (APIException e){
+ // just return the body below
+ }
+ }
+ return text;
+ }
+
+ private interface DisableCheck {
+ public boolean isDisabled();
+ };
+
+ public boolean isDisabled() {
+ return disableCheck.isDisabled();
+ }
+}
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
index 0000000..7092613
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.dme2.DME2BasicAuth;
+import com.att.cadi.dme2.DME2TransferSS;
+import com.att.cadi.dme2.DME2x509SS;
+import com.att.cadi.dme2.DRcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConDME2 extends AAFCon<DME2Client>{
+ private DME2Manager manager;
+ private boolean isProxy;
+ private URI initURI;
+
+ public AAFConDME2(PropAccess access) throws CadiException, GeneralSecurityException, IOException{
+ super(access,Config.AAF_URL,new SecurityInfoC<DME2Client> (access));
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, String url) throws CadiException, GeneralSecurityException, IOException{
+ super(access,url,new SecurityInfoC<DME2Client> (access));
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, SecurityInfoC<DME2Client> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, String url, SecurityInfoC<DME2Client> si) throws CadiException {
+ super(access,url,si);
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ /**
+ * Construct a Connector based on the AAF one. This is for remote access to OTHER than AAF,
+ * but using Credentials, etc
+ */
+ private AAFConDME2(AAFCon<DME2Client> aafcon, String url) throws CadiException {
+ super(aafcon);
+ try {
+ initURI = new URI(url);
+ } catch (URISyntaxException e) {
+ throw new CadiException(e);
+ }
+ manager = newManager(access);
+ }
+
+ /**
+ * Create a Connector based on the AAF one. This is for remote access to OTHER than AAF,
+ * but using Credentials, etc
+ */
+ public AAFCon<DME2Client> clone(String url) throws CadiException {
+ return new AAFConDME2(this,url);
+ }
+
+ private void setIsProxy() {
+ String str;
+ if((str=access.getProperty(Config.AAF_URL, null))!=null) {
+ isProxy = str.contains("service=com.att.authz.authz-gw/version=");
+ }
+ }
+
+ private DME2Manager newManager(PropAccess access) throws CadiException {
+ Properties props = access.getDME2Properties();
+ // Critical that TLS Settings not ignored
+ try {
+ return new DME2Manager("AAFCon",props);
+ } catch (DME2Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<DME2Client> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error Decrypting Password",e);
+ }
+ }
+
+ try {
+ return set(new DME2BasicAuth(user,password,si));
+ } catch (IOException e) {
+ throw new CadiException("Error setting up DME2BasicAuth",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<DME2Client> rclient(URI uri, SecuritySetter<DME2Client> ss) {
+ DRcli dc = new DRcli(uri, ss);
+ dc.setProxy(isProxy);
+ dc.setManager(manager);
+ return dc;
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> transferSS(Principal principal) throws CadiException {
+ try {
+ return principal==null?ss:new DME2TransferSS(principal, app, si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2TransferSS",e);
+ }
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new DME2BasicAuth(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2BasicAuth",e);
+ }
+
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> x509Alias(String alias) throws CadiException {
+ try {
+ presetProps(access, alias);
+ return new DME2x509SS(alias,si);
+ } catch (Exception e) {
+ throw new CadiException("Error creating DME2x509SS",e);
+ }
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ // NOTE: DME2 had Retry Logic embedded lower.
+ try {
+ return (retryable.code(rclient(initURI,ss)));
+ } catch (ConnectException e) {
+ // DME2 should catch
+ try {
+ manager.refresh();
+ } catch (Exception e1) {
+ throw new CadiException(e1);
+ }
+ throw new CadiException(e);
+ }
+ }
+
+ public static void presetProps(PropAccess access, String alias) throws IOException {
+ System.setProperty(Config.AFT_DME2_CLIENT_SSL_CERT_ALIAS, alias);
+ if(System.getProperty(Config.AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {
+ access.getDME2Properties();
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()
+ */
+ @Override
+ protected URI initURI() {
+ return initURI;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)
+ */
+ @Override
+ protected void setInitURI(String uriString) throws CadiException {
+ try {
+ initURI = new URI(uriString);
+ } catch (URISyntaxException e) {
+ throw new CadiException(e);
+ }
+ }
+}
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
index 0000000..5454773
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.http.HRcli;
+import com.att.cadi.http.HTransferSS;
+import com.att.cadi.http.HX509SS;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConHttp extends AAFCon<HttpURLConnection> {
+ private final HMangr hman;
+
+ public AAFConHttp(PropAccess access) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(Config.AAF_URL,null)));
+ }
+
+ public AAFConHttp(PropAccess access, String tag) throws CadiException, GeneralSecurityException, IOException {
+ super(access,tag,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(tag,null)));
+ }
+
+ public AAFConHttp(PropAccess access, String urlTag, SecurityInfoC<HttpURLConnection> si) throws CadiException {
+ super(access,urlTag,si);
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(urlTag,null)));
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si, String tag) throws CadiException {
+ super(access,tag,si);
+ hman = new HMangr(access, locator);
+ }
+
+ private AAFConHttp(AAFCon<HttpURLConnection> aafcon, String url) {
+ super(aafcon);
+ hman = new HMangr(aafcon.access,Config.loadLocator(access, url));
+ }
+
+ @Override
+ public AAFCon<HttpURLConnection> clone(String url) {
+ return new AAFConHttp(this,url);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error decrypting password",e);
+ }
+ }
+ try {
+ return new HBasicAuthSS(user,password,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public SecuritySetter<HttpURLConnection> x509Alias(String alias) throws APIException, CadiException {
+ try {
+ return set(new HX509SS(alias,si));
+ } catch (Exception e) {
+ throw new CadiException("Error creating X509SS",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<HttpURLConnection> rclient(URI ignoredURI, SecuritySetter<HttpURLConnection> ss) throws CadiException {
+ if(hman.loc==null) {
+ throw new CadiException("No Locator set in AAFConHttp");
+ }
+ try {
+ return new HRcli(hman, hman.loc.best() ,ss);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public AbsTransferSS<HttpURLConnection> transferSS(Principal principal) throws CadiException {
+ return new HTransferSS(principal, app,si);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuthSS(java.security.Principal)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new HBasicAuthSS(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public HMangr hman() {
+ return hman;
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ return hman.best(ss, (Retryable<RET>)retryable);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()
+ */
+ @Override
+ protected URI initURI() {
+ try {
+ Item item = hman.loc.best();
+ if(item!=null) {
+ return hman.loc.get(item);
+ }
+ } catch (LocatorException e) {
+ access.log(e, "Error in AAFConHttp obtaining initial URI");
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)
+ */
+ @Override
+ protected void setInitURI(String uriString) throws CadiException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..db03347
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.ConnectException;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.Map;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Permission;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.lur.LocalPermission;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+
+import aaf.v2_0.Perm;
+import aaf.v2_0.Perms;
+
+/**
+ * Use AAF Service as Permission Service.
+ *
+ * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.
+ *
+ * If you want a simple Role Lur, use AAFRoleLur
+ *
+ *
+ */
+public class AAFLurPerm extends AbsAAFLur<AAFPermission> {
+ /**
+ * Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this
+ * point by AAF. There is no "domain", aka, no "@att.com" in "ab1234@att.com".
+ *
+ * The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.
+ * Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely
+ * @throws APIException
+ * @throws URISyntaxException
+ * @throws DME2Exception
+ */
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con) throws CadiException, DME2Exception, URISyntaxException, APIException {
+ super(con);
+ }
+
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(con,auc);
+ }
+
+ protected User<AAFPermission> loadUser(Principal p) {
+ // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't
+ // have domains. We are going to make the Transitive Class (see this.transmutative) to convert
+ Principal principal = transmutate.mutate(p);
+ if(principal==null)return null; // if not a valid Transmutated credential, don't bother calling...
+ return loadUser(p, p.getName());
+ }
+
+ protected User<AAFPermission> loadUser(String name) {
+ return loadUser((Principal)null, name);
+ }
+
+ private User<AAFPermission> loadUser(final Principal prin, final String name) {
+
+ //TODO Create a dynamic way to declare domains supported.
+ final long start = System.nanoTime();
+ final boolean[] success = new boolean[]{false};
+
+// new Exception("loadUser").printStackTrace();
+ try {
+ return aaf.best(new Retryable<User<AAFPermission>>() {
+ @Override
+ public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);
+
+ // In the meantime, lookup User, create if necessary
+ User<AAFPermission> user = getUser(name);
+ Principal p;
+ if(prin == null) {
+ p = new Principal() {// Create a holder for lookups
+ private String n = name;
+ public String getName() {
+ return n;
+ }
+ };
+ } else {
+ p = prin;
+ }
+
+ if(user==null) {
+ addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
+ }
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success[0]=true;
+ Map<String, Permission> newMap = user.newMap();
+ boolean willLog = aaf.access.willLog(Level.DEBUG);
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ if(willLog) {
+ aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
+ }
+ }
+ user.setMap(newMap);
+ user.renewPerm();
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ }
+
+ return user;
+ }
+ });
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ success[0]=false;
+ return null;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.INFO, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ public Resp reload(User<AAFPermission> user) {
+ final String name = user.principal.getName();
+ long start = System.nanoTime();
+ boolean success = false;
+ try {
+ Future<Perms> fp = aaf.client(AAFCon.AAF_LATEST_VERSION).read(
+ "/authz/perms/user/"+name,
+ aaf.permsDF
+ );
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success = true;
+ Map<String,Permission> newMap = user.newMap();
+ boolean willLog = aaf.access.willLog(Level.DEBUG);
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ if(willLog) {
+ aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
+ }
+ }
+ user.renewPerm();
+ return Resp.REVALIDATED;
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ return Resp.INACCESSIBLE;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ @Override
+ protected boolean isCorrectPermType(Permission pond) {
+ return pond instanceof AAFPermission;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#createPerm(java.lang.String)
+ */
+ @Override
+ public Permission createPerm(String p) {
+ String[] params = Split.split('|', p);
+ if(params.length==3) {
+ return new AAFPermission(params[0],params[1],params[2]);
+ } else {
+ return new LocalPermission(p);
+ }
+ }
+
+}
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
index 0000000..35df38f
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CachedBasicPrincipal;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+import com.att.cadi.taf.basic.BasicHttpTafResp;
+
+public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {
+// private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";
+// private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";
+ private AAFCon<CLIENT> aaf;
+ private boolean warn;
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {
+ super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {
+ super(other);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ //TODO Do we allow just anybody to validate?
+
+ // Note: Either Carbon or Silicon based LifeForms ok
+ String authz = req.getHeader("Authorization");
+ if(authz != null && authz.startsWith("Basic ")) {
+ if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
+ try {
+ CachedBasicPrincipal bp;
+ if(req.getUserPrincipal() instanceof CachedBasicPrincipal) {
+ bp = (CachedBasicPrincipal)req.getUserPrincipal();
+ } else {
+ bp = new CachedBasicPrincipal(this,authz,aaf.getRealm(),aaf.userExpires);
+ }
+ // First try Cache
+ User<AAFPermission> usr = getUser(bp);
+ if(usr != null && usr.principal != null) {
+ if(usr.principal instanceof GetCred) {
+ if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ }
+ }
+ }
+
+ Miss miss = missed(bp.getName());
+ if(miss!=null && !miss.mayContinue(bp.getCred())) {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.basicAuthSS(bp));
+ Future<String> fp = userAAF.read("/authn/basicAuth", "text/plain");
+ if(fp.get(aaf.timeout)) {
+ if(usr!=null) {
+ usr.principal = bp;
+ } else {
+ addUser(new User<AAFPermission>(bp,aaf.userExpires));
+ }
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ } else {
+ // Note: AddMiss checks for miss==null, and is part of logic
+ boolean rv= addMiss(bp.getName(),bp.getCred());
+ if(rv) {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF"),
+ RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
+ } else {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF - Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+ }
+ } catch (IOException e) {
+ String msg = buildMsg(null,req,"Invalid Auth Token");
+ aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);
+ } catch (Exception e) {
+ String msg = buildMsg(null,req,"Authenticating Service unavailable");
+ aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);
+ }
+ }
+ return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
+ }
+
+ private String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
+ StringBuilder sb = new StringBuilder();
+ for(Object s : msg) {
+ sb.append(s.toString());
+ }
+ if(pr!=null) {
+ sb.append(" for ");
+ sb.append(pr.getName());
+ }
+ sb.append(" from ");
+ sb.append(req.getRemoteAddr());
+ sb.append(':');
+ sb.append(req.getRemotePort());
+ return sb.toString();
+ }
+
+
+
+ public Resp revalidate(CachedPrincipal prin) {
+ // !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal
+ if(prin instanceof BasicPrincipal) {
+ Future<String> fp;
+ try {
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.transferSS(prin));
+ fp = userAAF.read("/authn/basicAuth", "text/plain");
+ return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;
+ } catch (Exception e) {
+ aaf.access.log(e, "Cannot Revalidate",prin.getName());
+ return Resp.INACCESSIBLE;
+ }
+ }
+ return Resp.NOT_MINE;
+ }
+
+}
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
index 0000000..3bc4faf
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import com.att.cadi.Access;
+import com.att.cadi.Lur;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.config.Config;
+import com.att.cadi.principal.TrustPrincipal;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TrustNotTafResp;
+import com.att.cadi.taf.TrustTafResp;
+import com.att.inno.env.Env;
+import com.att.inno.env.util.Split;
+
+public class AAFTrustChecker implements TrustChecker {
+ private final String tag, id;
+ private final AAFPermission perm;
+ private Lur lur;
+
+ /**
+ *
+ * Instance will be replaced by Identity
+ * @param lur
+ *
+ * @param tag
+ * @param perm
+ */
+ public AAFTrustChecker(final Env env) {
+ tag = env.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);
+ id = env.getProperty(Config.CADI_ALIAS,env.getProperty(Config.AAF_MECHID)); // share between components
+ String str = env.getProperty(Config.CADI_TRUST_PERM);
+ AAFPermission temp=null;
+ if(str!=null) {
+ String[] sp = Split.splitTrim('|', str);
+ if(sp.length==3) {
+ temp = new AAFPermission(sp[0],sp[1],sp[2]);
+ }
+ }
+ perm=temp;
+ }
+
+ public AAFTrustChecker(final Access access) {
+ tag = access.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);
+ id = access.getProperty(Config.CADI_ALIAS,access.getProperty(Config.AAF_MECHID,null)); // share between components
+ String str = access.getProperty(Config.CADI_TRUST_PERM,null);
+ AAFPermission temp=null;
+ if(str!=null) {
+ String[] sp = Split.splitTrim('|', str);
+ if(sp.length==3) {
+ temp = new AAFPermission(sp[0],sp[1],sp[2]);
+ }
+ }
+ perm=temp;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.TrustChecker#setLur(com.att.cadi.Lur)
+ */
+ @Override
+ public void setLur(Lur lur) {
+ this.lur = lur;
+ }
+
+ @Override
+ public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {
+ String user_info = req.getHeader(tag);
+ if(user_info !=null ) {
+ String[] info = Split.split(',', user_info);
+ if(info.length>0) {
+ String[] flds = Split.splitTrim(':',info[0]);
+ if(flds.length>3 && "AS".equals(flds[3])) { // is it set for "AS"
+ String pn = tresp.getPrincipal().getName();
+ if(pn.equals(id) // We do trust our own App Components: if a trust entry is made with self, always accept
+ || lur.fish(tresp.getPrincipal(), perm)) { // Have Perm set by Config.CADI_TRUST_PERM
+ return new TrustTafResp(tresp,
+ new TrustPrincipal(tresp.getPrincipal(), flds[0]),
+ " " + flds[0] + " validated using " + flds[2] + " by " + flds[1] + ','
+ );
+ } else if(pn.equals(flds[0])) { // Ignore if same identity
+ return tresp;
+ } else {
+ return new TrustNotTafResp(tresp, tresp.getPrincipal().getName() + " requested trust as "
+ + flds[0] + ", but does not have Authorization");
+ }
+ }
+ }
+ }
+ return tresp;
+ }
+
+}
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
index 0000000..8626588
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachingLur;
+import com.att.cadi.Permission;
+import com.att.cadi.StrLur;
+import com.att.cadi.Transmutate;
+import com.att.cadi.User;
+import com.att.cadi.config.Config;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.AAFTransmutate;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+
+public abstract class AbsAAFLur<PERM extends Permission> extends AbsUserCache<PERM> implements StrLur, CachingLur<PERM> {
+ protected static final byte[] BLANK_PASSWORD = new byte[0];
+ protected static final Transmutate<Principal> transmutate = new AAFTransmutate();
+ private String[] debug = null;
+ public AAFCon<?> aaf;
+ private String[] supports;
+
+ public AbsAAFLur(AAFCon<?> con) throws DME2Exception, URISyntaxException, APIException {
+ super(con.access, con.cleanInterval, con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ public AbsAAFLur(AAFCon<?> con, AbsUserCache<PERM> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(auc);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ @Override
+ public void setDebug(String ids) {
+ this.debug = ids==null?null:Split.split(',', ids);
+ }
+
+ protected abstract User<PERM> loadUser(Principal bait);
+ protected abstract User<PERM> loadUser(String name);
+ public final boolean supports(String userName) {
+ if(userName!=null) {
+ for(String s : supports) {
+ if(userName.endsWith(s))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected abstract boolean isCorrectPermType(Permission pond);
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(Principal bait, Permission pond) {
+ return fish(bait.getName(), pond);
+ }
+
+ public void fishAll(Principal bait, List<Permission> perms) {
+ fishAll(bait.getName(),perms);
+ }
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(String bait, Permission pond) {
+ if(isDebug(bait)) {
+ boolean rv = false;
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else if(user.contains(pond)) {
+ sb.append("\n\tUser contains ");
+ sb.append(pond.getKey());
+ rv = true;
+ } else {
+ sb.append("\n\tUser does not contain ");
+ sb.append(pond.getKey());
+ List<Permission> perms = new ArrayList<Permission>();
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ return rv;
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ }
+ return user==null?false:user.contains(pond);
+ }
+ return false;
+ }
+ }
+
+ public void fishAll(String bait, List<Permission> perms) {
+ if(isDebug(bait)) {
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else {
+ sb.append("\n\tCopying Perms ");
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) user = loadUser(bait);
+ if(user!=null) {
+ user.copyPermsTo(perms);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void remove(String user) {
+ super.remove(user);
+ }
+
+ private boolean isDebug(String bait) {
+ if(debug!=null) {
+ if(debug.length==1 && "all".equals(debug[0]))return true;
+ for(String s : debug) {
+ if(s.equals(bait))return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * This special case minimizes loops, avoids multiple Set hits, and calls all the appropriate Actions found.
+ *
+ * @param bait
+ * @param obj
+ * @param type
+ * @param instance
+ * @param actions
+ */
+ public<A> void fishOneOf(String bait, A obj, String type, String instance, List<Action<A>> actions) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired()))user = loadUser(bait);
+// return user==null?false:user.contains(pond);
+ if(user!=null) {
+ ReuseAAFPermission perm = new ReuseAAFPermission(type,instance);
+ for(Action<A> action : actions) {
+ perm.setAction(action.getName());
+ if(user.contains(perm)) {
+ if(action.exec(obj))return;
+ }
+ }
+ }
+ }
+
+ public static interface Action<A> {
+ public String getName();
+ /**
+ * Return false to continue, True to end now
+ * @return
+ */
+ public boolean exec(A a);
+ }
+
+ private class ReuseAAFPermission extends AAFPermission {
+ public ReuseAAFPermission(String type, String instance) {
+ super(type,instance,null);
+ }
+
+ public void setAction(String s) {
+ action = s;
+ }
+
+ /**
+ * This function understands that AAF Keys are hierarchical, :A:B:C,
+ * Cassandra follows a similar method, so we'll short circuit and do it more efficiently when there isn't a first hit
+ * @return
+ */
+ }
+}
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
index 0000000..39854d6
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public abstract class ArtifactDir implements PlaceArtifact {
+
+ protected static final String C_R = "\n";
+ protected File dir;
+ private List<String> encodeds = new ArrayList<String>();
+
+ private Symm symm;
+ // This checks for multiple passes of Dir on the same objects. Run clear after done.
+ protected static Map<String,Object> processed = new HashMap<String,Object>();
+
+
+ /**
+ * Note: Derived Classes should ALWAYS call "super.place(cert,arti)" first, and
+ * then "placeProperties(arti)" just after they implement
+ */
+ @Override
+ public final boolean place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ validate(arti);
+
+ try {
+ // Obtain/setup directory as required
+ dir = new File(arti.getDir());
+ if(processed.get("dir")==null) {
+ if(!dir.exists()) {
+ Chmod.to755.chmod(dir);
+ if(!dir.mkdirs()) {
+ throw new CadiException("Could not create " + dir);
+ }
+ }
+
+ // Also place cm_url and Host Name
+ addProperty(Config.CM_URL,trans.getProperty(Config.CM_URL));
+ addProperty(Config.HOSTNAME,arti.getMachine());
+ //addProperty(Config.AAF_ENV,certInfo.getEnv());
+ // Obtain Issuers
+ boolean first = true;
+ StringBuilder issuers = new StringBuilder();
+// for(String dn : certInfo.getCaIssuerDNs()) {
+// if(first) {
+// first=false;
+// } else {
+// issuers.append(':');
+// }
+// issuers.append(dn);
+// }
+ addProperty(Config.CADI_X509_ISSUERS,issuers.toString());
+ }
+ symm = (Symm)processed.get("symm");
+ if(symm==null) {
+ // CADI Key Gen
+ File f = new File(dir,arti.getAppName() + ".keyfile");
+ if(!f.exists()) {
+ write(f,Chmod.to400,Symm.baseCrypt().keygen());
+ }
+ symm = Symm.obtain(f);
+
+ addEncProperty("ChallengePassword", certInfo.getChallenge());
+
+ processed.put("symm",symm);
+ }
+
+ _place(trans, certInfo,arti);
+
+ placeProperties(arti);
+
+ processed.put("dir",dir);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ /**
+ * Derived Classes implement this instead, so Dir can process first, and write any Properties last
+ * @param cert
+ * @param arti
+ * @return
+ * @throws CadiException
+ */
+ protected abstract boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException;
+
+ protected void addProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append(value);
+ encodeds.add(sb.toString());
+ }
+
+ protected void addEncProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append("enc:???");
+ sb.append(symm.enpass(value));
+ encodeds.add(sb.toString());
+ }
+
+ protected void write(File f, Chmod c, String ... data) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ PrintStream ps = new PrintStream(fos);
+ try {
+ for(String s : data) {
+ ps.print(s);
+ }
+ } finally {
+ ps.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, byte[] bytes) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ fos.write(bytes);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, KeyStore ks, char[] pass ) throws IOException, CadiException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ ks.store(fos, pass);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+
+ private void validate(Artifact a) throws CadiException {
+ StringBuilder sb = new StringBuilder();
+ if(a.getDir()==null) {
+ sb.append("File Artifacts require a path");
+ }
+
+ if(a.getAppName()==null) {
+ if(sb.length()>0) {
+ sb.append('\n');
+ }
+ sb.append("File Artifacts require an AAF Namespace");
+ }
+
+ if(sb.length()>0) {
+ throw new CadiException(sb.toString());
+ }
+ }
+
+ private boolean placeProperties(Artifact arti) throws CadiException {
+ if(encodeds.size()==0) {
+ return true;
+ }
+ boolean first=processed.get("dir")==null;
+ try {
+ File f = new File(dir,arti.getAppName()+".props");
+ if(f.exists()) {
+ if(first) {
+ f.delete();
+ } else {
+ f.setWritable(true);
+ }
+ }
+ // Append if not first
+ PrintWriter pw = new PrintWriter(new FileWriter(f,!first));
+
+ // Write a Header
+ if(first) {
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ pw.println("# Properties Generated by AT&T Certificate Manager");
+ pw.print("# by ");
+ pw.println(System.getProperty("user.name"));
+ pw.print("# on ");
+ pw.println(Chrono.dateStamp());
+ pw.println("# @copyright 2016, AT&T");
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ for(String prop : encodeds) {
+ if( prop.startsWith("cm_")
+ || prop.startsWith(Config.HOSTNAME)
+ || prop.startsWith(Config.AAF_ENV)) {
+ pw.println(prop);
+ }
+ }
+ }
+
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("cadi")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to644.chmod(f);
+
+ if(first) {
+ // Challenge
+ f = new File(dir,arti.getAppName()+".chal");
+ if(f.exists()) {
+ f.delete();
+ }
+ pw = new PrintWriter(new FileWriter(f));
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("Challenge")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to400.chmod(f);
+ }
+ } catch(Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ public static void clear() {
+ processed.clear();
+ }
+
+}
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
index 0000000..a2694ce
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/CertException.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+public class CertException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1373028409048516401L;
+
+ public CertException() {
+ }
+
+ public CertException(String message) {
+ super(message);
+ }
+
+ public CertException(Throwable cause) {
+ super(cause);
+ }
+
+ public CertException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
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
index 0000000..424ef83
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/CmAgent.java
@@ -0,0 +1,711 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.aaf.client.ErrMessage;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.sso.AAFSSO;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import certman.v1_0.Artifacts;
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+import certman.v1_0.CertificateRequest;
+
+public class CmAgent {
+ private static final String PRINT = "print";
+ private static final String FILE = "file";
+ private static final String PKCS12 = "pkcs12";
+ private static final String JKS = "jks";
+ private static final String SCRIPT="script";
+
+ private static final String CM_VER = "1.0";
+ public static final int PASS_SIZE = 24;
+ private static int TIMEOUT;
+
+ private static RosettaDF<CertificateRequest> reqDF;
+ private static RosettaDF<CertInfo> certDF;
+ private static RosettaDF<Artifacts> artifactsDF;
+ private static ErrMessage errMsg;
+ private static Map<String,PlaceArtifact> placeArtifact;
+ private static RosettaEnv env;
+
+ public static void main(String[] args) {
+ int exitCode = 0;
+ try {
+ AAFSSO aafsso = new AAFSSO(args);
+ if(aafsso.loginOnly()) {
+ aafsso.setLogDefault();
+ aafsso.writeFiles();
+ System.out.println("AAF SSO information created in ~/.aaf");
+ } else {
+ PropAccess access = aafsso.access();
+ env = new RosettaEnv(access.getProperties());
+ Deque<String> cmds = new ArrayDeque<String>();
+ for(String p : args) {
+ if(p.indexOf('=')<0) {
+ cmds.add(p);
+ }
+ }
+
+ if(cmds.size()==0) {
+ aafsso.setLogDefault();
+ System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");
+ System.out.println(" create <mechID> [<machine>]");
+ System.out.println(" read <mechID> [<machine>]");
+ System.out.println(" update <mechID> [<machine>]");
+ System.out.println(" delete <mechID> [<machine>]");
+ System.out.println(" copy <mechID> <machine> <newmachine>[,<newmachine>]*");
+ System.out.println(" place <mechID> [<machine>]");
+ System.out.println(" showpass <mechID> [<machine>]");
+ System.out.println(" check <mechID> [<machine>]");
+ System.exit(1);
+ }
+
+ TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));
+
+ reqDF = env.newDataFactory(CertificateRequest.class);
+ artifactsDF = env.newDataFactory(Artifacts.class);
+ certDF = env.newDataFactory(CertInfo.class);
+ errMsg = new ErrMessage(env);
+
+ placeArtifact = new HashMap<String,PlaceArtifact>();
+ placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));
+ placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));
+ placeArtifact.put(FILE, new PlaceArtifactInFiles());
+ placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));
+ placeArtifact.put(SCRIPT, new PlaceArtifactScripts());
+
+ Trans trans = env.newTrans();
+ try {
+ // show Std out again
+ aafsso.setLogDefault();
+ aafsso.setStdErrDefault();
+
+ // if CM_URL can be obtained, add to sso.props, if written
+ String cm_url = getProperty(access,env,false, Config.CM_URL,Config.CM_URL+": ");
+ if(cm_url!=null) {
+ aafsso.addProp(Config.CM_URL, cm_url);
+ }
+ aafsso.writeFiles();
+
+ AAFCon<?> aafcon = new AAFConHttp(access,Config.CM_URL);
+
+ String cmd = cmds.removeFirst();
+ if("place".equals(cmd)) {
+ placeCerts(trans,aafcon,cmds);
+ } else if("create".equals(cmd)) {
+ createArtifact(trans, aafcon,cmds);
+ } else if("read".equals(cmd)) {
+ readArtifact(trans, aafcon, cmds);
+ } else if("copy".equals(cmd)) {
+ copyArtifact(trans, aafcon, cmds);
+ } else if("update".equals(cmd)) {
+ updateArtifact(trans, aafcon, cmds);
+ } else if("delete".equals(cmd)) {
+ deleteArtifact(trans, aafcon, cmds);
+ } else if("showpass".equals(cmd)) {
+ showPass(trans,aafcon,cmds);
+ } else if("check".equals(cmd)) {
+ try {
+ exitCode = check(trans,aafcon,cmds);
+ } catch (Exception e) {
+ exitCode = 1;
+ throw e;
+ }
+ } else {
+ AAFSSO.cons.printf("Unknown command \"%s\"\n", cmd);
+ }
+ } finally {
+ StringBuilder sb = new StringBuilder();
+ trans.auditTrail(4, sb, Trans.REMOTE);
+ if(sb.length()>0) {
+ trans.info().log("Trans Info\n",sb);
+ }
+ }
+ aafsso.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if(exitCode!=0) {
+ System.exit(exitCode);
+ }
+ }
+
+ private static String getProperty(PropAccess pa, Env env, boolean secure, String tag, String prompt, Object ... def) {
+ String value;
+ if((value=pa.getProperty(tag))==null) {
+ if(secure) {
+ value = new String(AAFSSO.cons.readPassword(prompt, def));
+ } else {
+ value = AAFSSO.cons.readLine(prompt,def).trim();
+ }
+ if(value!=null) {
+ if(value.length()>0) {
+ pa.setProperty(tag,value);
+ env.setProperty(tag,value);
+ } else if(def.length==1) {
+ value=def[0].toString();
+ pa.setProperty(tag,value);
+ env.setProperty(tag,value);
+ }
+ }
+ }
+ return value;
+ }
+
+ private static String mechID(Deque<String> cmds) {
+ if(cmds.size()<1) {
+ String alias = env.getProperty(Config.CADI_ALIAS);
+ return alias!=null?alias:AAFSSO.cons.readLine("MechID: ");
+ }
+ return cmds.removeFirst();
+ }
+
+ private static String machine(Deque<String> cmds) throws UnknownHostException {
+ if(cmds.size()>0) {
+ return cmds.removeFirst();
+ } else {
+ String mach = env.getProperty(Config.HOSTNAME);
+ return mach!=null?mach:InetAddress.getLocalHost().getHostName();
+ }
+ }
+
+ private static String[] machines(Deque<String> cmds) {
+ String machines;
+ if(cmds.size()>0) {
+ machines = cmds.removeFirst();
+ } else {
+ machines = AAFSSO.cons.readLine("Machines (sep by ','): ");
+ }
+ return Split.split(',', machines);
+ }
+
+ private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ Artifacts artifacts = new Artifacts();
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+ arti.setMechid(mechID!=null?mechID:AAFSSO.cons.readLine("MechID: "));
+ arti.setMachine(machine!=null?machine:AAFSSO.cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));
+ arti.setCa(AAFSSO.cons.readLine("CA: (%s): ","aaf"));
+
+ String resp = AAFSSO.cons.readLine("Types [file,jks,script] (%s): ", "jks");
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ String configRootName = AAFCon.reverseDomain(arti.getMechid());
+ arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",configRootName));
+ arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", System.getProperty("user.dir")));
+ arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", System.getProperty("user.name")));
+ arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renewal Days (%s):", "30")));
+ arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (mailto owner):", "")));
+
+ TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static String toNotification(String notification) {
+ if(notification==null) {
+ notification="";
+ } else if(notification.length()>0) {
+ if(notification.indexOf(':')<0) {
+ notification = "mailto:" + notification;
+ }
+ }
+ return notification;
+ }
+
+
+ private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Read Artifact", Env.SUB);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ AAFSSO.cons.printf("MechID: %s\n",a.getMechid());
+ AAFSSO.cons.printf(" Sponsor: %s\n",a.getSponsor());
+ AAFSSO.cons.printf("Machine: %s\n",a.getMachine());
+ AAFSSO.cons.printf("CA: %s\n",a.getCa());
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+ AAFSSO.cons.printf("Types: %s\n",sb);
+ AAFSSO.cons.printf("Namespace: %s\n",a.getAppName());
+ AAFSSO.cons.printf("Directory: %s\n",a.getDir());
+ AAFSSO.cons.printf("O/S User: %s\n",a.getOsUser());
+ AAFSSO.cons.printf("Renew Days: %d\n",a.getRenewDays());
+ AAFSSO.cons.printf("Notification %s\n",a.getNotification());
+ printed = true;
+ }
+ if(!printed) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+ String[] newmachs = machines(cmds);
+ if(newmachs==null || newmachs == null) {
+ trans.error().log("No machines listed to copy to");
+ } else {
+ TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ for(String m : newmachs) {
+ a.setMachine(m);
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+
+ printed = true;
+ }
+ }
+ if(!printed) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+ }
+
+ private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> fread = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(fread.get(TIMEOUT)) {
+ Artifacts artifacts = new Artifacts();
+ for(Artifact a : fread.value.getArtifact()) {
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+
+ AAFSSO.cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());
+ arti.setMechid(a.getMechid());
+ arti.setMachine(a.getMachine());
+ arti.setCa(AAFSSO.cons.readLine("CA: (%s): ",a.getCa()));
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+
+ String resp = AAFSSO.cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",a.getAppName()));
+ arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", a.getDir()));
+ arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", a.getOsUser()));
+ arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renew Days (%s):", a.getRenewDays())));
+ arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (%s):", a.getNotification())));
+
+ }
+ if(artifacts.getArtifact().size()==0) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ } else {
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+ }
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(fread),mechID,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechid = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);
+ try {
+ Future<Void> future = aafcon.client(CM_VER)
+ .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );
+
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(future),mechid,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+
+
+ private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ boolean rv = false;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("===> There are no artifacts for %s %s", mechID, machine);
+ } else {
+ for(Artifact a : acf.value.getArtifact()) {
+ String osID = System.getProperty("user.name");
+ if(a.getOsUser().equals(osID)) {
+ CertificateRequest cr = new CertificateRequest();
+ cr.setMechid(a.getMechid());
+ cr.setSponsor(a.getSponsor());
+ cr.getFqdns().add(a.getMachine());
+ Future<String> f = aafcon.client(CM_VER)
+ .setQueryParams("withTrust")
+ .updateRespondString("/cert/" + a.getCa(),reqDF, cr);
+ if(f.get(TIMEOUT)) {
+ CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();
+ for(String type : a.getType()) {
+ PlaceArtifact pa = placeArtifact.get(type);
+ if(pa!=null) {
+ if(rv = pa.place(trans, capi, a)) {
+ notifyPlaced(a,rv);
+ }
+ }
+ }
+ // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact
+ } else {
+ trans.error().log(errMsg.toMsg(f));
+ }
+ } else {
+ trans.error().log("You must be OS User \"" + a.getOsUser() +"\" to place Certificates on this box");
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+ return rv;
+ }
+
+ private static void notifyPlaced(Artifact a, boolean rv) {
+
+
+ }
+
+ private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Show Password", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ boolean allowed;
+ for(Artifact a : acf.value.getArtifact()) {
+ allowed = id!=null && (id.equals(a.getSponsor()) ||
+ (id.equals(a.getMechid())
+ && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));
+ if(!allowed) {
+ Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" +
+ a.getAppName() + ".certman|"+a.getCa()+"|showpass","*/*");
+ if(pf.get(TIMEOUT)) {
+ allowed = true;
+ } else {
+ trans.error().log(errMsg.toMsg(pf));
+ }
+ }
+ if(allowed) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ fis.close();
+ fis = new FileInputStream(new File(dir,a.getAppName()+".chal"));
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ File f = new File(dir,a.getAppName()+".keyfile");
+ if(f.exists()) {
+ Symm symm = Symm.obtain(f);
+
+ for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {
+ Entry<Object,Object> en = iter.next();
+ if(en.getValue().toString().startsWith("enc:???")) {
+ System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));
+ }
+ }
+ } else {
+ trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",
+ f.getAbsolutePath(),a.getMechid(), a.getMachine());
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+
+ }
+
+
+ /**
+ * Check returns Error Codes, so that Scripts can know what to do
+ *
+ * 0 - Check Complete, nothing to do
+ * 1 - General Error
+ * 2 - Error for specific Artifact - read check.msg
+ * 10 - Certificate Updated - check.msg is email content
+ *
+ * @param trans
+ * @param aafcon
+ * @param cmds
+ * @return
+ * @throws Exception
+ */
+ private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ int exitCode=1;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);
+ try {
+
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ GregorianCalendar now = new GregorianCalendar();
+ for(Artifact a : acf.value.getArtifact()) {
+ if(id.equals(a.getMechid())) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ String prop;
+ File f;
+
+ if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||
+ !(f=new File(prop)).exists()) {
+ trans.error().printf("Keyfile must exist to check Certificates for %s on %s",
+ a.getMechid(), a.getMachine());
+ } else {
+ String ksf = props.getProperty(Config.CADI_KEYSTORE);
+ String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);
+ if(ksf==null || ksps == null) {
+ trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",
+ Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());
+ } else {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ Symm symm = Symm.obtain(f);
+
+ fis = new FileInputStream(ksf);
+ try {
+ ks.load(fis,symm.depass(ksps).toCharArray());
+ } finally {
+ fis.close();
+ }
+ X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);
+ String msg = null;
+
+ if(cert==null) {
+ msg = String.format("X509Certificate does not exist for %s on %s in %s",
+ a.getMechid(), a.getMachine(), ksf);
+ trans.error().log(msg);
+ exitCode = 2;
+ } else {
+ GregorianCalendar renew = new GregorianCalendar();
+ renew.setTime(cert.getNotAfter());
+ renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());
+ if(renew.after(now)) {
+ 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",
+ a.getMechid(), a.getMachine(),Chrono.dateOnlyStamp(now),cert.getNotAfter(),Chrono.dateOnlyStamp(renew));
+ trans.info().log(msg);
+ exitCode = 0; // OK
+ } else {
+ trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n",
+ a.getMechid(), a.getMachine(),cert.getNotAfter());
+ cmds.offerLast(mechID);
+ cmds.offerLast(machine);
+ if(placeCerts(trans,aafcon,cmds)) {
+ msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 10; // Refreshed
+ } else {
+ msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 1; // Error Renewing
+ }
+ }
+ }
+ if(msg!=null) {
+ FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getAppName()+".msg");
+ try {
+ fos.write(msg.getBytes());
+ } finally {
+ fos.close();
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ exitCode=1;
+ }
+ } finally {
+ tt.done();
+ }
+ return exitCode;
+ }
+
+}
+
+
+
+
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
index 0000000..178cc81
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/Factory.java
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Collection;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import com.att.cadi.Symm;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+
+public class Factory {
+ private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";
+ public static final String KEY_ALGO = "RSA";
+ public static final String SIG_ALGO = "SHA256withRSA";
+
+ public static final int KEY_LENGTH = 2048;
+ private static final KeyPairGenerator keygen;
+ private static final KeyFactory keyFactory;
+ private static final CertificateFactory certificateFactory;
+ private static final SecureRandom random;
+
+
+ private static final Symm base64 = Symm.base64.copy(64);
+
+ static {
+ random = new SecureRandom();
+ KeyPairGenerator tempKeygen;
+ try {
+ tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");
+ tempKeygen.initialize(KEY_LENGTH, random);
+ } catch (NoSuchAlgorithmException e) {
+ tempKeygen = null;
+ e.printStackTrace(System.err);
+ }
+ keygen = tempKeygen;
+
+ KeyFactory tempKeyFactory;
+ try {
+ tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"
+ } catch (NoSuchAlgorithmException e) {
+ tempKeyFactory = null;
+ e.printStackTrace(System.err);
+ };
+ keyFactory = tempKeyFactory;
+
+ CertificateFactory tempCertificateFactory;
+ try {
+ tempCertificateFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ tempCertificateFactory = null;
+ e.printStackTrace(System.err);
+ }
+ certificateFactory = tempCertificateFactory;
+
+
+ }
+
+
+ public static KeyPair generateKeyPair(Trans trans) {
+ TimeTaken tt;
+ if(trans!=null) {
+ tt = trans.start("Generate KeyPair", Env.SUB);
+ } else {
+ tt = null;
+ }
+ try {
+ return keygen.generateKeyPair();
+ } finally {
+ if(tt!=null) {
+ tt.done();
+ }
+ }
+ }
+
+ private static final String LINE_END = "-----\n";
+
+ protected static String textBuilder(String kind, byte[] bytes) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append("-----BEGIN ");
+ sb.append(kind);
+ sb.append(LINE_END);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ base64.encode(bais, baos);
+ sb.append(new String(baos.toByteArray()));
+
+ if(sb.charAt(sb.length()-1)!='\n') {
+ sb.append('\n');
+ }
+ sb.append("-----END ");
+ sb.append(kind);
+ sb.append(LINE_END);
+ return sb.toString();
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {
+ byte[] bytes = decode(new StringReader(pk));
+ return toPrivateKey(trans, bytes);
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {
+ TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);
+ try {
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+ } catch (InvalidKeySpecException e) {
+ throw new CertException("Translating Private Key from PKCS8 KeySpec",e);
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {
+ TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);
+ try {
+ return toPrivateKey(trans,decode(file));
+ }finally {
+ tt.done();
+ }
+ }
+
+ public static String toString(Trans trans, PrivateKey pk) throws IOException {
+// PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());
+ trans.debug().log("Private Key to String");
+ return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());
+ }
+
+ public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {
+ TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);
+ try {
+ ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64noSplit.decode(bais, baos);
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));
+ } catch (InvalidKeySpecException e) {
+ trans.error().log(e,"Translating Public Key from X509 KeySpec");
+ return null;
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static String toString(Trans trans, PublicKey pk) throws IOException {
+ trans.debug().log("Public Key to String");
+ return textBuilder("PUBLIC KEY",pk.getEncoded());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(String x509) throws CertificateException {
+ return toX509Certificate(x509.getBytes());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(List<String> x509s) throws CertificateException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ for(String x509 : x509s) {
+ baos.write(x509.getBytes());
+ }
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ return toX509Certificate(new ByteArrayInputStream(baos.toByteArray()));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(byte[] x509) throws CertificateException {
+ return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ return toX509Certificate(fis);
+ } finally {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(InputStream is) throws CertificateException {
+ return certificateFactory.generateCertificates(is);
+ }
+
+ public static String toString(Trans trans, Certificate cert) throws IOException, CertException {
+ if(trans.debug().isLoggable()) {
+ StringBuilder sb = new StringBuilder("Certificate to String");
+ if(cert instanceof X509Certificate) {
+ sb.append(" - ");
+ sb.append(((X509Certificate)cert).getSubjectDN());
+ }
+ trans.debug().log(sb);
+ }
+ try {
+ if(cert==null) {
+ throw new CertException("Certificate not built");
+ }
+ return textBuilder("CERTIFICATE",cert.getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new CertException(e);
+ }
+ }
+
+ public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
+ return Cipher.getInstance(KEY_ALGO);
+ }
+
+ public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ Cipher cipher = Cipher.getInstance(KEY_ALGO);
+ cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);
+ return cipher;
+ }
+
+ public static byte[] strip(Reader rdr) throws IOException {
+ BufferedReader br = new BufferedReader(rdr);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ String line;
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ baos.write(line.getBytes());
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ public static class StripperInputStream extends InputStream {
+ private Reader created;
+ private BufferedReader br;
+ private int idx;
+ private String line;
+
+ public StripperInputStream(Reader rdr) {
+ if(rdr instanceof BufferedReader) {
+ br = (BufferedReader)rdr;
+ } else {
+ br = new BufferedReader(rdr);
+ }
+ created = null;
+ }
+
+ public StripperInputStream(File file) throws FileNotFoundException {
+ this(new FileReader(file));
+ created = br;
+ }
+
+ public StripperInputStream(InputStream is) throws FileNotFoundException {
+ this(new InputStreamReader(is));
+ created = br;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(line==null || idx>=line.length()) {
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ break;
+ }
+ }
+
+ if(line==null) {
+ return -1;
+ }
+ idx = 0;
+ }
+ return line.charAt(idx++);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static class Base64InputStream extends InputStream {
+ private InputStream created;
+ private InputStream is;
+ private byte trio[];
+ private byte duo[];
+ private int idx;
+
+
+ public Base64InputStream(File file) throws FileNotFoundException {
+ this(new FileInputStream(file));
+ created = is;
+ }
+
+ public Base64InputStream(InputStream is) throws FileNotFoundException {
+ this.is = is;
+ trio = new byte[3];
+ idx = 4;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(duo==null || idx>=duo.length) {
+ int read = is.read(trio);
+ if(read==-1) {
+ return -1;
+ }
+ duo = Symm.base64.decode(trio);
+ if(duo==null || duo.length==0) {
+ return -1;
+ }
+ idx=0;
+ }
+
+ return duo[idx++];
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static byte[] decode(byte[] bytes) throws IOException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64.decode(bais, baos);
+ return baos.toByteArray();
+ }
+
+ public static byte[] decode(File f) throws IOException {
+ FileReader fr = new FileReader(f);
+ try {
+ return Factory.decode(fr);
+ } finally {
+ fr.close();
+ }
+
+ }
+ public static byte[] decode(Reader rdr) throws IOException {
+ return decode(strip(rdr));
+ }
+
+
+ public static byte[] binary(File file) throws IOException {
+ DataInputStream dis = new DataInputStream(new FileInputStream(file));
+ try {
+ byte[] bytes = new byte[(int)file.length()];
+ dis.readFully(bytes);
+ return bytes;
+ } finally {
+ dis.close();
+ }
+ }
+
+
+ public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
+ TimeTaken tt = trans.start("Sign Data", Env.SUB);
+ try {
+ Signature sig = Signature.getInstance(SIG_ALGO);
+ sig.initSign(pk, random);
+ sig.update(bytes);
+ return sig.sign();
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static String toSignatureString(byte[] signed) throws IOException {
+ return textBuilder("SIGNATURE", signed);
+ }
+
+ public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ TimeTaken tt = trans.start("Verify Data", Env.SUB);
+ try {
+ Signature sig = Signature.getInstance(SIG_ALGO);
+ sig.initVerify(pk);
+ sig.update(bytes);
+ return sig.verify(signature);
+ } finally {
+ tt.done();
+ }
+ }
+}
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
index 0000000..b5a3fb0
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.Trans;
+
+public interface PlaceArtifact {
+ public boolean place(Trans trans, CertInfo cert, Artifact arti) throws CadiException;
+}
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
index 0000000..219eb4a
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactInFiles extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup Public Cert
+ File f = new File(dir,arti.getAppName()+".crt");
+ write(f,Chmod.to644,certInfo.getCerts().get(0),C_R);
+
+ // Setup Private Key
+ f = new File(dir,arti.getAppName()+".key");
+ write(f,Chmod.to400,certInfo.getPrivatekey(),C_R);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+}
+
+
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
index 0000000..6859ba5
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactInKeystore extends ArtifactDir {
+ private String kst;
+ //TODO get ROOT DNs or Trusted DNs from Certificate Manager.
+// private static String[] rootDNs = new String[]{
+// "CN=ATT CADI Root CA - Test, O=ATT, OU=CSO, C=US", // Lab. delete eventually
+// "CN=ATT AAF CADI TEST CA, OU=CSO, O=ATT, C=US",
+// "CN=ATT AAF CADI CA, OU=CSO, O=ATT, C=US"
+// };
+
+ public PlaceArtifactInKeystore(String kst) {
+ this.kst = kst;
+ }
+
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ File fks = new File(dir,arti.getAppName()+'.'+kst);
+ try {
+ KeyStore jks = KeyStore.getInstance(kst);
+ if(fks.exists()) {
+ fks.delete();
+ }
+
+ // Get the Cert(s)... Might include Trust store
+ Collection<? extends Certificate> certColl = Factory.toX509Certificate(certInfo.getCerts());
+ X509Certificate[] certs = new X509Certificate[certColl.size()];
+ certColl.toArray(certs);
+
+
+ // Add CADI Keyfile Entry to Properties
+ addProperty(Config.CADI_KEYFILE,arti.getDir()+'/'+arti.getAppName() + ".keyfile");
+ // Set Keystore Password
+ addProperty(Config.CADI_KEYSTORE,fks.getAbsolutePath());
+ String keystorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_KEYSTORE_PASSWORD,keystorePass);
+ char[] keystorePassArray = keystorePass.toCharArray();
+ jks.load(null,keystorePassArray); // load in
+
+ // Add Private Key/Cert Entry for App
+ // Note: Java SSL security classes, while having a separate key from keystore,
+ // is documented to not actually work.
+ // java.security.UnrecoverableKeyException: Cannot recover key
+ // You can create a custom Key Manager to make it work, but Practicality
+ // dictates that you live with the default, meaning, they are the same
+ String keyPass = keystorePass; //Symm.randomGen(CmAgent.PASS_SIZE);
+ PrivateKey pk = Factory.toPrivateKey(trans, certInfo.getPrivatekey());
+ addEncProperty(Config.CADI_KEY_PASSWORD, keyPass);
+ addProperty(Config.CADI_ALIAS, arti.getMechid());
+// Set<Attribute> attribs = new HashSet<Attribute>();
+// if(kst.equals("pkcs12")) {
+// // Friendly Name
+// attribs.add(new PKCS12Attribute("1.2.840.113549.1.9.20", arti.getAppName()));
+// }
+//
+ KeyStore.ProtectionParameter protParam =
+ new KeyStore.PasswordProtection(keyPass.toCharArray());
+
+ KeyStore.PrivateKeyEntry pkEntry =
+ new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]});
+ jks.setEntry(arti.getMechid(),
+ pkEntry, protParam);
+
+ // Write out
+ write(fks,Chmod.to400,jks,keystorePassArray);
+
+ // Change out to TrustStore
+ fks = new File(dir,arti.getAppName()+".trust."+kst);
+ jks = KeyStore.getInstance(kst);
+
+ // Set Truststore Password
+ addProperty(Config.CADI_TRUSTSTORE,fks.getAbsolutePath());
+ String trustStorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_TRUSTSTORE_PASSWORD,trustStorePass);
+ char[] truststorePassArray = trustStorePass.toCharArray();
+ jks.load(null,truststorePassArray); // load in
+
+ // Add Trusted Certificates
+ for(int i=1; i<certs.length;++i) {
+ jks.setCertificateEntry("cadi_root_" + arti.getCa() + '_' + i, certs[i]);
+ }
+ // Write out
+ write(fks,Chmod.to644,jks,truststorePassArray);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return false;
+ }
+
+}
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
index 0000000..7815a8e
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.PrintStream;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactOnStream implements PlaceArtifact {
+ private PrintStream out;
+
+ public PlaceArtifactOnStream(PrintStream printStream) {
+ out = printStream;
+ }
+
+ @Override
+ public boolean place(Trans trans, CertInfo capi, Artifact a) {
+ if(capi.getNotes()!=null && capi.getNotes().length()>0) {
+ trans.info().printf("Warning: %s\n",capi.getNotes());
+ }
+ out.printf("Challenge: %s\n",capi.getChallenge());
+ out.printf("PrivateKey:\n%s\n",capi.getPrivatekey());
+ out.println("Certificate Chain:");
+ for(String c : capi.getCerts()) {
+ out.println(c);
+ }
+ return true;
+ }
+}
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
index 0000000..ab77ca2
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactScripts extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup check.sh script
+ String filename = arti.getAppName()+".check.sh";
+ File f1 = new File(dir,filename);
+ String email = arti.getNotification() + '\n';
+ if(email.startsWith("mailto:")) {
+ email=email.substring(7);
+ } else {
+ email=arti.getOsUser() + '\n';
+ }
+
+ StringBuilder classpath = new StringBuilder();
+ boolean first = true;
+ for(String pth : Split.split(File.pathSeparatorChar, System.getProperty("java.class.path"))) {
+ if(first) {
+ first=false;
+ } else {
+ classpath.append(File.pathSeparatorChar);
+ }
+ File f = new File(pth);
+ classpath.append(f.getCanonicalPath().replaceAll("[0-9]+\\.[0-9]+\\.[0-9]+","*"));
+ }
+
+ write(f1,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Check Script\n",
+ "# Check on Certificate, and renew if needed.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "DIR="+arti.getDir()+'\n',
+ "APP="+arti.getAppName()+'\n',
+ "EMAIL="+email,
+ "CP=\""+classpath.toString()+"\"\n",
+ checkScript
+ );
+
+ // Setup check.sh script
+ File f2 = new File(dir,arti.getAppName()+".crontab.sh");
+ write(f2,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Crontab Loading Script\n",
+ "# Add/Update a Crontab entry, that adds a check on Certificate Manager generated Certificate nightly.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "TFILE=\"/tmp/cmcron$$.temp\"\n",
+ "DIR=\""+arti.getDir()+"\"\n",
+ "CF=\""+arti.getAppName()+" Certificate Check Script\"\n",
+ "SCRIPT=\""+f1.getCanonicalPath()+"\"\n",
+ cronScript
+ );
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ private final static String checkScript =
+ "> $DIR/$APP.msg\n\n" +
+ "function mailit {\n" +
+ " printf \"$*\" | /bin/mail -s \"AAF Certman Notification for `uname -n`\" $EMAIL\n"+
+ "}\n\n" +
+ System.getProperty("java.home") + "/bin/" +"java -cp $CP " +
+ CmAgent.class.getName() +
+ " cadi_prop_files=$DIR/$APP.props check 2> $DIR/$APP.STDERR > $DIR/$APP.STDOUT\n" +
+ "case \"$?\" in\n" +
+ " 0)\n" +
+ " # Note: Validation will be mailed only the first day after any modification\n" +
+ " if [ \"`find $DIR -mtime 0 -name $APP.check.sh`\" != \"\" ] ; then\n" +
+ " mailit `echo \"Certficate Validated:\\n\\n\" | cat - $DIR/$APP.msg`\n" +
+ " else\n" +
+ " cat $DIR/$APP.msg\n" +
+ " fi\n" +
+ " ;;\n" +
+ " 1) mailit \"Error with Certificate Check:\\\\n\\\\nCheck logs $DIR/$APP.STDOUT and $DIR/$APP.STDERR on `uname -n`\"\n" +
+ " ;;\n" +
+ " 2) mailit `echo \"Certificate Check Error\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " 10) mailit `echo \"Certificate Replaced\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " if [ -e $DIR/$APP.restart.sh ]; then\n" +
+ " # Note: it is THIS SCRIPT'S RESPONSIBILITY to notify upon success or failure as necessary!!\n" +
+ " /bin/sh $DIR/$APP.restart.sh\n" +
+ " fi\n" +
+ " ;;\n" +
+ " *) mailit `echo \"Unknown Error code for CM Agent\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " esac\n\n" +
+ " # Note: make sure to cover this sripts' exit Code\n";
+
+ private final static String cronScript =
+ "crontab -l | sed -n \"/#### BEGIN $CF/,/END $CF ####/!p\" > $TFILE\n" +
+ "# Note: Randomize Minutes (0-60) and hours (1-4)\n" +
+ "echo \"#### BEGIN $CF ####\" >> $TFILE\n" +
+ "echo \"$(( $RANDOM % 60)) $(( $(( $RANDOM % 3 )) + 1 )) * * * /bin/bash $SCRIPT " +
+ ">> $DIR/cronlog 2>&1 \" >> $TFILE\n" +
+ "echo \"#### END $CF ####\" >> $TFILE\n" +
+ "crontab $TFILE\n" +
+ "rm $TFILE\n";
+}
+
+
+
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
index 0000000..5d0d342
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/sso/AAFSSO.java
@@ -0,0 +1,286 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.sso;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.CadiException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.MyConsole;
+import com.att.cadi.util.SubStandardConsole;
+import com.att.cadi.util.TheConsole;
+
+
+public class AAFSSO {
+ public static final MyConsole cons = TheConsole.implemented()?new TheConsole():new SubStandardConsole();
+
+ private Properties diskprops = null; // use for temp storing User/Password on disk
+ private File dot_aaf = null, sso=null; // instantiated, if ever, with diskprops
+
+ boolean removeSSO=false;
+ boolean loginOnly = false;
+ private PropAccess access;
+ private StringBuilder err;
+ private String user,encrypted_pass;
+ private boolean use_X509;
+
+ private PrintStream os, stdout=null,stderr=null;
+
+ private Method close;
+
+ public AAFSSO(String[] args) throws IOException, CadiException {
+ List<String> larg = new ArrayList<String>(args.length);
+
+ // Cover for bash's need to escape *... (\\*)
+ // also, remove SSO if required
+ for (int i = 0; i < args.length; ++i) {
+ if ("\\*".equals(args[i])) {
+ args[i] = "*";
+ }
+
+ if("-logout".equalsIgnoreCase(args[i])) {
+ removeSSO=true;
+ } else if("-login".equalsIgnoreCase(args[i])) {
+ loginOnly = true;
+ } else {
+ larg.add(args[i]);
+ }
+ }
+
+ String[] nargs = new String[larg.size()];
+ larg.toArray(nargs);
+
+ dot_aaf = new File(System.getProperty("user.home")+"/.aaf");
+ if(!dot_aaf.exists()) {
+ dot_aaf.mkdirs();
+ }
+ File f = new File(dot_aaf,"sso.out");
+ os = new PrintStream(new FileOutputStream(f,true));
+ stdout = System.out;
+ stderr = System.err;
+ System.setOut(os);
+ System.setErr(os);
+
+ access = new PropAccess(os,nargs);
+ Config.setDefaultRealm(access);
+
+ user = access.getProperty(Config.AAF_MECHID);
+ encrypted_pass = access.getProperty(Config.AAF_MECHPASS);
+
+ File dot_aaf_kf = new File(dot_aaf,"keyfile");
+
+ sso = new File(dot_aaf,"sso.props");
+ if(removeSSO) {
+ if(dot_aaf_kf.exists()) {
+ dot_aaf_kf.setWritable(true,true);
+ dot_aaf_kf.delete();
+ }
+ if(sso.exists()) {
+ sso.delete();
+ }
+ System.out.println("AAF SSO information removed");
+ System.exit(0);
+ }
+
+ if(!dot_aaf_kf.exists()) {
+ FileOutputStream fos = new FileOutputStream(dot_aaf_kf);
+ try {
+ fos.write(Symm.encrypt.keygen());
+ dot_aaf_kf.setExecutable(false,false);
+ dot_aaf_kf.setWritable(false,false);
+ dot_aaf_kf.setReadable(false,false);
+ dot_aaf_kf.setReadable(true, true);
+ } finally {
+ fos.close();
+ }
+ }
+
+ String keyfile = access.getProperty(Config.CADI_KEYFILE); // in case it's CertificateMan props
+ if(keyfile==null) {
+ access.setProperty(Config.CADI_KEYFILE, dot_aaf_kf.getAbsolutePath());
+ }
+
+ String alias = access.getProperty(Config.CADI_ALIAS);
+ if(user==null && alias!=null && access.getProperty(Config.CADI_KEYSTORE_PASSWORD)!=null) {
+ user = alias;
+ access.setProperty(Config.AAF_MECHID, user);
+ use_X509 = true;
+ } else {
+ use_X509 = false;
+ Symm decryptor = Symm.obtain(dot_aaf_kf);
+ if (user==null) {
+ if(sso.exists() && sso.lastModified()>System.currentTimeMillis()-(8*60*60*1000 /* 8 hours */)) {
+ String cm_url = access.getProperty(Config.CM_URL); // SSO might overwrite...
+ FileInputStream fos = new FileInputStream(sso);
+ try {
+ access.load(fos);
+ user = access.getProperty(Config.AAF_MECHID);
+ encrypted_pass = access.getProperty(Config.AAF_MECHPASS);
+ // decrypt with .aaf, and re-encrypt with regular Keyfile
+ access.setProperty(Config.AAF_MECHPASS,
+ access.encrypt(decryptor.depass(encrypted_pass)));
+ if(cm_url!=null) { //Command line CM_URL Overwrites ssofile.
+ access.setProperty(Config.CM_URL, cm_url);
+ }
+ } finally {
+ fos.close();
+ }
+ } else {
+ diskprops = new Properties();
+ String realm = Config.getDefaultRealm();
+ // Turn on Console Sysout
+ System.setOut(stdout);
+ user=cons.readLine("aaf_id(%s@%s): ",System.getProperty("user.name"),realm);
+ if(user==null) {
+ user = System.getProperty("user.name")+'@'+realm;
+ } else if(user.length()==0) { //
+ user = System.getProperty("user.name")+'@' + realm;
+ } else if(user.indexOf('@')<0 && realm!=null) {
+ user = user+'@'+realm;
+ }
+ access.setProperty(Config.AAF_MECHID,user);
+ diskprops.setProperty(Config.AAF_MECHID,user);
+ encrypted_pass = new String(cons.readPassword("aaf_password: "));
+ System.setOut(os);
+ encrypted_pass = Symm.ENC+decryptor.enpass(encrypted_pass);
+ access.setProperty(Config.AAF_MECHPASS,encrypted_pass);
+ diskprops.setProperty(Config.AAF_MECHPASS,encrypted_pass);
+ diskprops.setProperty(Config.CADI_KEYFILE, access.getProperty(Config.CADI_KEYFILE));
+ }
+ }
+ }
+ if (user == null) {
+ err = new StringBuilder("Add -D" + Config.AAF_MECHID + "=<id> ");
+ }
+
+ if (encrypted_pass == null && alias==null) {
+ if (err == null) {
+ err = new StringBuilder();
+ } else {
+ err.append("and ");
+ }
+ err.append("-D" + Config.AAF_MECHPASS + "=<passwd> ");
+ }
+ }
+
+ public void setLogDefault() {
+ access.setLogLevel(PropAccess.DEFAULT);
+ if(stdout!=null) {
+ System.setOut(stdout);
+ }
+ }
+
+ public void setStdErrDefault() {
+ access.setLogLevel(PropAccess.DEFAULT);
+ if(stderr!=null) {
+ System.setErr(stderr);
+ }
+ }
+
+ public void setLogDefault(Level level) {
+ access.setLogLevel(level);
+ if(stdout!=null) {
+ System.setOut(stdout);
+ }
+ }
+
+ public boolean loginOnly() {
+ return loginOnly;
+ }
+
+ public void addProp(String key, String value) {
+ if(diskprops!=null) {
+ diskprops.setProperty(key, value);
+ }
+ }
+
+ public void writeFiles() throws IOException {
+ // Store Creds, if they work
+ if(diskprops!=null) {
+ if(!dot_aaf.exists()) {
+ dot_aaf.mkdirs();
+ }
+ FileOutputStream fos = new FileOutputStream(sso);
+ try {
+ diskprops.store(fos, "AAF Single Signon");
+ } finally {
+ fos.close();
+ sso.setWritable(false,false);
+ sso.setExecutable(false,false);
+ sso.setReadable(false,false);
+ sso.setReadable(true,true);
+ }
+ }
+ if(sso!=null) {
+ sso.setReadable(false,false);
+ sso.setWritable(false,false);
+ sso.setExecutable(false,false);
+ sso.setReadable(true,true);
+ sso.setWritable(true,true);
+ }
+ }
+
+ public PropAccess access() {
+ return access;
+ }
+
+ public StringBuilder err() {
+ return err;
+ }
+
+ public String user() {
+ return user;
+ }
+
+ public String enc_pass() {
+ return encrypted_pass;
+ }
+
+ public boolean useX509() {
+ return use_X509;
+ }
+
+ public void close() {
+ if(close!=null) {
+ try {
+ close.invoke(null);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ // nothing to do here.
+ }
+ close = null;
+ }
+ }
+}
diff --git a/aaf/src/src/assemble/cadi-aaf-test.xml b/aaf/src/src/assemble/cadi-aaf-test.xml
new file mode 100644
index 0000000..a6671ba
--- /dev/null
+++ b/aaf/src/src/assemble/cadi-aaf-test.xml
@@ -0,0 +1,110 @@
+<!--
+ ============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.
+ *
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>test</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.cadi:cadi-core</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.cadi:cadi-aaf</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>org.eclipse.jetty.aggregate:jetty-all</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>org.eclipse.jetty.orbit:javax.servlet</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>javax:servlet</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.aft:dme2</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>test</scope>
+ <includes>
+ <include>com.att.aft.discovery:discovery-clt</include>
+ </includes>
+ </dependencySet>
+ <dependencySet>
+ <unpack>false</unpack>
+ <scope>compile</scope>
+ <includes>
+ <include>com.att.cssa:rosetta</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>run</directory>
+ <includes>
+ <include>cadi.properties</include>
+ <include>keyfile</include>
+ <include>start.sh</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <includes>
+ <include>../cadi/target/cadi-core*tests.jar</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/aaf/src/src/assemble/cadi-aaf.xml b/aaf/src/src/assemble/cadi-aaf.xml
new file mode 100644
index 0000000..578037b
--- /dev/null
+++ b/aaf/src/src/assemble/cadi-aaf.xml
@@ -0,0 +1,53 @@
+<!--
+ ============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.
+ *
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>full</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <unpack>true</unpack>
+ <scope>compile</scope>
+ <includes>
+ <include>com.att.authz:authz-client</include>
+ <include>com.att.cadi:cadi-aaf</include>
+ <include>com.att.cadi:cadi-core</include>
+ <include>com.att.cadi:cadi-client</include>
+ <include>com.att.inno:env</include>
+ <include>com.att.inno:rosetta</include>
+ </includes>
+ </dependencySet>
+
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>src/main/xsd</directory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/aaf/src/src/main/java/Examples.java b/aaf/src/src/main/java/Examples.java
new file mode 100644
index 0000000..91f313f
--- /dev/null
+++ b/aaf/src/src/main/java/Examples.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+import com.att.rosetta.env.RosettaEnv;
+
+public class Examples {
+ public static void main(String[] args) {
+ if(args.length<1) {
+ System.out.println("Usage: Examples <name> [\"optional\" - will show optional fields]");
+ } else {
+ boolean options = args.length>1&&"optional".equals(args[1]);
+ try {
+ RosettaEnv env = new RosettaEnv();
+ System.out.println(com.att.cadi.aaf.client.Examples.print(env, args[0], options));
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ }
+
+
+}
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
index 0000000..c436db4
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/AAFPermission.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import com.att.cadi.Permission;
+
+/**
+ * A Class that understands the AAF format of Permission (name/type/action)
+ * or String "name|type|action"
+ *
+ *
+ */
+public class AAFPermission implements Permission {
+ protected String type,instance,action,key;
+
+ protected AAFPermission() {}
+
+ public AAFPermission(String type, String instance, String action) {
+ this.type = type;
+ this.instance = instance;
+ this.action = action;
+ key = type + '|' + instance + '|' + action;
+ }
+
+ /**
+ * Match a Permission
+ * if Permission is Fielded type "Permission", we use the fields
+ * otherwise, we split the Permission with '|'
+ *
+ * when the type or action starts with REGEX indicator character ( ! ),
+ * then it is evaluated as a regular expression.
+ *
+ * If you want a simple field comparison, it is faster without REGEX
+ */
+ public boolean match(Permission p) {
+ if(p instanceof AAFPermission) {
+ AAFPermission ap = (AAFPermission)p;
+ // Note: In AAF > 1.0, Accepting "*" from name would violate multi-tenancy
+ // Current solution is only allow direct match on Type.
+ // 8/28/2014 - added REGEX ability
+ if(type.equals(ap.getName()))
+ if(PermEval.evalInstance(instance,ap.getInstance()))
+ if(PermEval.evalAction(action,ap.getAction()))
+ return true;
+ } else {
+ // Permission is concatenated together: separated by |
+ String[] aaf = p.getKey().split("[\\s]*\\|[\\s]*",3);
+ if(aaf.length>0 && type.equals(aaf[0]))
+ if(PermEval.evalInstance(instance,aaf.length>1?aaf[1]:"*"))
+ if(PermEval.evalAction(action,aaf.length>2?aaf[2]:"*"))
+ return true;
+ }
+ return false;
+ }
+
+
+ public String getName() {
+ return type;
+ }
+
+ public String getInstance() {
+ return instance;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Permission#permType()
+ */
+ public String permType() {
+ return "AAF";
+ }
+
+ public String toString() {
+ return "AAFPermission:\n\tType: " + type +
+ "\n\tInstance: " + instance +
+ "\n\tAction: " + action +
+ "\n\tKey: " + key;
+ }
+}
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
index 0000000..fca8e8f
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import java.security.Principal;
+import java.util.regex.Pattern;
+
+import com.att.cadi.Transmutate;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CSPPrincipal_T;
+
+/**
+ * AAFTransmutate
+ *
+ * Each System determines the mechanisms for which one Principal is transmutated to another, such as whether it is created
+ * independently, etc.
+ *
+ * For AAF, the only important thing is that these are valid ATTUID/mechIDs, to avoid unnecessary user hits
+ *
+ * attUIDs look like ab1234 or AB1234 or AZ123a
+ * mechids look like m12345
+ *
+ *
+ */
+public final class AAFTransmutate implements Transmutate<Principal> {
+ private Pattern pattern = Pattern.compile("[a-zA-Z]\\w\\d\\d\\d\\w");
+
+ public Principal mutate(Principal p) {
+ // Accept these three internal kinds of Principals
+ if(p instanceof CSPPrincipal_T
+ || p instanceof BasicPrincipal
+ || p instanceof ConfigPrincipal) {
+ return p;
+ } else {
+ String name = p.getName();
+ final int idx = name.indexOf('@');
+ if(idx>0) { // strip off any domain
+ name = name.substring(0,idx);
+ }
+
+ // Check for ATTUID specs before creating CSP_T
+ return pattern.matcher(name).matches()?
+ new CSP_T(name):
+ null;
+ }
+ }
+
+ /**
+ * Essential Principal reflecting CSP Principal
+ *
+ *
+ */
+ private final class CSP_T implements CSPPrincipal_T {
+ private String name;
+ public CSP_T(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return name;
+ }
+ }
+}
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
index 0000000..b721968
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/PermEval.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf;
+
+import com.att.inno.env.util.Split;
+
+
+public class PermEval {
+ public static final char START_REGEX_CHAR = '!';
+ public static final char START_INST_KEY_CHAR=':';
+ public static final char ALT_START_INST_KEY_CHAR='/';
+
+ public static final char LIST_SEP = ',';
+ public static final String INST_KEY_REGEX = new StringBuilder().append(START_INST_KEY_CHAR).toString();
+ public static final String ASTERIX = "*";
+
+ /**
+ * Evaluate Instance
+ *
+ * Instance can be more complex. It can be a string, a Regular Expression, or a ":" separated Key
+ * who's parts can also be a String, Regular Expression.
+ *
+ * sInst = Server's Instance
+ * In order to prevent false matches, keys must be the same length to count as equal
+ * Changing this will break existing users, like Cassandra. 9-4-2015
+ */
+ public static boolean evalInstance(String sInst, String pInst) {
+ if(ASTERIX.equals(sInst)) return true; // If Server's String is "*", then it accepts every Instance
+ char firstChar = pInst.charAt(0);
+ char startChar = firstChar==ALT_START_INST_KEY_CHAR?ALT_START_INST_KEY_CHAR:START_INST_KEY_CHAR;
+ switch(pInst.charAt(0)) { // First char
+ case START_REGEX_CHAR: // Evaluate as Regular Expression
+ String pItem = pInst.substring(1);
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," definition in Action
+ return sItem.matches(pItem);
+ }
+
+ case START_INST_KEY_CHAR: // Evaluate a special Key field, i.e.:xyz:*:!df.*
+ case ALT_START_INST_KEY_CHAR: // Also allow '/' as special Key Field, i.e. /xyz/*/!.*
+ if(sInst.charAt(0)==startChar) { // To compare key-to-key, both strings must be keys
+ String[] skeys=Split.split(startChar,sInst);
+ String[] pkeys=Split.split(startChar,pInst);
+ if(skeys.length!=pkeys.length) return false;
+
+ boolean pass = true;
+ for(int i=1;pass && i<skeys.length;++i) { // We start at 1, because the first one, being ":" is always ""
+ if(ASTERIX.equals(skeys[i]))continue; // Server data accepts all for this key spot
+ pass = false;
+ for(String sItem : Split.split(LIST_SEP,skeys[i])) { // allow for "," definition in Action
+ if(pkeys[i].length()==0) {
+ if(pass=sItem.length()==0) {
+ break; // Both Empty, keep checking
+ }
+// } else if(pkeys[i].charAt(0)==START_REGEX_CHAR) {
+// if(pass=sItem.matches(pkeys[i].substring(1))) {
+// break; // Matches, keep checking
+// }
+ } else if(sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like *
+ if(pass=pkeys[i].matches(sItem.substring(1))) {
+ break; // Matches, keep checking
+ }
+ } else if(skeys[i].endsWith(ASTERIX)) {
+ if(pass=endAsterixCompare(skeys[i],pkeys[i])) {
+ break;
+ }
+ } else {
+ if(pass=sItem.equals(pkeys[i]))
+ break; // Equal, keep checking
+ }
+ }
+ }
+ return pass; // return whether passed all key checks
+ }
+ return false; // if first chars aren't the same, further String compare not necessary
+ default: // Evaluate as String Compare
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," separator //TODO is this only for actions?
+ if(sItem.endsWith(ASTERIX)) {
+ if(endAsterixCompare(sInst, pInst));
+ } else if(sItem.equals(pInst)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static boolean endAsterixCompare(String sInst, String pInst) {
+ final int len = sInst.length()-1;
+ if(pInst.length()<len) {
+ return false;
+ }
+ for(int j=0;j<len;++j) {
+ if(pInst.charAt(j)!=sInst.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Evaluate Action
+ *
+ * sAction = Stored Action...
+ * pAction = Present Action... the Permission to validate against.
+ * Action is not quite as complex. But we write it in this function so it can be consistent
+ */
+ public static boolean evalAction(String sAction,String pAction) {
+ if(ASTERIX.equals(sAction))return true; // If Server's String is "*", then it accepts every Action
+ for(String sItem : Split.split(LIST_SEP,sAction)) { // allow for "," definition in Action
+ if (pAction.charAt(0)==START_REGEX_CHAR? // First char
+ sItem.matches(pAction.substring(1)): // Evaluate as Regular Expression
+ sItem.equals(pAction)) // Evaluate as String Compare
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Split.split by Char
+ *
+ * Note: I read the String Split.split and Pattern Split.split code, and we can do this more efficiently for a single Character
+ */
+
+}
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
index 0000000..7fc776a
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.client;
+
+import java.io.PrintStream;
+
+import aaf.v2_0.Error;
+
+import com.att.cadi.client.Future;
+import com.att.cadi.util.Vars;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class ErrMessage {
+ private RosettaDF<Error> errDF;
+
+ public ErrMessage(RosettaEnv env) throws APIException {
+ errDF = env.newDataFactory(Error.class);
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param ps
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public void printErr(PrintStream ps, String attErrJson) throws APIException {
+ StringBuilder sb = new StringBuilder();
+ Error err = errDF.newData().in(TYPE.JSON).load(attErrJson).asObject();
+ ps.println(toMsg(sb,err));
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param sb
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public StringBuilder toMsg(StringBuilder sb, String attErrJson) throws APIException {
+ return toMsg(sb,errDF.newData().in(TYPE.JSON).load(attErrJson).asObject());
+ }
+
+ public StringBuilder toMsg(Future<?> future) {
+ return toMsg(new StringBuilder(),future);
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Future<?> future) {
+ try {
+ toMsg(sb,errDF.newData().in(TYPE.JSON).load(future.body()).asObject());
+ } catch(Exception e) {
+ //just print what we can
+ sb.append(future.code());
+ sb.append(": ");
+ sb.append(future.body());
+ }
+ return sb;
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Error err) {
+ sb.append(err.getMessageId());
+ sb.append(' ');
+ String[] vars = new String[err.getVariables().size()];
+ err.getVariables().toArray(vars);
+ Vars.convert(sb, err.getText(),vars);
+ return sb;
+ }
+}
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
index 0000000..e8a4756
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/client/Examples.java
@@ -0,0 +1,445 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.client;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.GregorianCalendar;
+
+import aaf.v2_0.Approval;
+import aaf.v2_0.Approvals;
+import aaf.v2_0.CredRequest;
+import aaf.v2_0.Keys;
+import aaf.v2_0.NsRequest;
+import aaf.v2_0.Nss;
+import aaf.v2_0.Nss.Ns;
+import aaf.v2_0.Perm;
+import aaf.v2_0.PermKey;
+import aaf.v2_0.PermRequest;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Pkey;
+import aaf.v2_0.Request;
+import aaf.v2_0.Role;
+import aaf.v2_0.RoleKey;
+import aaf.v2_0.RolePermRequest;
+import aaf.v2_0.RoleRequest;
+import aaf.v2_0.Roles;
+import aaf.v2_0.UserRole;
+import aaf.v2_0.UserRoleRequest;
+import aaf.v2_0.UserRoles;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Chrono;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class Examples {
+ public static <C> String print(RosettaEnv env, String nameOrContentType, boolean optional) throws APIException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ // Discover ClassName
+ String className = null;
+ String version = null;
+ TYPE type = TYPE.JSON; // default
+ if(nameOrContentType.startsWith("application/")) {
+ for(String ct : nameOrContentType.split("\\s*,\\s*")) {
+ for(String elem : ct.split("\\s*;\\s*")) {
+ if(elem.endsWith("+json")) {
+ type = TYPE.JSON;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-5);
+ } else if(elem.endsWith("+xml")) {
+ type = TYPE.XML;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-4);
+ } else if(elem.startsWith("version=")) {
+ version = elem.substring(8);
+ }
+ }
+ if(className!=null && version!=null)break;
+ }
+ if(className==null) {
+ throw new APIException(nameOrContentType + " does not contain Class Information");
+ }
+ } else {
+ className = nameOrContentType;
+ }
+
+ // No Void.class in aaf.v2_0 package causing errors when trying to use a newVoidv2_0
+ // method similar to others in this class. This makes it work, but is it right?
+ if ("Void".equals(className)) return "";
+
+ if("1.1".equals(version)) {
+ version = "v1_0";
+ } else if(version!=null) {
+ version = "v" + version.replace('.', '_');
+ } else {
+ version = "v2_0";
+ }
+
+ Class<?> cls;
+ try {
+ cls = Examples.class.getClassLoader().loadClass("aaf."+version+'.'+className);
+ } catch (ClassNotFoundException e) {
+ throw new APIException(e);
+ }
+
+ Method meth;
+ try {
+ meth = Examples.class.getDeclaredMethod("new"+cls.getSimpleName()+version,boolean.class);
+ } catch (Exception e) {
+ throw new APIException("ERROR: " + cls.getName() + " does not have an Example in Code. Request from AAF Developers");
+ }
+
+ RosettaDF<C> df = env.newDataFactory(cls);
+ df.option(Data.PRETTY);
+
+ Object data = meth.invoke(null,optional);
+
+ @SuppressWarnings("unchecked")
+ String rv = df.newData().load((C)data).out(type).asString();
+// Object obj = df.newData().in(type).load(rv).asObject();
+ return rv;
+ }
+
+ /*
+ * Set Base Class Request (easier than coding over and over)
+ */
+ private static void setOptional(Request req) {
+ GregorianCalendar gc = new GregorianCalendar();
+ req.setStart(Chrono.timeStamp(gc));
+ gc.add(GregorianCalendar.MONTH, 6);
+ req.setEnd(Chrono.timeStamp(gc));
+// req.setForce("false");
+
+ }
+
+ @SuppressWarnings("unused")
+ private static Request newRequestv2_0(boolean optional) {
+ Request r = new Request();
+ setOptional(r);
+ return r;
+ }
+ @SuppressWarnings("unused")
+ private static RolePermRequest newRolePermRequestv2_0(boolean optional) {
+ RolePermRequest rpr = new RolePermRequest();
+ Pkey pkey = new Pkey();
+ pkey.setType("com.att.myns.mytype");
+ pkey.setInstance("myInstance");
+ pkey.setAction("myAction");
+ rpr.setPerm(pkey);
+ rpr.setRole("com.att.myns.myrole");
+ if(optional)setOptional(rpr);
+ return rpr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Roles newRolesv2_0(boolean optional) {
+ Role r;
+ Pkey p;
+ Roles rs = new Roles();
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myOtherRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOthertype");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ return rs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermRequest newPermRequestv2_0(boolean optional) {
+ PermRequest pr = new PermRequest();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+
+ setOptional(pr);
+ }
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perm newPermv2_0(boolean optional) {
+ Perm pr = new Perm();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ pr.getRoles().add("com.att.myns.myRole");
+ pr.getRoles().add("com.att.myns.myRole2");
+ pr.setDescription("This is my description, and I'm sticking with it");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+ }
+ return pr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermKey newPermKeyv2_0(boolean optional) {
+ PermKey pr = new PermKey();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perms newPermsv2_0(boolean optional) {
+ Perms perms = new Perms();
+ Perm p;
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+ return perms;
+
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoleRequest newUserRoleRequestv2_0(boolean optional) {
+ UserRoleRequest urr = new UserRoleRequest();
+ urr.setRole("com.att.myns.myRole");
+ urr.setUser("ab1234@csp.att.com");
+ if(optional) setOptional(urr);
+ return urr;
+ }
+
+ @SuppressWarnings("unused")
+ private static NsRequest newNsRequestv2_0(boolean optional) {
+ NsRequest nr = new NsRequest();
+ nr.setName("com.att.myns");
+ nr.getResponsible().add("ab1234@csp.att.com");
+ nr.getResponsible().add("cd5678@csp.att.com");
+ nr.getAdmin().add("zy9876@csp.att.com");
+ nr.getAdmin().add("xw5432@csp.att.com");
+ if(optional) {
+ nr.setDescription("This is my Namespace to set up");
+ nr.setType("APP");
+ setOptional(nr);
+ }
+ return nr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Nss newNssv2_0(boolean optional) {
+ Ns ns;
+
+ Nss nss = new Nss();
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myns");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+ ns.setDescription("This is my Namespace to set up");
+
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myOtherNs");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+
+ return nss;
+ }
+ @SuppressWarnings("unused")
+ private static RoleRequest newRoleRequestv2_0(boolean optional) {
+ RoleRequest rr = new RoleRequest();
+ rr.setName("com.att.myns.myRole");
+ if(optional) {
+ rr.setDescription("This is my Role");
+ setOptional(rr);
+ }
+ return rr;
+ }
+
+ @SuppressWarnings("unused")
+ private static CredRequest newCredRequestv2_0(boolean optional) {
+ CredRequest cr = new CredRequest();
+ cr.setId("myID@fully.qualified.domain");
+ if(optional) {
+ cr.setType(2);
+ cr.setEntry("0x125AB256344CE");
+ } else {
+ cr.setPassword("This is my provisioned password");
+ }
+
+ return cr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Users newUsersv2_0(boolean optional) {
+ User user;
+
+ Users users = new Users();
+ users.getUser().add(user = new Users.User());
+ user.setId("ab1234@csp.att.com");
+ GregorianCalendar gc = new GregorianCalendar();
+ user.setExpires(Chrono.timeStamp(gc));
+
+ users.getUser().add(user = new Users.User());
+ user.setId("zy9876@csp.att.com");
+ user.setExpires(Chrono.timeStamp(gc));
+
+ return users;
+ }
+
+ @SuppressWarnings("unused")
+ private static Role newRolev2_0(boolean optional) {
+ Role r = new Role();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static RoleKey newRoleKeyv2_0(boolean optional) {
+ RoleKey r = new RoleKey();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static Keys newKeysv2_0(boolean optional) {
+ Keys ks = new Keys();
+ ks.getKey().add("Reponse 1");
+ ks.getKey().add("Response 2");
+ return ks;
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoles newUserRolesv2_0(boolean optional) {
+ UserRoles urs = new UserRoles();
+ UserRole ur = new UserRole();
+ ur.setUser("xy1234");
+ ur.setRole("com.test.myapp.myRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+
+ ur = new UserRole();
+ ur.setUser("yx4321");
+ ur.setRole("com.test.yourapp.yourRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+ return urs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Approvals newApprovalsv2_0(boolean optional) {
+ Approvals as = new Approvals();
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ as.getApprovals().add(a);
+ a = new Approval();
+ a.setApprover("MyApprover2");
+ a.setId("MyID2");
+ a.setMemo("My memo (and then some)2");
+ a.setOperation("MyOperation2");
+ a.setStatus("MyStatus2");
+ a.setTicket("MyTicket2");
+ a.setType("MyType2");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser2");
+ as.getApprovals().add(a);
+ return as;
+ }
+
+ @SuppressWarnings("unused")
+ private static Approval newApprovalv2_0(boolean optional) {
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ return a;
+ }
+
+
+
+ @SuppressWarnings("unused")
+ private static aaf.v2_0.Error newErrorv2_0(boolean optional) {
+ aaf.v2_0.Error err = new aaf.v2_0.Error();
+ err.setMessageId("SVC1403");
+ err.setText("MyText %s, %s: The last three digits are usually the HTTP Code");
+ err.getVariables().add("Variable 1");
+ err.getVariables().add("Variable 2");
+ return err;
+ }
+
+}
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
index 0000000..4193d43
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.marshal;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.FieldDateTime;
+import com.att.rosetta.marshal.FieldHexBinary;
+import com.att.rosetta.marshal.FieldString;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertMarshal extends ObjMarshal<Cert> {
+ public CertMarshal() {
+ add(new FieldHexBinary<Cert>("fingerprint") {
+ @Override
+ protected byte[] data(Cert t) {
+ return t.getFingerprint();
+ }
+ });
+
+ add(new FieldString<Cert>("id") {
+ @Override
+ protected String data(Cert t) {
+ return t.getId();
+ }
+ });
+
+ add(new FieldString<Cert>("x500") {
+ @Override
+ protected String data(Cert t) {
+ return t.getX500();
+ }
+ });
+
+ add(new FieldDateTime<Cert>("expires") {
+ @Override
+ protected XMLGregorianCalendar data(Cert t) {
+ return t.getExpires();
+ }
+ });
+
+
+ }
+}
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
index 0000000..16fc580
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.marshal;
+
+import java.util.List;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.ObjArray;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertsMarshal extends ObjMarshal<Certs> {
+
+ public CertsMarshal() {
+ add(new ObjArray<Certs,Cert>("cert",new CertMarshal()) {
+ @Override
+ protected List<Cert> data(Certs t) {
+ return t.getCert();
+ }
+ });
+ }
+
+
+}
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
index 0000000..0c72dcd
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.config.Config;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
+ private AAFCon<CLIENT> con;
+ private String realm;
+
+ /**
+ * Configure with Standard AAF properties, Stand alone
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con) throws Exception {
+ super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);
+ this.con = con;
+
+ try {
+ setRealm();
+ } catch (APIException e) {
+ if(e.getCause() instanceof DME2Exception) {
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ /**
+ * Configure with Standard AAF properties, but share the Cache (with AAF Lur)
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {
+ super(cache);
+ this.con = con;
+ try {
+ setRealm();
+ } catch (Exception e) {
+ if(e.getCause() instanceof DME2Exception) {
+ access.log(e);
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ private void setRealm() throws Exception {
+ // Make a call without security set to get the 401 response, which
+ // includes the Realm of the server
+ // This also checks on Connectivity early on.
+ Future<String> fp = con.client(AAFCon.AAF_VERSION).read("/authn/basicAuth", "text/plain");
+ if(fp.get(con.timeout)) {
+ throw new Exception("Do not preset Basic Auth Information for AAFAuthn");
+ } else {
+ if(fp.code()==401) {
+ realm = fp.header("WWW-Authenticate");
+ if(realm!=null && realm.startsWith("Basic realm=\"")) {
+ realm = realm.substring(13, realm.length()-1);
+ } else {
+ realm = "unknown.com";
+ }
+ }
+ }
+ }
+
+ /**
+ * Return Native Realm of AAF Instance.
+ *
+ * @return
+ */
+ public String getRealm() {
+ return realm;
+ }
+
+ /**
+ * Returns null if ok, or an Error String;
+ *
+ * @param user
+ * @param password
+ * @return
+ * @throws Exception
+ */
+ public String validate(String user, String password) throws Exception {
+ User<AAFPermission> usr = getUser(user);
+ if(password.startsWith("enc:???")) {
+ password = access.decrypt(password, true);
+ }
+
+ byte[] bytes = password.getBytes();
+ if(usr != null && usr.principal != null && usr.principal.getName().equals(user)
+ && usr.principal instanceof GetCred) {
+
+ if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {
+ return null;
+ } else {
+ remove(usr);
+ usr = null;
+ }
+ }
+
+ AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);
+ // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch
+ // Statement
+ switch(cp.revalidate()) {
+ case REVALIDATED:
+ if(usr!=null) {
+ usr.principal = cp;
+ } else {
+ addUser(new User<AAFPermission>(cp,con.timeout));
+ }
+ return null;
+ case INACCESSIBLE:
+ return "AAF Inaccessible";
+ case UNVALIDATED:
+ return "User/Pass combo invalid";
+ default:
+ return "AAFAuthn doesn't handle this Principal";
+ }
+ }
+
+ private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {
+ private long expires,timeToLive;
+
+ public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {
+ super(name,pass);
+ this.timeToLive = timeToLive;
+ expires = timeToLive + System.currentTimeMillis();
+ }
+
+ public Resp revalidate() {
+ try {
+ Miss missed = missed(getName());
+ if(missed==null || missed.mayContinue(getCred())) {
+ Rcli<CLIENT> client = con.client(AAFCon.AAF_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));
+ Future<String> fp = client.read(
+ "/authn/basicAuth",
+ "text/plain"
+ );
+ if(fp.get(con.timeout)) {
+ expires = System.currentTimeMillis() + timeToLive;
+ addUser(new User<AAFPermission>(this, expires));
+ return Resp.REVALIDATED;
+ } else {
+ addMiss(getName(), getCred());
+ return Resp.UNVALIDATED;
+ }
+ } else {
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ con.access.log(e);
+ return Resp.INACCESSIBLE;
+ }
+ }
+
+ public long expires() {
+ return expires;
+ }
+ };
+
+}
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
index 0000000..c58dd9a
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.Principal;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.CadiWrap;
+import com.att.cadi.Connector;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Lur;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.marshal.CertsMarshal;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfo;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Users;
+
+public abstract class AAFCon<CLIENT> implements Connector {
+ public static final String AAF_VERSION = "2.0";
+
+ final public Access access;
+ // Package access
+ final public int timeout, cleanInterval, connTimeout;
+ final public int highCount, userExpires, usageRefreshTriggerCount;
+ private Rcli<CLIENT> client = null;
+ final public RosettaDF<Perms> permsDF;
+ final public RosettaDF<Certs> certsDF;
+ final public RosettaDF<Users> usersDF;
+ private String realm;
+ public final String app;
+ protected SecuritySetter<CLIENT> ss;
+ protected SecurityInfo<CLIENT> si;
+ protected final URI initURI;
+
+ public Rcli<CLIENT> client(String apiVersion) throws CadiException {
+ if(client==null) {
+ client = rclient(initURI,ss);
+ client.apiVersion(apiVersion)
+ .readTimeout(connTimeout);
+ }
+ return client;
+ }
+
+ protected AAFCon(Access access, String tag, SecurityInfo<CLIENT> si) throws CadiException{
+ try {
+ this.access = access;
+ this.si = si;
+ this.ss = si.defSS;
+ if(ss==null) {
+ String mechid = access.getProperty(Config.AAF_MECHID, null);
+ String encpass = access.getProperty(Config.AAF_MECHPASS, null);
+ if(encpass==null) {
+ String alias = access.getProperty(Config.CADI_ALIAS, mechid);
+ if(alias==null) {
+ throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");
+ }
+ si.defSS=ss = x509Alias(alias);
+ } else {
+ if(mechid!=null && encpass !=null) {
+ si.defSS=ss=basicAuth(mechid, encpass);
+ } else {
+ si.defSS=ss=new SecuritySetter<CLIENT>() {
+
+ @Override
+ public String getID() {
+ return "";
+ }
+
+ @Override
+ public void setSecurity(CLIENT client) throws CadiException {
+ throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
+ }
+ };
+ }
+ }
+ }
+
+ timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));
+ cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
+ highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
+ connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
+ userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
+ usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
+
+
+ initURI = new URI(access.getProperty(tag,null));
+ if(initURI==null) {
+ throw new CadiException(tag + " property is required.");
+ }
+
+ app=reverseDomain(ss.getID());
+ realm="openecomp.org";
+
+ RosettaEnv env = new RosettaEnv();
+ permsDF = env.newDataFactory(Perms.class);
+ usersDF = env.newDataFactory(Users.class);
+ certsDF = env.newDataFactory(Certs.class);
+ certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
+ } catch (APIException|URISyntaxException e) {
+ throw new CadiException("AAFCon cannot be configured",e);
+ }
+ }
+
+ /**
+ * Return the backing AAFCon, if there is a Lur Setup that is AAF.
+ *
+ * If there is no AAFLur setup, it will return "null"
+ * @param servletRequest
+ * @return
+ */
+ public static final AAFCon<?> obtain(Object servletRequest) {
+ if(servletRequest instanceof CadiWrap) {
+ Lur lur = ((CadiWrap)servletRequest).getLur();
+ if(lur != null) {
+ if(lur instanceof EpiLur) {
+ AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
+ if(aal!=null) {
+ return aal.aaf;
+ }
+ } else {
+ if(lur instanceof AbsAAFLur) {
+ return ((AbsAAFLur<?>)lur).aaf;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public AAFAuthn<CLIENT> newAuthn() throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFLurPerm newLur() throws CadiException {
+ try {
+ return new AAFLurPerm(this);
+ } catch (CadiException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFLurPerm(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ /**
+ * Take a Fully Qualified User, and get a Namespace from it.
+ * @param user
+ * @return
+ */
+ public static String reverseDomain(String user) {
+ StringBuilder sb = null;
+ String[] split = Split.split('.',user);
+ int at;
+ for(int i=split.length-1;i>=0;--i) {
+ if(sb == null) {
+ sb = new StringBuilder();
+ } else {
+ sb.append('.');
+ }
+
+ if((at = split[i].indexOf('@'))>0) {
+ sb.append(split[i].subSequence(at+1, split[i].length()));
+ } else {
+ sb.append(split[i]);
+ }
+ }
+
+ return sb==null?"":sb.toString();
+ }
+
+ protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
+
+ public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
+
+
+ public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
+
+
+ public String getRealm() {
+ return realm;
+
+ }
+
+ public SecuritySetter<CLIENT> set(SecuritySetter<CLIENT> ss) {
+ this.ss = ss;
+ if(client!=null) {
+ client.setSecuritySetter(ss);
+ }
+ return ss;
+ }
+
+ public SecurityInfo<CLIENT> securityInfo() {
+ return si;
+ }
+
+ public String defID() {
+ if(ss!=null) {
+ return ss.getID();
+ }
+ return "unknown";
+ }
+
+ public void invalidate() throws CadiException {
+ if(client!=null) {
+ client.invalidate();
+ }
+ client = null;
+ }
+
+
+}
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
index 0000000..07bc390
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfo;
+import com.att.cadi.dme2.DME2BasicAuth;
+import com.att.cadi.dme2.DME2TransferSS;
+import com.att.cadi.dme2.DME2x509SS;
+import com.att.cadi.dme2.DRcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConDME2 extends AAFCon<DME2Client>{
+ private DME2Manager manager;
+
+ public AAFConDME2(Access access) throws CadiException, GeneralSecurityException, IOException{
+ super(access,Config.AAF_URL,new SecurityInfo<DME2Client> (access));
+ manager = newManager(access);
+ }
+
+ public AAFConDME2(Access access, String url) throws CadiException, GeneralSecurityException, IOException{
+ super(access,url,new SecurityInfo<DME2Client> (access));
+ manager = newManager(access);
+ }
+
+ public AAFConDME2(Access access, SecurityInfo<DME2Client> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ manager = newManager(access);
+ }
+
+ public AAFConDME2(Access access, String url, SecurityInfo<DME2Client> si) throws CadiException {
+ super(access,url,si);
+ manager = newManager(access);
+ }
+
+ private DME2Manager newManager(Access access) throws CadiException {
+ Properties props = new Properties();
+ Config.cadiToDME2(access, props);
+ try {
+ return new DME2Manager("AAFCon",props);
+ } catch (DME2Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<DME2Client> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error Decrypting Password",e);
+ }
+ }
+
+ try {
+ return set(new DME2BasicAuth(user,password,si));
+ } catch (IOException e) {
+ throw new CadiException("Error setting up DME2BasicAuth",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<DME2Client> rclient(URI uri, SecuritySetter<DME2Client> ss) {
+ DRcli dc = new DRcli(uri, ss);
+ dc.setManager(manager);
+ return dc;
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> transferSS(Principal principal) throws CadiException {
+ try {
+ return principal==null?ss:new DME2TransferSS(principal, app);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2TransferSS",e);
+ }
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new DME2BasicAuth(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2BasicAuth",e);
+ }
+
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> x509Alias(String alias) throws CadiException {
+ try {
+ return new DME2x509SS(alias,si);
+ } catch (Exception e) {
+ throw new CadiException("Error creating DME2x509SS",e);
+ }
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ // NOTE: DME2 had Retry Logic embedded lower.
+ try {
+ return (retryable.code(rclient(initURI,ss)));
+ } catch (ConnectException e) {
+ // DME2 should catch
+ try {
+ manager.refresh();
+ } catch (Exception e1) {
+ throw new CadiException(e1);
+ }
+ throw new CadiException(e);
+ }
+ }
+}
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
index 0000000..ffe1331
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfo;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.http.HRcli;
+import com.att.cadi.http.HTransferSS;
+import com.att.cadi.http.HX509SS;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConHttp extends AAFCon<HttpURLConnection> {
+ private final HMangr hman;
+
+ public AAFConHttp(Access access) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfo<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(Config.AAF_URL,null)));
+ }
+
+ public AAFConHttp(Access access, String tag) throws CadiException, GeneralSecurityException, IOException {
+ super(access,tag,new SecurityInfo<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(tag,null)));
+ }
+
+ public AAFConHttp(Access access, String urlTag, SecurityInfo<HttpURLConnection> si) throws CadiException {
+ super(access,urlTag,si);
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(urlTag,null)));
+ }
+
+ public AAFConHttp(Access access, Locator locator) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfo<HttpURLConnection>(access));
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(Access access, Locator locator, SecurityInfo<HttpURLConnection> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(Access access, Locator locator, SecurityInfo<HttpURLConnection> si, String tag) throws CadiException {
+ super(access,tag,si);
+ hman = new HMangr(access, locator);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error decrypting password",e);
+ }
+ }
+ try {
+ return set(new HBasicAuthSS(user,password,si));
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public SecuritySetter<HttpURLConnection> x509Alias(String alias) throws APIException, CadiException {
+ try {
+ return set(new HX509SS(alias,si));
+ } catch (Exception e) {
+ throw new CadiException("Error creating X509SS",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<HttpURLConnection> rclient(URI ignoredURI, SecuritySetter<HttpURLConnection> ss) throws CadiException {
+ try {
+ return new HRcli(hman, hman.loc.best() ,ss);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public AbsTransferSS<HttpURLConnection> transferSS(Principal principal) throws CadiException {
+ return new HTransferSS(principal, app,si);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuthSS(java.security.Principal)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new HBasicAuthSS(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public HMangr hman() {
+ return hman;
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ return hman.best(ss, (Retryable<RET>)retryable);
+ }
+
+}
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
index 0000000..c1c25c2
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.ConnectException;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.Map;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Permission;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.inno.env.APIException;
+
+import aaf.v2_0.Perm;
+import aaf.v2_0.Perms;
+
+/**
+ * Use AAF Service as Permission Service.
+ *
+ * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.
+ *
+ * If you want a simple Role Lur, use AAFRoleLur
+ *
+ *
+ */
+public class AAFLurPerm extends AbsAAFLur<AAFPermission> {
+ /**
+ * Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this
+ * point by AAF. There is no "domain", aka, no "@att.com" in "ab1234@att.com".
+ *
+ * The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.
+ * Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely
+ * @throws APIException
+ * @throws URISyntaxException
+ * @throws DME2Exception
+ */
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con) throws CadiException, DME2Exception, URISyntaxException, APIException {
+ super(con);
+ }
+
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(con,auc);
+ }
+
+ protected User<AAFPermission> loadUser(Principal p) {
+ // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't
+ // have domains. We are going to make the Transitive Class (see this.transmutative) to convert
+ Principal principal = transmutate.mutate(p);
+ if(principal==null)return null; // if not a valid Transmutated credential, don't bother calling...
+ return loadUser(p, p.getName());
+ }
+
+ protected User<AAFPermission> loadUser(String name) {
+ return loadUser((Principal)null, name);
+ }
+
+ private User<AAFPermission> loadUser(final Principal prin, final String name) {
+
+ //TODO Create a dynamic way to declare domains supported.
+ final long start = System.nanoTime();
+ final boolean[] success = new boolean[]{false};
+
+// new Exception("loadUser").printStackTrace();
+ try {
+ return aaf.best(new Retryable<User<AAFPermission>>() {
+ @Override
+ public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);
+
+ // In the meantime, lookup User, create if necessary
+ User<AAFPermission> user = getUser(name);
+ Principal p;
+ if(prin == null) {
+ p = new Principal() {// Create a holder for lookups
+ private String n = name;
+ public String getName() {
+ return n;
+ }
+ };
+ } else {
+ p = prin;
+ }
+
+ if(user==null) {
+ addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
+ }
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success[0]=true;
+ Map<String, Permission> newMap = user.newMap();
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
+ }
+ user.setMap(newMap);
+ user.renewPerm();
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ }
+
+ return user;
+ }
+ });
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ return null;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.AUDIT, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ public Resp reload(User<AAFPermission> user) {
+ final String name = user.principal.getName();
+ long start = System.nanoTime();
+ boolean success = false;
+ try {
+ Future<Perms> fp = aaf.client(AAFCon.AAF_VERSION).read(
+ "/authz/perms/user/"+name,
+ aaf.permsDF
+ );
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success = true;
+ Map<String,Permission> newMap = user.newMap();
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
+ }
+ user.renewPerm();
+ return Resp.REVALIDATED;
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ return Resp.INACCESSIBLE;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ @Override
+ protected boolean isCorrectPermType(Permission pond) {
+ return pond instanceof AAFPermission;
+ }
+
+}
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
index 0000000..a36c11a
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CachedBasicPrincipal;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+import com.att.cadi.taf.basic.BasicHttpTafResp;
+
+public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {
+// private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";
+// private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";
+ private AAFCon<CLIENT> aaf;
+ private boolean warn;
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {
+ super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {
+ super(other);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ //TODO Do we allow just anybody to validate?
+
+ // Note: Either Carbon or Silicon based LifeForms ok
+ String auth = req.getHeader("Authorization");
+
+ System.out.println("value of auth ------1------- ++++++++++++++++++++++++++++++++++++++++++" +auth);
+
+ if(auth == null) {
+ return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
+ } else {
+ if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
+
+ try {
+ CachedBasicPrincipal bp = new CachedBasicPrincipal(this,auth,aaf.getRealm(),aaf.cleanInterval);
+ System.out.println(" value of aaf.getRealm --------2--------- +++++++++++++++++++++++++++++++++++++++++++++" +aaf.getRealm() );
+ //System.out.println(" value of bp +++++++++++++++++++++++++++++++++++++++++++" +bp.toString());
+ System.out.println(" value of bp.getName() -------3----- +++++++++++++++++++++++++++++++++++++++++++" +bp.getName().toString());
+ System.out.println(" value of bp.getCred() -------4----- +++++++++++++++++++++++++++++++++++++++++++" +bp.getCred().toString());
+
+ // First try Cache
+ User<AAFPermission> usr = getUser(bp);
+
+ // System.out.println(" value of usr -------5-------++++++++++++++++++++++++++++++++++++++++++" +usr.toString());
+
+ if(usr != null && usr.principal != null) {
+ if(usr.principal instanceof GetCred) {
+ if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {
+
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ }
+ }
+ }
+
+ Miss miss = missed(bp.getName());
+ System.out.println(" value of miss before if loop ---------6----- +++++++++++++++++++++++++++++++++++++" +miss );
+ if(miss!=null && !miss.mayContinue(bp.getCred())) {
+
+ System.out.println(" In if(miss!=null && !miss.mayContinue(bp.getCred())) -------7--------+++++++++++++++++++++++++++++++++++++++++++++");
+
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_VERSION).forUser(aaf.basicAuthSS(bp));
+
+ //System.out.println("value of userAAF ------8---- +++++++++++++++++++++++" +userAAF);
+ //System.out.println("value of userAAF +++++++++++++++++++++++" +userAAF.);
+ Future<String> fp = userAAF.read("/authn/basicAuth", "text/plain");
+
+ //System.out.println("value of fp --------9------ +++++++++++++++++++++++" +fp.toString());
+
+ if(fp.get(aaf.timeout)) {
+ System.out.println("In fp.get check -----10----- +++++++++++++");
+ if(usr!=null)usr.principal = bp;
+
+ else addUser(new User<AAFPermission>(bp,aaf.cleanInterval));
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ } else {
+ // Note: AddMiss checks for miss==null, and is part of logic
+
+ System.out.println(" In the else part --------11--------++++++++++++++ ");
+
+ boolean rv= addMiss(bp.getName(),bp.getCred());
+ System.out.println(" value of bp.getName() and bp.getCred() before if check ----12--- ++++++++++++!!!!!!!!!!!++++++++++" +bp.getName() +"and " +bp.getCred());
+
+ if(rv) {
+ System.out.println("In if(rv) check -----13----- +++++++++++++");
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF"),
+ RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
+ } else {
+ System.out.println("In if(rv) else check -----14----- +++++++++++++");
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF - Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+ }
+ } catch (IOException e) {
+ String msg = buildMsg(null,req,"Invalid Auth Token");
+ System.out.println("In IOException catch block -----15----- +++++++++++++");
+ e.getStackTrace();
+ e.printStackTrace();
+ aaf.access.log(Level.INFO,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);
+ } catch (Exception e) {
+ String msg = buildMsg(null,req,"Authenticating Service unavailable");
+ System.out.println("In Exception catch block -----16----- +++++++++++++");
+ e.getStackTrace();
+ e.printStackTrace();
+ aaf.access.log(Level.INFO,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);
+ }
+ }
+ }
+
+ private String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
+ StringBuilder sb = new StringBuilder();
+ for(Object s : msg) {
+ sb.append(s.toString());
+ }
+ if(pr!=null) {
+ sb.append(" for ");
+ sb.append(pr.getName());
+ }
+ sb.append(" from ");
+ sb.append(req.getRemoteAddr());
+ sb.append(':');
+ sb.append(req.getRemotePort());
+ return sb.toString();
+ }
+
+
+
+ public Resp revalidate(CachedPrincipal prin) {
+ // !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal
+ if(prin instanceof BasicPrincipal) {
+ Future<String> fp;
+ try {
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_VERSION).forUser(aaf.transferSS(prin));
+ fp = userAAF.read("/authn/basicAuth", "text/plain");
+ return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;
+ } catch (Exception e) {
+ aaf.access.log(e, "Cannot Revalidate",prin.getName());
+ return Resp.INACCESSIBLE;
+ }
+ }
+ return Resp.NOT_MINE;
+ }
+
+}
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
index 0000000..cc1e16c
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import com.att.cadi.Lur;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.principal.TrustPrincipal;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TrustNotTafResp;
+import com.att.cadi.taf.TrustTafResp;
+import com.att.inno.env.util.Split;
+
+public class AAFTrustChecker implements TrustChecker {
+ private final String tag,type,instance,action;
+ private Lur lur;
+
+ /**
+ *
+ * Instance will be replaced by Identity
+ * @param lur
+ *
+ * @param tag
+ * @param perm
+ */
+ public AAFTrustChecker(final String tag, final String perm) {
+ this.tag = tag;
+ String[] split = Split.split('|', perm);
+ this.type = split[0];
+ this.instance = split[1];
+ this.action = split[2];
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.TrustChecker#setLur(com.att.cadi.Lur)
+ */
+ @Override
+ public void setLur(Lur lur) {
+ this.lur = lur;
+ }
+
+ @Override
+ public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {
+ String user_info = req.getHeader(tag);
+ if(user_info !=null ) {
+ String[] info = Split.split(',', user_info);
+ if(info.length>0) {
+ String[] flds = Split.split(':',info[0]);
+ if(flds.length>3 && "AS".equals(flds[3])) { // is it set for "AS"
+ if(!tresp.getPrincipal().getName().equals(flds[0])) { // We do trust ourselves, if a trust entry is made with self
+ if(lur.fish(tresp.getPrincipal(), new AAFPermission(type,instance,action))) {
+ return new TrustTafResp(tresp,
+ new TrustPrincipal(tresp.getPrincipal(), flds[0]),
+ " " + flds[0] + " validated using " + flds[2] + " by " + flds[1] + ','
+ );
+ } else {
+ return new TrustNotTafResp(tresp, " " + tresp.getPrincipal().getName() +
+ " requested identity change to " + flds[0] + ", but does not have Authorization");
+ }
+ }
+ }
+ }
+ }
+
+ return tresp;
+ }
+
+}
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
index 0000000..0e831b9
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.v2_0;
+
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachingLur;
+import com.att.cadi.Permission;
+import com.att.cadi.StrLur;
+import com.att.cadi.Transmutate;
+import com.att.cadi.User;
+import com.att.cadi.config.Config;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.AAFTransmutate;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+
+public abstract class AbsAAFLur<PERM extends Permission> extends AbsUserCache<PERM> implements StrLur, CachingLur<PERM> {
+ protected static final byte[] BLANK_PASSWORD = new byte[0];
+ protected static final Transmutate<Principal> transmutate = new AAFTransmutate();
+ private String[] debug = null;
+ public AAFCon<?> aaf;
+ private String[] supports;
+
+ public AbsAAFLur(AAFCon<?> con) throws DME2Exception, URISyntaxException, APIException {
+ super(con.access, con.cleanInterval, con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ public AbsAAFLur(AAFCon<?> con, AbsUserCache<PERM> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(auc);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ @Override
+ public void setDebug(String ids) {
+ this.debug = ids==null?null:Split.split(',', ids);
+ }
+
+ protected abstract User<PERM> loadUser(Principal bait);
+ protected abstract User<PERM> loadUser(String name);
+ public final boolean supports(String userName) {
+ if(userName!=null) {
+ for(String s : supports) {
+ if(userName.endsWith(s))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected abstract boolean isCorrectPermType(Permission pond);
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(Principal bait, Permission pond) {
+ return fish(bait.getName(), pond);
+ }
+
+ public void fishAll(Principal bait, List<Permission> perms) {
+ fishAll(bait.getName(),perms);
+ }
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(String bait, Permission pond) {
+ if(isDebug(bait)) {
+ boolean rv = false;
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else if(user.contains(pond)) {
+ sb.append("\n\tUser contains ");
+ sb.append(pond.getKey());
+ rv = true;
+ } else {
+ sb.append("\n\tUser does not contain ");
+ sb.append(pond.getKey());
+ List<Permission> perms = new ArrayList<Permission>();
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ return rv;
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ }
+ return user==null?false:user.contains(pond);
+ }
+ return false;
+ }
+ }
+
+ public void fishAll(String bait, List<Permission> perms) {
+ if(isDebug(bait)) {
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else {
+ sb.append("\n\tCopying Perms ");
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) user = loadUser(bait);
+ if(user!=null) {
+ user.copyPermsTo(perms);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void remove(String user) {
+ super.remove(user);
+ }
+
+ private boolean isDebug(String bait) {
+ if(debug!=null) {
+ if(debug.length==1 && "all".equals(debug[0]))return true;
+ for(String s : debug) {
+ if(s.equals(bait))return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * This special case minimizes loops, avoids multiple Set hits, and calls all the appropriate Actions found.
+ *
+ * @param bait
+ * @param obj
+ * @param type
+ * @param instance
+ * @param actions
+ */
+ public<A> void fishOneOf(String bait, A obj, String type, String instance, List<Action<A>> actions) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired()))user = loadUser(bait);
+// return user==null?false:user.contains(pond);
+ if(user!=null) {
+ ReuseAAFPermission perm = new ReuseAAFPermission(type,instance);
+ for(Action<A> action : actions) {
+ perm.setAction(action.getName());
+ if(user.contains(perm)) {
+ if(action.exec(obj))return;
+ }
+ }
+ }
+ }
+
+ public static interface Action<A> {
+ public String getName();
+ /**
+ * Return false to continue, True to end now
+ * @return
+ */
+ public boolean exec(A a);
+ }
+
+ private class ReuseAAFPermission extends AAFPermission {
+ public ReuseAAFPermission(String type, String instance) {
+ super(type,instance,null);
+ }
+
+ public void setAction(String s) {
+ action = s;
+ }
+
+ /**
+ * This function understands that AAF Keys are hierarchical, :A:B:C,
+ * Cassandra follows a similar method, so we'll short circuit and do it more efficiently when there isn't a first hit
+ * @return
+ */
+// public boolean setParentInstance() {
+// int i = instance.lastIndexOf(':');
+// if(i<0) return false;
+// instance = instance.substring(0, i);
+// return true;
+// }
+ }
+}
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
index 0000000..7ddf529
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/ArtifactDir.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public abstract class ArtifactDir implements PlaceArtifact {
+
+ protected static final String C_R = "\n";
+ protected File dir;
+ private List<String> encodeds = new ArrayList<String>();
+
+ private Symm symm;
+ // This checks for multiple passes of Dir on the same objects. Run clear after done.
+ protected static Map<String,Object> processed = new HashMap<String,Object>();
+
+
+ /**
+ * Note: Derived Classes should ALWAYS call "super.place(cert,arti)" first, and
+ * then "placeProperties(arti)" just after they implement
+ */
+ @Override
+ public final boolean place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ validate(arti);
+
+ try {
+ // Obtain/setup directory as required
+ dir = new File(arti.getDir());
+ if(processed.get("dir")==null) {
+ if(!dir.exists()) {
+ Chmod.to755.chmod(dir);
+ if(!dir.mkdirs()) {
+ throw new CadiException("Could not create " + dir);
+ }
+ }
+
+ // Also place cm_url and Host Name
+ addProperty(Config.CM_URL,trans.getProperty(Config.CM_URL));
+ addProperty(Config.HOSTNAME,arti.getMachine());
+ }
+ symm = (Symm)processed.get("symm");
+ if(symm==null) {
+ // CADI Key Gen
+ File f = new File(dir,arti.getAppName() + ".keyfile");
+ if(!f.exists()) {
+ write(f,Chmod.to400,Symm.baseCrypt().keygen());
+ }
+ symm = Symm.obtain(f);
+
+ addEncProperty("ChallengePassword", certInfo.getChallenge());
+
+ processed.put("symm",symm);
+ }
+
+ _place(trans, certInfo,arti);
+
+ placeProperties(arti);
+
+ processed.put("dir",dir);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ /**
+ * Derived Classes implement this instead, so Dir can process first, and write any Properties last
+ * @param cert
+ * @param arti
+ * @return
+ * @throws CadiException
+ */
+ protected abstract boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException;
+
+ protected void addProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append(value);
+ encodeds.add(sb.toString());
+ }
+
+ protected void addEncProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append("enc:???");
+ sb.append(symm.enpass(value));
+ encodeds.add(sb.toString());
+ }
+
+ protected void write(File f, Chmod c, String ... data) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ PrintStream ps = new PrintStream(fos);
+ try {
+ for(String s : data) {
+ ps.print(s);
+ }
+ } finally {
+ ps.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, byte[] bytes) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ fos.write(bytes);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, KeyStore ks, char[] pass ) throws IOException, CadiException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ ks.store(fos, pass);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+
+ private void validate(Artifact a) throws CadiException {
+ StringBuilder sb = new StringBuilder();
+ if(a.getDir()==null) {
+ sb.append("File Artifacts require a path");
+ }
+
+ if(a.getAppName()==null) {
+ if(sb.length()>0) {
+ sb.append('\n');
+ }
+ sb.append("File Artifacts require an appName");
+ }
+
+ if(sb.length()>0) {
+ throw new CadiException(sb.toString());
+ }
+ }
+
+ private boolean placeProperties(Artifact arti) throws CadiException {
+ if(encodeds.size()==0) {
+ return true;
+ }
+ boolean first=processed.get("dir")==null;
+ try {
+ File f = new File(dir,arti.getAppName()+".props");
+ if(f.exists()) {
+ if(first) {
+ f.delete();
+ } else {
+ f.setWritable(true);
+ }
+ }
+ // Append if not first
+ PrintWriter pw = new PrintWriter(new FileWriter(f,!first));
+
+ // Write a Header
+ if(first) {
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ pw.println("# Properties Generated by AT&T Certificate Manager");
+ pw.print("# by ");
+ pw.println(System.getProperty("user.name"));
+ pw.print("# on ");
+ pw.println(Chrono.dateStamp());
+ pw.println("# @copyright 2016, AT&T");
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ for(String prop : encodeds) {
+ if(prop.startsWith("cm_") || prop.startsWith(Config.HOSTNAME)) {
+ pw.println(prop);
+ }
+ }
+ }
+
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("cadi")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to400.chmod(f);
+
+ if(first) {
+ // Challenge
+ f = new File(dir,arti.getAppName()+".chal");
+ if(f.exists()) {
+ f.delete();
+ }
+ pw = new PrintWriter(new FileWriter(f));
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("Challenge")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to400.chmod(f);
+ }
+ } catch(Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ public static void clear() {
+ processed.clear();
+ }
+
+}
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
index 0000000..a2694ce
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/CertException.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+public class CertException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1373028409048516401L;
+
+ public CertException() {
+ }
+
+ public CertException(String message) {
+ super(message);
+ }
+
+ public CertException(Throwable cause) {
+ super(cause);
+ }
+
+ public CertException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
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
index 0000000..9e5e77a
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/CmAgent.java
@@ -0,0 +1,787 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.cadi.aaf.client.ErrMessage;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.client.EnvAccess;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import certman.v1_0.Artifacts;
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+import certman.v1_0.CertificateRequest;
+
+public class CmAgent {
+ private static final String PRINT = "print";
+ private static final String FILE = "file";
+ private static final String PKCS12 = "pkcs12";
+ private static final String JKS = "jks";
+ private static final String SCRIPT="script";
+
+ private static final String CM_VER = "1.0";
+ public static final int PASS_SIZE = 24;
+ private static int TIMEOUT;
+
+ private static MyConsole cons;
+
+ private static RosettaDF<CertificateRequest> reqDF;
+ private static RosettaDF<CertInfo> certDF;
+ private static RosettaDF<Artifacts> artifactsDF;
+ private static ErrMessage errMsg;
+ private static Map<String,PlaceArtifact> placeArtifact;
+ private static RosettaEnv env;
+
+ public static void main(String[] args) {
+ int exitCode = 0;
+ env = new RosettaEnv(Config.CADI_PROP_FILES,args);
+ Deque<String> cmds = new ArrayDeque<String>();
+ for(String p : args) {
+ if(p.indexOf('=')<0) {
+ cmds.add(p);
+ }
+ }
+
+ if(cmds.size()==0) {
+ System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");
+ System.out.println(" create <mechID> [<machine>]");
+ System.out.println(" read <mechID> [<machine>]");
+ System.out.println(" update <mechID> [<machine>]");
+ System.out.println(" delete <mechID> [<machine>]");
+ System.out.println(" copy <mechID> <machine> <newmachine>[,<newmachine>]*");
+ System.out.println(" place <mechID> [<machine>]");
+ System.out.println(" showpass <mechID> [<machine>]");
+ System.out.println(" check <mechID> [<machine>]");
+ System.exit(1);
+ }
+
+ TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));
+ cons = TheConsole.implemented()?new TheConsole():new SubStandardConsole();
+
+ try {
+ reqDF = env.newDataFactory(CertificateRequest.class);
+ artifactsDF = env.newDataFactory(Artifacts.class);
+ certDF = env.newDataFactory(CertInfo.class);
+ errMsg = new ErrMessage(env);
+
+ placeArtifact = new HashMap<String,PlaceArtifact>();
+ placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));
+ placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));
+ placeArtifact.put(FILE, new PlaceArtifactInFiles());
+ placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));
+ placeArtifact.put(SCRIPT, new PlaceArtifactScripts());
+
+ Access access = new EnvAccess(env);
+ Trans trans = env.newTrans();
+ try {
+ getProperty(env,false, Config.CM_URL,Config.CM_URL+": ");
+ String str=env.getProperty(Config.CADI_ALIAS);
+ if(str==null) { // ask for MechID pass
+ getProperty(env,false,Config.AAF_MECHID,"Your Identity: ");
+ getProperty(env,true,Config.AAF_MECHPASS,"Password: ");
+ }
+ AAFCon<?> aafcon = new AAFConHttp(access,Config.CM_URL);
+
+ String cmd = cmds.removeFirst();
+ if("place".equals(cmd)) {
+ placeCerts(trans,aafcon,cmds);
+ } else if("create".equals(cmd)) {
+ createArtifact(trans, aafcon,cmds);
+ } else if("read".equals(cmd)) {
+ readArtifact(trans, aafcon, cmds);
+ } else if("copy".equals(cmd)) {
+ copyArtifact(trans, aafcon, cmds);
+ } else if("update".equals(cmd)) {
+ updateArtifact(trans, aafcon, cmds);
+ } else if("delete".equals(cmd)) {
+ deleteArtifact(trans, aafcon, cmds);
+ } else if("showpass".equals(cmd)) {
+ showPass(trans,aafcon,cmds);
+ } else if("check".equals(cmd)) {
+ try {
+ exitCode = check(trans,aafcon,cmds);
+ } catch (Exception e) {
+ exitCode = 1;
+ throw e;
+ }
+ } else {
+ cons.printf("Unknown command \"%s\"\n", cmd);
+ }
+ } finally {
+ StringBuilder sb = new StringBuilder();
+ trans.auditTrail(4, sb, Trans.REMOTE);
+ if(sb.length()>0) {
+ trans.info().log("Trans Info\n",sb);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if(exitCode!=0) {
+ System.exit(exitCode);
+ }
+ }
+
+ private static String getProperty(Env env, boolean secure, String tag, String prompt, Object ... def) {
+ String value;
+ if((value=env.getProperty(tag))==null) {
+ if(secure) {
+ value = new String(cons.readPassword(prompt, def));
+ } else {
+ value = cons.readLine(prompt,def).trim();
+ }
+ if(value!=null) {
+ if(value.length()>0) {
+ env.setProperty(tag,value);
+ } else if(def.length==1) {
+ value=def[0].toString();
+ env.setProperty(tag,value);
+ }
+ }
+ }
+ return value;
+ }
+
+ private interface MyConsole {
+ public String readLine(String fmt, Object ... args);
+ public char[] readPassword(String fmt, Object ... args);
+ public void printf(String fmt, Object ...args);
+ }
+
+ private static class TheConsole implements MyConsole {
+ @Override
+ public String readLine(String fmt, Object... args) {
+ String rv = System.console().readLine(fmt, args);
+ if(args.length>0 && args[0]!=null && rv.length()==0) {
+ rv = args[0].toString();
+ }
+ return rv;
+ }
+
+ @Override
+ public char[] readPassword(String fmt, Object... args) {
+ return System.console().readPassword(fmt, args);
+ }
+
+ public static boolean implemented() {
+ return System.console()!=null;
+ }
+
+ @Override
+ public void printf(String fmt, Object... args) {
+ System.console().printf(fmt, args);
+ }
+ }
+
+ // Substandard, because System.in doesn't do Passwords..
+ private static class SubStandardConsole implements MyConsole {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ @Override
+ public String readLine(String fmt, Object... args) {
+ String rv;
+ try {
+ System.out.printf(fmt,args);
+ rv = br.readLine();
+ if(args.length==1 && rv.length()==0) {
+ rv = args[0].toString();
+ }
+ } catch (IOException e) {
+ System.err.println("uh oh...");
+ rv = "";
+ }
+ return rv;
+ }
+
+ @Override
+ public char[] readPassword(String fmt, Object... args) {
+ try {
+ System.out.printf(fmt,args);
+ return br.readLine().toCharArray();
+ } catch (IOException e) {
+ System.err.println("uh oh...");
+ return new char[0];
+ }
+ }
+
+ @Override
+ public void printf(String fmt, Object... args) {
+ System.out.printf(fmt, args);
+ }
+ }
+
+// private static class AutoData implements MyConsole {
+//// private Env env;
+// private Map<String,String> data;
+//
+// @Override
+// public String readLine(String fmt, Object... args) {
+// String rv=data.get(fmt);
+// return rv==null?"":rv;
+// }
+//
+// @Override
+// public char[] readPassword(String fmt, Object... args) {
+// String rv=data.get(fmt);
+// return rv==null?new char[0]:rv.toCharArray();
+// }
+//
+// @Override
+// public void printf(String fmt, Object... args) {
+// System.out.printf(fmt, args);
+// }
+//
+// }
+//
+ private static String mechID(Deque<String> cmds) {
+ if(cmds.size()<1) {
+ String alias = env.getProperty(Config.CADI_ALIAS);
+ return alias!=null?alias:cons.readLine("MechID: ");
+ }
+ return cmds.removeFirst();
+ }
+
+ private static String machine(Deque<String> cmds) throws UnknownHostException {
+ if(cmds.size()>0) {
+ return cmds.removeFirst();
+ } else {
+ String mach = env.getProperty(Config.HOSTNAME);
+ return mach!=null?mach:InetAddress.getLocalHost().getHostName();
+ }
+ }
+
+ private static String[] machines(Deque<String> cmds) {
+ String machines;
+ if(cmds.size()>0) {
+ machines = cmds.removeFirst();
+ } else {
+ machines = cons.readLine("Machines (sep by ','): ");
+ }
+ return Split.split(',', machines);
+ }
+
+ private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ Artifacts artifacts = new Artifacts();
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+ arti.setMechid(mechID!=null?mechID:cons.readLine("MechID: "));
+ arti.setMachine(machine!=null?machine:cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));
+ arti.setCa(cons.readLine("CA: (%s): ","aaf"));
+
+ String resp = cons.readLine("Types [file,jks,pkcs12] (%s): ", "jks");
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ String configRootName = AAFCon.reverseDomain(arti.getMechid());
+ arti.setAppName(cons.readLine("AppName (%s): ",configRootName));
+ arti.setDir(cons.readLine("Directory (%s): ", System.getProperty("user.dir")));
+ arti.setOsUser(cons.readLine("OS User (%s): ", System.getProperty("user.name")));
+ arti.setRenewDays(Integer.parseInt(cons.readLine("Renewal Days (%s):", "30")));
+ arti.setNotification(toNotification(cons.readLine("Notification (mailto owner):", "")));
+
+ TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static String toNotification(String notification) {
+ if(notification==null) {
+ notification="";
+ } else if(notification.length()>0) {
+ if(notification.indexOf(':')<0) {
+ notification = "mailto:" + notification;
+ }
+ }
+ return notification;
+ }
+
+
+ private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Read Artifact", Env.SUB);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ cons.printf("MechID: %s\n",a.getMechid());
+ cons.printf(" Sponsor: %s\n",a.getSponsor());
+ cons.printf("Machine: %s\n",a.getMachine());
+ cons.printf("CA: %s\n",a.getCa());
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+ cons.printf("Types: %s\n",sb);
+ cons.printf("AppName: %s\n",a.getAppName());
+ cons.printf("Directory: %s\n",a.getDir());
+ cons.printf("O/S User: %s\n",a.getOsUser());
+ cons.printf("Renew Days: %d\n",a.getRenewDays());
+ cons.printf("Notification %s\n",a.getNotification());
+ printed = true;
+ }
+ if(!printed) {
+ cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+ String[] newmachs = machines(cmds);
+ if(newmachs==null || newmachs == null) {
+ trans.error().log("No machines listed to copy to");
+ } else {
+ TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ for(String m : newmachs) {
+ a.setMachine(m);
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+
+ printed = true;
+ }
+ }
+ if(!printed) {
+ cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+ }
+
+ private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> fread = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(fread.get(TIMEOUT)) {
+ Artifacts artifacts = new Artifacts();
+ for(Artifact a : fread.value.getArtifact()) {
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+
+ cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());
+ arti.setMechid(a.getMechid());
+ arti.setMachine(a.getMachine());
+ arti.setCa(cons.readLine("CA: (%s): ",a.getCa()));
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+
+ String resp = cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ arti.setAppName(cons.readLine("AppName (%s): ",a.getAppName()));
+ arti.setDir(cons.readLine("Directory (%s): ", a.getDir()));
+ arti.setOsUser(cons.readLine("OS User (%s): ", a.getOsUser()));
+ arti.setRenewDays(Integer.parseInt(cons.readLine("Renew Days (%s):", a.getRenewDays())));
+ arti.setNotification(toNotification(cons.readLine("Notification (%s):", a.getNotification())));
+
+ }
+ if(artifacts.getArtifact().size()==0) {
+ cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ } else {
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+ }
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(fread),mechID,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechid = mechID(cmds);
+ String machine = mechID(cmds);
+
+ TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);
+ try {
+ Future<Void> future = aafcon.client(CM_VER)
+ .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );
+
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(future),mechid,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+
+
+ private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ boolean rv = false;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ cons.printf("There are no artifacts for %s %s", mechID, machine);
+ } else {
+ for(Artifact a : acf.value.getArtifact()) {
+ CertificateRequest cr = new CertificateRequest();
+ cr.setMechid(a.getMechid());
+ cr.setSponsor(a.getSponsor());
+ cr.getFqdns().add(a.getMachine());
+ Future<String> f = aafcon.client(CM_VER)
+ .setQueryParams("withTrust")
+ .updateRespondString("/cert/" + a.getCa(),reqDF, cr);
+ if(f.get(TIMEOUT)) {
+ CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();
+ for(String type : a.getType()) {
+ PlaceArtifact pa = placeArtifact.get(type);
+ if(pa!=null) {
+ if(rv = pa.place(trans, capi, a)) {
+ notifyPlaced(a,rv);
+ }
+ }
+ }
+ // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact
+ ArtifactDir.clear();
+ } else {
+ trans.error().log(errMsg.toMsg(f));
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+ return rv;
+ }
+
+ private static void notifyPlaced(Artifact a, boolean rv) {
+
+
+ }
+
+ private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Show Password", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ boolean allowed;
+ for(Artifact a : acf.value.getArtifact()) {
+ allowed = id!=null && (id.equals(a.getSponsor()) ||
+ (id.equals(a.getMechid())
+ && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));
+ if(!allowed) {
+ Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" +
+ a.getAppName() + ".certman|"+a.getCa()+"|showpass","*/*");
+ if(pf.get(TIMEOUT)) {
+ allowed = true;
+ } else {
+ trans.error().log(errMsg.toMsg(pf));
+ }
+ }
+ if(allowed) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ fis.close();
+ fis = new FileInputStream(new File(dir,a.getAppName()+".chal"));
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ File f = new File(dir,a.getAppName()+".keyfile");
+ if(f.exists()) {
+ Symm symm = Symm.obtain(f);
+
+ for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {
+ Entry<Object,Object> en = iter.next();
+ if(en.getValue().toString().startsWith("enc:???")) {
+ System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));
+ }
+ }
+ } else {
+ trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",
+ f.getCanonicalPath(),a.getMechid(), a.getMachine());
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+
+ }
+
+
+ /**
+ * Check returns Error Codes, so that Scripts can know what to do
+ *
+ * 0 - Check Complete, nothing to do
+ * 1 - General Error
+ * 2 - Error for specific Artifact - read check.msg
+ * 10 - Certificate Updated - check.msg is email content
+ *
+ * @param trans
+ * @param aafcon
+ * @param cmds
+ * @return
+ * @throws Exception
+ */
+ private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ int exitCode=1;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);
+ try {
+
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ GregorianCalendar now = new GregorianCalendar();
+ for(Artifact a : acf.value.getArtifact()) {
+ if(id.equals(a.getMechid())) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ String prop;
+ File f;
+
+ if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||
+ !(f=new File(prop)).exists()) {
+ trans.error().printf("Keyfile must exist to check Certificates for %s on %s",
+ a.getMechid(), a.getMachine());
+ } else {
+ String ksf = props.getProperty(Config.CADI_KEYSTORE);
+ String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);
+ if(ksf==null || ksps == null) {
+ trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",
+ Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());
+ } else {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ Symm symm = Symm.obtain(f);
+
+ fis = new FileInputStream(ksf);
+ try {
+ ks.load(fis,symm.depass(ksps).toCharArray());
+ } finally {
+ fis.close();
+ }
+ X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);
+ String msg = null;
+
+ if(cert==null) {
+ msg = String.format("X509Certificate does not exist for %s on %s in %s",
+ a.getMechid(), a.getMachine(), ksf);
+ trans.error().log(msg);
+ exitCode = 2;
+ } else {
+ GregorianCalendar renew = new GregorianCalendar();
+ renew.setTime(cert.getNotAfter());
+ renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());
+ if(renew.after(now)) {
+ msg = String.format("As of %s, X509Certificate for %s on %s, expiration %s is still within %d renewal days.\n",
+ Chrono.dateOnlyStamp(), a.getMechid(), a.getMachine(), cert.getNotAfter(),a.getRenewDays());
+ trans.info().log(msg);
+ exitCode = 0; // OK
+ } else {
+ trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n",
+ a.getMechid(), a.getMachine(),cert.getNotAfter());
+ cmds.offerLast(mechID);
+ cmds.offerLast(machine);
+ if(placeCerts(trans,aafcon,cmds)) {
+ msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 10; // Refreshed
+ } else {
+ msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 1; // Error Renewing
+ }
+ }
+ }
+ if(msg!=null) {
+ FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getAppName()+".msg");
+ try {
+ fos.write(msg.getBytes());
+ } finally {
+ fos.close();
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ exitCode=1;
+ }
+ } finally {
+ tt.done();
+ }
+ return exitCode;
+ }
+
+}
+
+
+
+
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
index 0000000..6fc9b27
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/Factory.java
@@ -0,0 +1,447 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Collection;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import com.att.cadi.Symm;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+
+public class Factory {
+ public static final String KEY_ALGO = "RSA";
+ private static final String PRIVATE_KEY_HEADER = KEY_ALGO + " PRIVATE KEY";
+ public static final String SIG_ALGO = "SHA256withRSA";
+
+ public static final int KEY_LENGTH = 2048;
+ private static final KeyPairGenerator keygen;
+ private static final KeyFactory keyFactory;
+ private static final CertificateFactory certificateFactory;
+ private static final SecureRandom random;
+
+
+ private static final Symm base64 = Symm.base64.copy(64);
+
+ static {
+ random = new SecureRandom();
+ KeyPairGenerator tempKeygen;
+ try {
+ tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");
+ tempKeygen.initialize(KEY_LENGTH, random);
+ } catch (NoSuchAlgorithmException e) {
+ tempKeygen = null;
+ e.printStackTrace(System.err);
+ }
+ keygen = tempKeygen;
+
+ KeyFactory tempKeyFactory;
+ try {
+ tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"
+ } catch (NoSuchAlgorithmException e) {
+ tempKeyFactory = null;
+ e.printStackTrace(System.err);
+ };
+ keyFactory = tempKeyFactory;
+
+ CertificateFactory tempCertificateFactory;
+ try {
+ tempCertificateFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ tempCertificateFactory = null;
+ e.printStackTrace(System.err);
+ }
+ certificateFactory = tempCertificateFactory;
+
+
+ }
+
+
+ public static KeyPair generateKeyPair(Trans trans) {
+ TimeTaken tt;
+ if(trans!=null) {
+ tt = trans.start("Generate KeyPair", Env.SUB);
+ } else {
+ tt = null;
+ }
+ try {
+ return keygen.generateKeyPair();
+ } finally {
+ if(tt!=null) {
+ tt.done();
+ }
+ }
+ }
+
+ private static final String LINE_END = "-----\n";
+
+ protected static String textBuilder(String kind, byte[] bytes) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append("-----BEGIN ");
+ sb.append(kind);
+ sb.append(LINE_END);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ base64.encode(bais, baos);
+ sb.append(new String(baos.toByteArray()));
+
+ if(sb.charAt(sb.length()-1)!='\n') {
+ sb.append('\n');
+ }
+ sb.append("-----END ");
+ sb.append(kind);
+ sb.append(LINE_END);
+ return sb.toString();
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {
+ byte[] bytes = decode(new StringReader(pk));
+ return toPrivateKey(trans, bytes);
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {
+ TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);
+ try {
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+ } catch (InvalidKeySpecException e) {
+ throw new CertException("Translating Private Key from PKCS8 KeySpec",e);
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {
+ TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);
+ try {
+ return toPrivateKey(trans,decode(file));
+ }finally {
+ tt.done();
+ }
+ }
+
+
+ public static String toString(Trans trans, PrivateKey pk) throws IOException {
+ trans.debug().log("Private Key to String");
+ return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());
+ }
+
+ public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {
+ TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);
+ try {
+ ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64noSplit.decode(bais, baos);
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));
+ } catch (InvalidKeySpecException e) {
+ trans.error().log(e,"Translating Public Key from X509 KeySpec");
+ return null;
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static String toString(Trans trans, PublicKey pk) throws IOException {
+ trans.debug().log("Public Key to String");
+ return textBuilder("PUBLIC KEY",pk.getEncoded());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, String x509) throws CertificateException {
+ return toX509Certificate(trans, x509.getBytes());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, List<String> x509s) throws CertificateException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ for(String x509 : x509s) {
+ baos.write(x509.getBytes());
+ }
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ return toX509Certificate(trans, new ByteArrayInputStream(baos.toByteArray()));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, byte[] x509) throws CertificateException {
+ return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ return toX509Certificate(trans,fis);
+ } finally {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, InputStream is) throws CertificateException {
+ TimeTaken tt=trans.start("Reconstitute Certificates", Env.SUB);
+ try {
+ return certificateFactory.generateCertificates(is);
+ } finally {
+ tt.done();
+ }
+ }
+
+
+
+ public static String toString(Trans trans, Certificate cert) throws IOException, CertException {
+ if(trans.debug().isLoggable()) {
+ StringBuilder sb = new StringBuilder("Certificate to String");
+ if(cert instanceof X509Certificate) {
+ sb.append(" - ");
+ sb.append(((X509Certificate)cert).getSubjectDN());
+ }
+ trans.debug().log(sb);
+ }
+ try {
+ if(cert==null) {
+ throw new CertException("Certificate not built");
+ }
+ return textBuilder("CERTIFICATE",cert.getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new CertException(e);
+ }
+ }
+
+ public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
+ return Cipher.getInstance(KEY_ALGO);
+ }
+
+ public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ Cipher cipher = Cipher.getInstance(KEY_ALGO);
+ cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);
+ return cipher;
+ }
+
+ public static byte[] strip(Reader rdr) throws IOException {
+ BufferedReader br = new BufferedReader(rdr);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ String line;
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ baos.write(line.getBytes());
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ public static class StripperInputStream extends InputStream {
+ private Reader created;
+ private BufferedReader br;
+ private int idx;
+ private String line;
+
+ public StripperInputStream(Reader rdr) {
+ if(rdr instanceof BufferedReader) {
+ br = (BufferedReader)rdr;
+ } else {
+ br = new BufferedReader(rdr);
+ }
+ created = null;
+ }
+
+ public StripperInputStream(File file) throws FileNotFoundException {
+ this(new FileReader(file));
+ created = br;
+ }
+
+ public StripperInputStream(InputStream is) throws FileNotFoundException {
+ this(new InputStreamReader(is));
+ created = br;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(line==null || idx>=line.length()) {
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ break;
+ }
+ }
+
+ if(line==null) {
+ return -1;
+ }
+ idx = 0;
+ }
+ return line.charAt(idx++);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static class Base64InputStream extends InputStream {
+ private InputStream created;
+ private InputStream is;
+ private byte trio[];
+ private byte duo[];
+ private int idx;
+
+
+ public Base64InputStream(File file) throws FileNotFoundException {
+ this(new FileInputStream(file));
+ created = is;
+ }
+
+ public Base64InputStream(InputStream is) throws FileNotFoundException {
+ this.is = is;
+ trio = new byte[3];
+ idx = 4;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(duo==null || idx>=duo.length) {
+ int read = is.read(trio);
+ if(read==-1) {
+ return -1;
+ }
+ duo = Symm.base64.decode(trio);
+ if(duo==null || duo.length==0) {
+ return -1;
+ }
+ idx=0;
+ }
+
+ return duo[idx++];
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static byte[] decode(byte[] bytes) throws IOException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64.decode(bais, baos);
+ return baos.toByteArray();
+ }
+
+ public static byte[] decode(File f) throws IOException {
+ FileReader fr = new FileReader(f);
+ try {
+ return Factory.decode(fr);
+ } finally {
+ fr.close();
+ }
+
+ }
+ public static byte[] decode(Reader rdr) throws IOException {
+ return decode(strip(rdr));
+ }
+
+
+ public static byte[] binary(File file) throws IOException {
+ DataInputStream dis = new DataInputStream(new FileInputStream(file));
+ try {
+ byte[] bytes = new byte[(int)file.length()];
+ dis.readFully(bytes);
+ return bytes;
+ } finally {
+ dis.close();
+ }
+ }
+
+
+ public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
+ TimeTaken tt = trans.start("Sign Data", Env.SUB);
+ try {
+ Signature sig = Signature.getInstance(SIG_ALGO);
+ sig.initSign(pk, random);
+ sig.update(bytes);
+ return sig.sign();
+ } finally {
+ tt.done();
+ }
+ }
+
+ // TODO IMPLEMENT!
+ public static void getSignature(byte[] signed) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..b5a3fb0
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifact.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.Trans;
+
+public interface PlaceArtifact {
+ public boolean place(Trans trans, CertInfo cert, Artifact arti) throws CadiException;
+}
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
index 0000000..219eb4a
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactInFiles extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup Public Cert
+ File f = new File(dir,arti.getAppName()+".crt");
+ write(f,Chmod.to644,certInfo.getCerts().get(0),C_R);
+
+ // Setup Private Key
+ f = new File(dir,arti.getAppName()+".key");
+ write(f,Chmod.to400,certInfo.getPrivatekey(),C_R);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+}
+
+
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
index 0000000..abe0586
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactInKeystore extends ArtifactDir {
+ private String kst;
+ //TODO get ROOT DNs or Trusted DNs from Certificate Manager.
+ private static String[] rootDNs = new String[]{
+ "CN=ATT CADI Root CA - Test, O=ATT, OU=CSO, C=US",
+ "CN=ATT AAF CADI CA, OU=CSO, O=ATT, C=US"
+ };
+
+ public PlaceArtifactInKeystore(String kst) {
+ this.kst = kst;
+ }
+
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ File fks = new File(dir,arti.getAppName()+'.'+kst);
+ try {
+ KeyStore jks = KeyStore.getInstance(kst);
+ if(fks.exists()) {
+ fks.delete();
+ }
+
+ // Get the Cert(s)... Might include Trust store
+ Collection<? extends Certificate> certColl = Factory.toX509Certificate(trans, certInfo.getCerts());
+ Certificate[] certs = new Certificate[certColl.size()];
+ certColl.toArray(certs);
+
+ boolean first = true;
+ StringBuilder issuers = new StringBuilder();
+ for(Certificate c : certs) {
+ if(c instanceof X509Certificate) {
+ X509Certificate xc = (X509Certificate)c;
+ String issuer = xc.getIssuerDN().toString();
+ for(String root : rootDNs) {
+ if(root.equals(issuer)) {
+ if(first) {
+ first=false;
+ } else {
+ issuers.append(":");
+ }
+ if(xc.getSubjectDN().toString().contains("Issuing CA")) {
+ issuers.append(xc.getSubjectDN());
+ }
+ }
+ }
+ }
+ }
+ addProperty(Config.CADI_X509_ISSUERS,issuers.toString());
+
+ // Add CADI Keyfile Entry to Properties
+ addProperty(Config.CADI_KEYFILE,arti.getDir()+'/'+arti.getAppName() + ".keyfile");
+ // Set Keystore Password
+ addProperty(Config.CADI_KEYSTORE,fks.getCanonicalPath());
+ String keystorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_KEYSTORE_PASSWORD,keystorePass);
+ char[] keystorePassArray = keystorePass.toCharArray();
+ jks.load(null,keystorePassArray); // load in
+
+ // Add Private Key/Cert Entry for App
+ // Note: Java SSL security classes, while having a separate key from keystore,
+ // is documented to not actually work.
+ // java.security.UnrecoverableKeyException: Cannot recover key
+ // You can create a custom Key Manager to make it work, but Practicality
+ // dictates that you live with the default, meaning, they are the same
+ String keyPass = keystorePass; //Symm.randomGen(CmAgent.PASS_SIZE);
+ PrivateKey pk = Factory.toPrivateKey(trans, certInfo.getPrivatekey());
+ addEncProperty(Config.CADI_KEY_PASSWORD, keyPass);
+ addProperty(Config.CADI_ALIAS, arti.getMechid());
+// Set<Attribute> attribs = new HashSet<Attribute>();
+// if(kst.equals("pkcs12")) {
+// // Friendly Name
+// attribs.add(new PKCS12Attribute("1.2.840.113549.1.9.20", arti.getAppName()));
+// }
+//
+ KeyStore.ProtectionParameter protParam =
+ new KeyStore.PasswordProtection(keyPass.toCharArray());
+
+ KeyStore.PrivateKeyEntry pkEntry =
+ new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]});
+ jks.setEntry(arti.getMechid(),
+ pkEntry, protParam);
+
+ // Write out
+ write(fks,Chmod.to400,jks,keystorePassArray);
+
+ // Change out to TrustStore
+ fks = new File(dir,arti.getAppName()+".trust."+kst);
+ jks = KeyStore.getInstance(kst);
+
+ // Set Truststore Password
+ addProperty(Config.CADI_TRUSTSTORE,fks.getCanonicalPath());
+ String trustStorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_TRUSTSTORE_PASSWORD,trustStorePass);
+ char[] truststorePassArray = trustStorePass.toCharArray();
+ jks.load(null,truststorePassArray); // load in
+
+ // Add Trusted Certificates
+ for(int i=1; i<certs.length;++i) {
+ jks.setCertificateEntry("cadi_" + arti.getCa() + '_' + i, certs[i]);
+ }
+ // Write out
+ write(fks,Chmod.to400,jks,truststorePassArray);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return false;
+ }
+
+}
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
index 0000000..7815a8e
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.PrintStream;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactOnStream implements PlaceArtifact {
+ private PrintStream out;
+
+ public PlaceArtifactOnStream(PrintStream printStream) {
+ out = printStream;
+ }
+
+ @Override
+ public boolean place(Trans trans, CertInfo capi, Artifact a) {
+ if(capi.getNotes()!=null && capi.getNotes().length()>0) {
+ trans.info().printf("Warning: %s\n",capi.getNotes());
+ }
+ out.printf("Challenge: %s\n",capi.getChallenge());
+ out.printf("PrivateKey:\n%s\n",capi.getPrivatekey());
+ out.println("Certificate Chain:");
+ for(String c : capi.getCerts()) {
+ out.println(c);
+ }
+ return true;
+ }
+}
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
index 0000000..0525739
--- /dev/null
+++ b/aaf/src/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.cm;
+
+import java.io.File;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactScripts extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup check.sh script
+ String filename = arti.getAppName()+".check.sh";
+ File f1 = new File(dir,filename);
+ String email = arti.getNotification() + '\n';
+ if(email.startsWith("mailto:")) {
+ email=email.substring(7);
+ } else {
+ email=arti.getOsUser() + '\n';
+ }
+ write(f1,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Check Script\n",
+ "# Check on Certificate, and renew if needed.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "DIR="+arti.getDir()+'\n',
+ "APP="+arti.getAppName()+'\n',
+ "EMAIL="+email,
+ checkScript
+ );
+
+ // Setup check.sh script
+ File f2 = new File(dir,arti.getAppName()+".crontab.sh");
+ write(f2,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Crontab Loading Script\n",
+ "# Add/Update a Crontab entry, that adds a check on Certificate Manager generated Certificate nightly.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "TFILE=\"/tmp/cmcron$$.temp\"\n",
+ "DIR=\""+arti.getDir()+"\"\n",
+ "CF=\""+arti.getAppName()+" Certificate Check Script\"\n",
+ "SCRIPT=\""+f1.getCanonicalPath()+"\"\n",
+ cronScript
+ );
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ private final static String checkScript =
+ "> $DIR/$APP.msg\n\n" +
+ "function mailit {\n" +
+ " printf \"$*\" | /bin/mail -s \"AAF Certman Notification for `uname -n`\" $EMAIL\n"+
+ "}\n\n" +
+ System.getProperty("java.home") + "/bin/" +"java -jar " +
+ System.getProperty("java.class.path") +
+ " cadi_prop_files=$DIR/$APP.props check 2> $DIR/$APP.STDERR > $DIR/$APP.STDOUT\n" +
+ "case \"$?\" in\n" +
+ " 0)\n" +
+ " # Note: Validation will be mailed only the first day after any modification\n" +
+ " if [ \"`find $DIR -mtime 0 -name $APP.check.sh`\" != \"\" ] ; then\n" +
+ " mailit `echo \"Certficate Validated:\\n\\n\" | cat - $DIR/$APP.msg`\n" +
+ " else\n" +
+ " cat $DIR/$APP.msg\n" +
+ " fi\n" +
+ " ;;\n" +
+ " 1) mailit \"Error with Certificate Check:\\\\n\\\\nCheck logs $DIR/$APP.STDOUT and $DIR/$APP.STDERR on `uname -n`\"\n" +
+ " ;;\n" +
+ " 2) mailit `echo \"Certificate Check Error\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " 10) mailit `echo \"Certificate Replaced\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " if [ -e $DIR/$APP.restart.sh ]; then\n" +
+ " # Note: it is THIS SCRIPT'S RESPONSIBILITY to notify upon success or failure as necessary!!\n" +
+ " /bin/sh $DIR/$APP.restart.sh\n" +
+ " fi\n" +
+ " ;;\n" +
+ " *) mailit `echo \"Unknown Error code for CM Agent\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " esac\n\n" +
+ " # Note: make sure to cover this sripts' exit Code\n";
+
+ private final static String cronScript =
+ "crontab -l | sed -n \"/#### BEGIN $CF/,/END $CF ####/!p\" > $TFILE\n" +
+ "# Note: Randomize Minutes (0-60) and hours (1-4)\n" +
+ "echo \"#### BEGIN $CF ####\" >> $TFILE\n" +
+ "echo \"$(( $RANDOM % 60)) $(( $(( $RANDOM % 3 )) + 1 )) * * * /bin/bash $SCRIPT " +
+ ">> $DIR/cronlog 2>&1 \" >> $TFILE\n" +
+ "echo \"#### END $CF ####\" >> $TFILE\n" +
+ "crontab $TFILE\n" +
+ "rm $TFILE\n";
+}
+
+
+
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
index 0000000..f65f03f
--- /dev/null
+++ b/aaf/src/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+public class TestAccess implements Access {
+ private Symm symm;
+ private PrintStream out;
+
+ public TestAccess(PrintStream out) {
+ this.out = out;
+ InputStream is = ClassLoader.getSystemResourceAsStream("cadi.properties");
+ try {
+ System.getProperties().load(is);
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ }
+ }
+
+ String keyfile = System.getProperty(Config.CADI_KEYFILE);
+ if(keyfile==null) {
+ System.err.println("No " + Config.CADI_KEYFILE + " in Classpath");
+ } else {
+ try {
+ is = new FileInputStream(keyfile);
+ try {
+ symm = Symm.obtain(is);
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ }
+ }
+
+
+
+ }
+
+ public void log(Level level, Object... elements) {
+ boolean first = true;
+ for(int i=0;i<elements.length;++i) {
+ if(first)first = false;
+ else out.print(' ');
+ out.print(elements[i].toString());
+ }
+ out.println();
+ }
+
+ public void log(Exception e, Object... elements) {
+ e.printStackTrace(out);
+ log(Level.ERROR,elements);
+ }
+
+ public void setLogLevel(Level level) {
+
+ }
+
+ @Override
+ public boolean willLog(Level level) {
+ return true;
+ }
+
+ public ClassLoader classLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ public String getProperty(String string, String def) {
+ String rv = System.getProperty(string);
+ return rv==null?def:rv;
+ }
+
+ public void load(InputStream is) throws IOException {
+
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+}
diff --git a/aaf/src/src/test/resources/cadi.properties b/aaf/src/src/test/resources/cadi.properties
new file mode 100644
index 0000000..4f38cf5
--- /dev/null
+++ b/aaf/src/src/test/resources/cadi.properties
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+##
+## AUTHZ API (authz-service) Properties
+##
+
+cadi_prop_file=com.att.aaf.props;com.att.aaf.common.props
+
+#cadi_trust_all_x509=true
+#cadi_alias=aaf.att
+https.protocols=TLSv1.1,TLSv1.2
+
+cm_url=https://XXX:8150
+
+basic_realm=localized
+basic_warn=false
+localhost_deny=false
+
+cass_group_name=com.att.aaf
+cass_cluster_name=mithrilcsp.sbc.com
+aaf_default_realm=com.att.csp
+
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE
+aaf_id=???
+aaf_password=enc:XXX
+
+aaf_user_expires=3000
+aaf_clean_interval=4000
+
diff --git a/aaf/src/src/test/resources/log4j.properties b/aaf/src/src/test/resources/log4j.properties
new file mode 100644
index 0000000..91b81ef
--- /dev/null
+++ b/aaf/src/src/test/resources/log4j.properties
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] %m %n
+
+# General Apache libraries
+log4j.rootLogger=WARN,stdout
+log4j.logger.org.apache=WARN,stdout
+log4j.logger.dme2=WARN,stdout
+log4j.logger.init=INFO,stdout
+log4j.logger.authz=INFO,stdout
+log4j.logger.audit=WARN,stdout
+
+
+
diff --git a/aaf/src/src/test/resources/logging.props b/aaf/src/src/test/resources/logging.props
new file mode 100644
index 0000000..9a30a2a
--- /dev/null
+++ b/aaf/src/src/test/resources/logging.props
@@ -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
index 0000000..676dcc1
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/content/JU_Content.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.content;
+
+import java.io.StringReader;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import aaf.v2_0.Error;
+
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaData;
+import com.att.rosetta.env.RosettaEnv;
+
+public class JU_Content {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+
+ @Test
+ public void parseErrorJSON() throws Exception {
+ final String msg = "{\"messageId\":\"SVC2000\",\"text\":\"Select which cred to delete (or 0 to delete all):" +
+ "1) %1" +
+ "2) %2" +
+ "3) %3" +
+ "4) %4" +
+ "Run same command again with chosen entry as last parameter\"," +
+ "\"variables\":[" +
+ "\"m55555@jr583u.cred.test.com 1 Wed Oct 08 11:48:08 CDT 2014\"," +
+ "\"m55555@jr583u.cred.test.com 1 Thu Oct 09 12:54:46 CDT 2014\"," +
+ "\"m55555@jr583u.cred.test.com 1 Tue Jan 06 05:00:00 CST 2015\"," +
+ "\"m55555@jr583u.cred.test.com 1 Wed Jan 07 05:00:00 CST 2015\"]}";
+
+ Error err = new Error();
+ err.setText("Hello");
+ err.getVariables().add("I'm a teapot");
+ err.setMessageId("12");
+
+
+// System.out.println(msg);
+ RosettaEnv env = new RosettaEnv();
+ RosettaDF<aaf.v2_0.Error> errDF = env.newDataFactory(aaf.v2_0.Error.class);
+ errDF.in(RosettaData.TYPE.JSON);
+ errDF.out(RosettaData.TYPE.JSON);
+ RosettaData<Error> data = errDF.newData();
+ data.load(err);
+ System.out.println(data.asString());
+
+ data.load(new StringReader(msg));
+ err = data.asObject();
+ System.out.println(err.getText());
+ }
+
+
+}
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
index 0000000..f6cbce2
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/example/CadiTest.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.example;
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+
+import com.att.cadi.Access;
+import com.att.cadi.PropAccess;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HClient;
+import com.att.cadi.http.HX509SS;
+
+public class CadiTest {
+ public static void main(String args[]) {
+ Access access = new PropAccess();
+ try {
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ HClient hclient = new HClient(
+ new HX509SS(si),
+ new URI("https://mithrilcsp.sbc.com:8085"),3000);
+ hclient.setMethod("OPTIONS");
+ hclient.setPathInfo("/gui/cadi/log/toggle/INFO");
+ hclient.send();
+ Future<String> future = hclient.futureReadString();
+ if(future.get(5000)) {
+ System.out.println(future.value);
+ } else {
+ System.out.printf("Error: %d-%s", future.code(),future.body());
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
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
index 0000000..78b5e99
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/example/ExampleAuthCheck.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.example;
+
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.locator.DNSLocator;
+
+public class ExampleAuthCheck {
+ public static void main(String args[]) {
+ // Link or reuse to your Logging mechanism
+ PropAccess myAccess = new PropAccess(); //
+
+ try {
+ AAFConHttp acon = new AAFConHttp(myAccess, new DNSLocator(
+ myAccess,"https","localhost","8100"));
+ AAFAuthn<?> authn = acon.newAuthn();
+ long start;
+ for (int i=0;i<10;++i) {
+ start = System.nanoTime();
+ String err = authn.validate("", "gritty");
+ if(err!=null) System.err.println(err);
+ else System.out.println("I'm ok");
+
+ err = authn.validate("bogus", "gritty");
+ if(err!=null) System.err.println(err + " (correct error)");
+ else System.out.println("I'm ok");
+
+ System.out.println((System.nanoTime()-start)/1000000f + " ms");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
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
index 0000000..11092df
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.example;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConDME2;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+
+public class ExamplePerm2_0 {
+ public static void main(String args[]) {
+
+ // Link or reuse to your Logging mechanism
+ PropAccess myAccess = new PropAccess();
+
+ //
+ try {
+ AAFCon<?> acon = new AAFConDME2(myAccess);
+
+ // AAFLur has pool of DME clients as needed, and Caches Client lookups
+ AAFLurPerm aafLur = acon.newLur();
+
+ // Note: If you need both Authn and Authz construct the following:
+ AAFAuthn<?> aafAuthn = acon.newAuthn(aafLur);
+
+ // Do not set Mech ID until after you construct AAFAuthn,
+ // because we initiate "401" info to determine the Realm of
+ // of the service we're after.
+ acon.basicAuth("mc0897@aaf.att.com", "XXXXXX");
+
+ try {
+
+ // Normally, you obtain Principal from Authentication System.
+ // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
+ // If you use CADI as Authenticator, it will get you these Principals from
+ // CSP or BasicAuth mechanisms.
+ String id = "mc0897@aaf.att.com"; //"cluster_admin@gridcore.att.com";
+
+ // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
+ String ok = aafAuthn.validate(id, "XXXXXX");
+ if(ok!=null)System.out.println(ok);
+
+ ok = aafAuthn.validate(id, "wrongPass");
+ if(ok!=null)System.out.println(ok);
+
+
+ // AAF Style permissions are in the form
+ // Type, Instance, Action
+ AAFPermission perm = new AAFPermission("com.att.grid.core.coh",":dev_cluster", "WRITE");
+
+ // Now you can ask the LUR (Local Representative of the User Repository about Authorization
+ // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object
+ // instead of creating your own LUR
+ System.out.println("Does " + id + " have " + perm);
+ if(aafLur.fish(id, perm)) {
+ System.out.println("Yes, you have permission");
+ } else {
+ System.out.println("No, you don't have permission");
+ }
+
+ System.out.println("Does Bogus have " + perm);
+ if(aafLur.fish("Bogus", perm)) {
+ System.out.println("Yes, you have permission");
+ } else {
+ System.out.println("No, you don't have permission");
+ }
+
+ // Or you can all for all the Permissions available
+ List<Permission> perms = new ArrayList<Permission>();
+
+ aafLur.fishAll(id,perms);
+ for(Permission prm : perms) {
+ System.out.println(prm.getKey());
+ }
+
+ // It might be helpful in some cases to clear the User's identity from the Cache
+ aafLur.remove(id);
+ } finally {
+ aafLur.destroy();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
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
index 0000000..2012465
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/example/ExamplePerm2_0_DME2.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.example;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+import com.att.cadi.locator.DNSLocator;
+
+public class ExamplePerm2_0_DME2 {
+ public static void main(String args[]) {
+ // Link or reuse to your Logging mechanism
+ PropAccess myAccess = new PropAccess();
+
+ //
+ try {
+ AAFConHttp acon = new AAFConHttp(myAccess, new DNSLocator(
+ myAccess,"https","localhost","8100"));
+
+ // AAFLur has pool of DME clients as needed, and Caches Client lookups
+ AAFLurPerm aafLur = acon.newLur();
+
+ // Note: If you need both Authn and Authz construct the following:
+ AAFAuthn<?> aafAuthn = acon.newAuthn(aafLur);
+
+ // Do not set Mech ID until after you construct AAFAuthn,
+ // because we initiate "401" info to determine the Realm of
+ // of the service we're after.
+ acon.basicAuth("mc0897@aaf.att.com", "XXXXXX");
+
+ try {
+
+ // Normally, you obtain Principal from Authentication System.
+ // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
+ // If you use CADI as Authenticator, it will get you these Principals from
+ // CSP or BasicAuth mechanisms.
+ String id = "mc0897@aaf.att.com"; //"cluster_admin@gridcore.att.com";
+
+ // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
+ String ok = aafAuthn.validate(id, "XXXXXX");
+ if(ok!=null)System.out.println(ok);
+
+ ok = aafAuthn.validate(id, "wrongPass");
+ if(ok!=null)System.out.println(ok);
+
+
+ // AAF Style permissions are in the form
+ // Type, Instance, Action
+ AAFPermission perm = new AAFPermission("com.att.grid.core.coh",":dev_cluster", "WRITE");
+
+ // Now you can ask the LUR (Local Representative of the User Repository about Authorization
+ // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object
+ // instead of creating your own LUR
+ System.out.println("Does " + id + " have " + perm);
+ if(aafLur.fish(id, perm)) {
+ System.out.println("Yes, you have permission");
+ } else {
+ System.out.println("No, you don't have permission");
+ }
+
+ System.out.println("Does Bogus have " + perm);
+ if(aafLur.fish("Bogus", perm)) {
+ System.out.println("Yes, you have permission");
+ } else {
+ System.out.println("No, you don't have permission");
+ }
+
+ // Or you can all for all the Permissions available
+ List<Permission> perms = new ArrayList<Permission>();
+
+ aafLur.fishAll(id,perms);
+ for(Permission prm : perms) {
+ System.out.println(prm.getKey());
+ }
+
+ // It might be helpful in some cases to clear the User's identity from the Cache
+ aafLur.remove(id);
+ } finally {
+ aafLur.destroy();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
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
index 0000000..e1b6be6
--- /dev/null
+++ b/aaf/src/test/java/com/att/aaf/example/X509Test.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.example;
+
+import java.security.Principal;
+
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+import com.att.cadi.client.Future;
+import com.att.cadi.locator.DNSLocator;
+import com.att.cadi.lur.LocalPermission;
+
+public class X509Test {
+ public static void main(String args[]) {
+ // Link or reuse to your Logging mechanism
+
+ PropAccess myAccess = new PropAccess();
+
+ //
+ try {
+ AAFConHttp con = new AAFConHttp(myAccess,
+ new DNSLocator(myAccess,"https","mithrilcsp.sbc.com","8100"));
+
+ // AAFLur has pool of DME clients as needed, and Caches Client lookups
+ AAFLurPerm aafLur = con.newLur();
+
+ // Note: If you need both Authn and Authz construct the following:
+// AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);
+
+ // con.x509Alias("aaf.att"); // alias in keystore
+
+ try {
+
+ // Normally, you obtain Principal from Authentication System.
+// // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
+// // If you use CADI as Authenticator, it will get you these Principals from
+// // CSP or BasicAuth mechanisms.
+// String id = "cluster_admin@gridcore.att.com";
+//
+// // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
+ Future<String> fs =
+ con.client("2.0").read("/authz/perms/com.att.aaf.ca","application/Perms+json");
+ if(fs.get(3000)) {
+ System.out.println(fs.value);
+ } else {
+ System.out.println("Error: " + fs.code() + ':' + fs.body());
+ }
+
+ // Check on Perms with LUR
+ if(aafLur.fish(new Principal() {
+ @Override
+ public String getName() {
+ return "m12345@aaf.att.com";
+ }
+ }, new LocalPermission("com.att.aaf.ca|aaf|request"))) {
+ System.out.println("Has Perm");
+ } else {
+ System.out.println("Does NOT Have Perm");
+ }
+ } finally {
+ aafLur.destroy();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
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
index 0000000..b71a9ba
--- /dev/null
+++ b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_JMeter.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.HttpURLConnection;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+import com.att.cadi.aaf.v2_0.AAFTaf;
+import com.att.cadi.config.Config;
+import com.att.cadi.locator.DNSLocator;
+import com.att.cadi.principal.CachedBasicPrincipal;
+
+import junit.framework.Assert;
+
+public class JU_JMeter {
+ private static AAFConHttp aaf;
+ private static AAFAuthn<HttpURLConnection> aafAuthn;
+ private static AAFLurPerm aafLur;
+ private static ArrayList<Principal> perfIDs;
+
+ private static AAFTaf<HttpURLConnection> aafTaf;
+ private static PropAccess access;
+
+ @BeforeClass
+ public static void before() throws Exception {
+ if(aafLur==null) {
+ Properties props = System.getProperties();
+ props.setProperty("AFT_LATITUDE", "32.780140");
+ props.setProperty("AFT_LONGITUDE", "-96.800451");
+ props.setProperty("DME2_EP_REGISTRY_CLASS","DME2FS");
+ props.setProperty("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");
+ props.setProperty("AFT_ENVIRONMENT", "AFTUAT");
+ props.setProperty("SCLD_PLATFORM", "NON-PROD");
+ props.setProperty(Config.AAF_URL,"https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");
+ props.setProperty(Config.AAF_READ_TIMEOUT, "2000");
+ int timeToLive = 3000;
+ props.setProperty(Config.AAF_CLEAN_INTERVAL, Integer.toString(timeToLive));
+ props.setProperty(Config.AAF_HIGH_COUNT, "4");
+
+ String aafPerfIDs = props.getProperty("AAF_PERF_IDS");
+ perfIDs = new ArrayList<Principal>();
+ File perfFile = null;
+ if(aafPerfIDs!=null) {
+ perfFile = new File(aafPerfIDs);
+ }
+
+ access = new PropAccess();
+ aaf = new AAFConHttp(access, new DNSLocator(access,"https","localhost","8100"));
+ aafTaf = new AAFTaf<HttpURLConnection>(aaf,false);
+ aafLur = aaf.newLur(aafTaf);
+ aafAuthn = aaf.newAuthn(aafTaf);
+ aaf.basicAuth("testid@aaf.att.com", "whatever");
+
+ if(perfFile==null||!perfFile.exists()) {
+ perfIDs.add(new CachedBasicPrincipal(aafTaf,
+ "Basic dGVzdGlkOndoYXRldmVy",
+ "aaf.att.com",timeToLive));
+ perfIDs.add(new Princ("ab1234@aaf.att.com")); // Example of Local ID, which isn't looked up
+ } else {
+ BufferedReader ir = new BufferedReader(new FileReader(perfFile));
+ try {
+ String line;
+ while((line = ir.readLine())!=null) {
+ if((line=line.trim()).length()>0)
+ perfIDs.add(new Princ(line));
+ }
+ } finally {
+ ir.close();
+ }
+ }
+ Assert.assertNotNull(aafLur);
+ }
+ }
+
+ private static class Princ implements Principal {
+ private String name;
+ public Princ(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return name;
+ }
+
+ };
+
+ private static int index = -1;
+
+ private synchronized Principal getIndex() {
+ if(perfIDs.size()<=++index)index=0;
+ return perfIDs.get(index);
+ }
+ @Test
+ public void test() {
+ try {
+ aafAuthn.validate("testid@aaf.att.com", "whatever");
+ List<Permission> perms = new ArrayList<Permission>();
+ aafLur.fishAll(getIndex(), perms);
+// Assert.assertFalse(perms.isEmpty());
+// for(Permission p : perms) {
+// //access.log(Access.Level.AUDIT, p.permType());
+// }
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ Assert.assertFalse(sw.toString(),true);
+ }
+ }
+
+}
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
index 0000000..2608980
--- /dev/null
+++ b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_Lur2_0Call.java
@@ -0,0 +1,576 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Lur;
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+import com.att.cadi.aaf.v2_0.AAFTaf;
+import com.att.cadi.locator.DNSLocator;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.cadi.lur.LocalPermission;
+import com.att.cadi.taf.TafResp;
+
+public class JU_Lur2_0Call {
+ private static AAFConHttp aaf;
+ private static PropAccess access;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ access = new PropAccess();
+ aaf = new AAFConHttp(access,new DNSLocator(access,"https","localhost","8100"));
+ aaf.basicAuth("testid", "whatever");
+ }
+
+ @Test
+ public void test() throws Exception {
+
+ AAFLurPerm aafLur = aaf.newLur();
+
+ Principal pri = new ConfigPrincipal("testid@aaf.att.com","whatever");
+ for (int i = 0; i < 10; ++i) {
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|write"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kumquat|write"),false);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|read"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kumquat|read"),true);
+
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","write"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","kumquat","write"),false);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","read"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","kumquat","read"),true);
+
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum.*|read"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|!wr*"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance"),true);
+
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!kum.*","read"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","!wr*"),true);
+
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum[Qq]uat|read"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my[iI]nstance|!wr*"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my[iI]nstance|!wr*"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|!wr*"),true);
+
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!kum[Qq]uat","read"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!my[iI]nstance","!wr*"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","!my[iI]nstance","!wr*"),true);
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service","myInstance","!wr*"),true);
+
+
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!my.nstance|!wr*"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|my.nstance|!wr*"),false);
+
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|my.nstance|!wr*"),false);
+
+ //Maitrayee, aren't we going to have issues if we do RegExp with "."?
+ //Is it too expensive to only do Reg Ex in presence of special characters, []{}*, etc? Not sure this helps for GRID.
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|kum.quat|read"),true);
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|!kum..uat|read"),true);
+
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance"),true); // ok if Stored Action is "*"
+
+ // Key Evaluations
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*:!my.*|write"),true); // ok if Stored Action is "*"
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*|write"),false); // not ok if key lengths don't match "*"
+ print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|:myCluster:*:myCF|write"),true); // ok if Stored Action is "*"
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*:!my.*","write"),true); // ok if Stored Action is "*"
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*:myCF","write"),true); // ok if Stored Action is "*"
+ print(aafLur, pri, new AAFPermission("com.test.JU_Lur2_0Call.service",":myCluster:*","write"),false); // not ok if key lengths don't match
+
+ }
+
+ print(aafLur, pri, new LocalPermission("bogus"),false);
+
+// try {
+// Thread.sleep(7000);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+ for (int i = 0; i < 10; ++i)
+ print(aafLur, pri, new LocalPermission("supergroup"),false);
+
+ System.out.println("All Done");
+ }
+ @Test
+ public void testTaf() throws Exception {
+ AAFTaf<?> aaft = new AAFTaf<HttpURLConnection>(aaf,true);
+
+ TafResp resp;
+ // No Header
+ resp = aaft.validate(LifeForm.CBLF, new Req(), null);
+ assertEquals(TafResp.RESP.TRY_AUTHENTICATING, resp.isAuthenticated());
+
+ String auth = "Basic " + Symm.base64.encode("testid:whatever");
+ resp = aaft.validate(LifeForm.CBLF, new Req("Authorization",auth), null);
+ assertEquals(TafResp.RESP.IS_AUTHENTICATED, resp.isAuthenticated());
+
+ }
+// @Test
+// public void testRole() throws CadiException {
+// TestAccess ta = new TestAccess();
+// AAFLurRole1_0 aafLur = new AAFLurRole1_0(
+// ta,
+//// "http://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=1.0.0/envContext=UAT/routeOffer=BAU_SE",
+// "http://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=1.0.0/envContext=DEV/routeOffer=D1",
+// "m12345", "m12345pass", 50000, // dme Time
+// // 5*60000); // 5 minutes User Expiration
+// 50000, // 5 seconds after Expiration
+// 200); // High Count of items.. These do not take much memory
+//
+// Principal pri = new ConfigPrincipal("xy1234","whatever);
+// for (int i = 0; i < 10; ++i) {
+//// print(aafLur, pri, new LocalPermission("*|*|*|com.att.authz"));
+// print(aafLur, pri, new LocalPermission("service|myInstance|write"),false);
+// print(aafLur, pri, new LocalPermission("com.test.JU_Lur2_0Call.service|myInstance|write"),false);
+// print(aafLur, pri, new LocalPermission("com.att.cadi"),true);
+// print(aafLur, pri, new LocalPermission("global"),true);
+// print(aafLur, pri, new LocalPermission("kumquat"),false);
+// }
+//
+// print(aafLur, pri, new LocalPermission("bogus"),false);
+//
+// for (int i = 0; i < 10; ++i)
+// print(aafLur, pri, new LocalPermission("supergroup"),false);
+//
+// System.out.println("All Done");
+// }
+
+
+ private void print(Lur aafLur, Principal pri, Permission perm, boolean shouldBe)
+ throws CadiException {
+ long start = System.nanoTime();
+
+ // The Call
+ boolean ok = aafLur.fish(pri, perm);
+
+ assertEquals(shouldBe,ok);
+ float ms = (System.nanoTime() - start) / 1000000f;
+ if (ok) {
+ System.out.println("Yes, part of " + perm.getKey() + " (" + ms
+ + "ms)");
+ } else {
+ System.out.println("No, not part of " + perm.getKey() + " (" + ms
+ + "ms)");
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public class Req implements HttpServletRequest {
+ private String[] headers;
+
+ public Req(String ... headers) {
+ this.headers = headers;
+ }
+
+ public Object getAttribute(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getAttributeNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getCharacterEncoding() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setCharacterEncoding(String env)
+ throws UnsupportedEncodingException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public int getContentLength() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getContentType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ServletInputStream getInputStream() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getParameter(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getParameterNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getParameterValues(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map getParameterMap() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getProtocol() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getScheme() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getServerName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getServerPort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public BufferedReader getReader() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRemoteAddr() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRemoteHost() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setAttribute(String name, Object o) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeAttribute(String name) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Locale getLocale() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getLocales() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean isSecure() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRealPath(String path) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getRemotePort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getLocalName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getLocalAddr() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getLocalPort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getAuthType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Cookie[] getCookies() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public long getDateHeader(String name) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getHeader(String name) {
+ for(int i=1;i<headers.length;i=i+2) {
+ if(headers[i-1].equals(name)) return headers[i];
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getHeaders(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getHeaderNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getIntHeader(String name) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getMethod() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getPathInfo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getPathTranslated() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getContextPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getQueryString() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRemoteUser() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean isUserInRole(String role) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public Principal getUserPrincipal() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRequestedSessionId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getRequestURI() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public StringBuffer getRequestURL() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getServletPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public HttpSession getSession(boolean create) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public HttpSession getSession() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean isRequestedSessionIdValid() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromCookie() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromURL() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromUrl() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest,
+ ServletResponse servletResponse) throws IllegalStateException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response)
+ throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password)
+ throws ServletException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void logout() throws ServletException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+}
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
index 0000000..efd108f
--- /dev/null
+++ b/aaf/src/test/java/com/att/cadi/lur/aaf/test/JU_PermEval.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import com.att.cadi.aaf.PermEval;
+
+public class JU_PermEval {
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() {
+ assertTrue(PermEval.evalInstance(":com.att.temp:role:write",":!com.att.*:role:write"));
+
+ // TRUE
+ assertTrue(PermEval.evalAction("fred","fred"));
+ assertTrue(PermEval.evalAction("fred,wilma","fred"));
+ assertTrue(PermEval.evalAction("barney,betty,fred,wilma","fred"));
+ assertTrue(PermEval.evalAction("*","fred"));
+
+ assertTrue(PermEval.evalInstance("fred","fred"));
+ assertTrue(PermEval.evalInstance("fred,wilma","fred"));
+ assertTrue(PermEval.evalInstance("barney,betty,fred,wilma","fred"));
+ assertTrue(PermEval.evalInstance("*","fred"));
+
+ assertTrue(PermEval.evalInstance(":fred:fred",":fred:fred"));
+ assertTrue(PermEval.evalInstance(":fred:fred,wilma",":fred:fred"));
+ assertTrue(PermEval.evalInstance(":fred:barney,betty,fred,wilma",":fred:fred"));
+ assertTrue(PermEval.evalInstance("*","fred"));
+ assertTrue(PermEval.evalInstance(":*:fred",":fred:fred"));
+ assertTrue(PermEval.evalInstance(":fred:*",":fred:fred"));
+ assertTrue(PermEval.evalInstance(":fred:fred",":!f.*:fred"));
+ assertTrue(PermEval.evalInstance(":fred:fred",":fred:!f.*"));
+
+ /// FALSE
+ assertFalse(PermEval.evalInstance("fred","wilma"));
+ assertFalse(PermEval.evalInstance("fred,barney,betty","wilma"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":fred:wilma"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":wilma:fred"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":wilma:!f.*"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":!f.*:wilma"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":!w.*:!f.*"));
+ assertFalse(PermEval.evalInstance(":fred:fred",":!f.*:!w.*"));
+
+ assertFalse(PermEval.evalInstance(":fred:fred",":fred:!x.*"));
+
+ // MSO Tests 12/3/2015
+ assertFalse(PermEval.evalInstance("/v1/services/features/*","/v1/services/features"));
+ assertFalse(PermEval.evalInstance(":v1:services:features:*",":v1:services:features"));
+ assertTrue(PermEval.evalInstance("/v1/services/features/*","/v1/services/features/api1"));
+ assertTrue(PermEval.evalInstance(":v1:services:features:*",":v1:services:features:api2"));
+ // MSO - Xue Gao
+ assertTrue(PermEval.evalInstance(":v1:requests:*",":v1:requests:test0-service"));
+
+
+
+ // Same tests, with Slashes
+ assertTrue(PermEval.evalInstance("/fred/fred","/fred/fred"));
+ assertTrue(PermEval.evalInstance("/fred/fred,wilma","/fred/fred"));
+ assertTrue(PermEval.evalInstance("/fred/barney,betty,fred,wilma","/fred/fred"));
+ assertTrue(PermEval.evalInstance("*","fred"));
+ assertTrue(PermEval.evalInstance("/*/fred","/fred/fred"));
+ assertTrue(PermEval.evalInstance("/fred/*","/fred/fred"));
+ assertTrue(PermEval.evalInstance("/fred/fred","/!f.*/fred"));
+ assertTrue(PermEval.evalInstance("/fred/fred","/fred/!f.*"));
+
+ /// FALSE
+ assertFalse(PermEval.evalInstance("fred","wilma"));
+ assertFalse(PermEval.evalInstance("fred,barney,betty","wilma"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/fred/wilma"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/wilma/fred"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/wilma/!f.*"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/!f.*/wilma"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/!w.*/!f.*"));
+ assertFalse(PermEval.evalInstance("/fred/fred","/!f.*/!w.*"));
+
+ assertFalse(PermEval.evalInstance("/fred/fred","/fred/!x.*"));
+
+ }
+
+}
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
index 0000000..cec5404
--- /dev/null
+++ b/aaf/src/test/java/com/att/cadi/lur/aaf/test/MultiThreadPermHit.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.att.cadi.Access;
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.aaf.v2_0.AAFLurPerm;
+import com.att.cadi.config.Config;
+import com.att.cadi.locator.PropertyLocator;
+
+public class MultiThreadPermHit {
+ public static void main(String args[]) {
+ // Link or reuse to your Logging mechanism
+ PropAccess myAccess = new PropAccess(); //
+
+ //
+ try {
+ AAFConHttp con = new AAFConHttp(myAccess,new PropertyLocator("https://mithrilcsp.sbc.com:8100"));
+
+ // AAFLur has pool of DME clients as needed, and Caches Client lookups
+ final AAFLurPerm aafLur = con.newLur();
+ aafLur.setDebug("m12345@aaf.att.com");
+
+ // Note: If you need both Authn and Authz construct the following:
+ AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);
+
+ // Do not set Mech ID until after you construct AAFAuthn,
+ // because we initiate "401" info to determine the Realm of
+ // of the service we're after.
+ final String id = myAccess.getProperty(Config.AAF_MECHID,null);
+ final String pass = myAccess.decrypt(myAccess.getProperty(Config.AAF_MECHPASS,null),false);
+ if(id!=null && pass!=null) {
+ try {
+
+ // Normally, you obtain Principal from Authentication System.
+ // // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
+ // // If you use CADI as Authenticator, it will get you these Principals from
+ // // CSP or BasicAuth mechanisms.
+ // String id = "cluster_admin@gridcore.att.com";
+ //
+ // // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
+ String ok;
+ ok = aafAuthn.validate(id, pass);
+ if(ok!=null) {
+ System.out.println(ok);
+ }
+
+ List<Permission> pond = new ArrayList<Permission>();
+ for(int i=0;i<20;++i) {
+ pond.clear();
+ aafLur.fishAll(i+id, pond);
+ if(ok!=null && i%1000==0) {
+ System.out.println(i + " " + ok);
+ }
+ }
+
+ for(int i=0;i<1000000;++i) {
+ ok = aafAuthn.validate( i+ id, "wrongPass");
+ if(ok!=null && i%1000==0) {
+ System.out.println(i + " " + ok);
+ }
+ }
+
+ final AAFPermission perm = new AAFPermission("com.att.aaf.access","*","*");
+
+ // Now you can ask the LUR (Local Representative of the User Repository about Authorization
+ // With CADI, in J2EE, you can call isUserInRole("com.att.mygroup|mytype|write") on the Request Object
+ // instead of creating your own LUR
+ for(int i=0;i<4;++i) {
+ if(aafLur.fish(id, perm)) {
+ System.out.println("Yes, " + id + " has permission for " + perm.getKey());
+ } else {
+ System.out.println("No, " + id + " does not have permission for " + perm.getKey());
+ }
+ }
+
+
+ // Or you can all for all the Permissions available
+ List<Permission> perms = new ArrayList<Permission>();
+
+
+ aafLur.fishAll(id,perms);
+ System.out.println("Perms for " + id);
+ for(Permission prm : perms) {
+ System.out.println(prm.getKey());
+ }
+
+ System.out.println("Press any key to continue");
+ System.in.read();
+
+ for(int j=0;j<5;++j) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ for(int i=0;i<20;++i) {
+ if(aafLur.fish(id, perm)) {
+ System.out.println("Yes, " + id + " has permission for " + perm.getKey());
+ } else {
+ System.out.println("No, " + id + " does not have permission for " + perm.getKey());
+ }
+ }
+ }
+ }).start();
+ }
+
+
+ } finally {
+ aafLur.destroy();
+ }
+ } else { // checked on IDs
+ System.err.println(Config.AAF_MECHID + " and/or " + Config.AAF_MECHPASS + " are not set.");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
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
index 0000000..0554d1d
--- /dev/null
+++ b/aaf/src/test/java/com/att/cadi/lur/aaf/test/TestAccess.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.aaf.test;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+public class TestAccess implements Access {
+ private Symm symm;
+ private PrintStream out;
+
+ public TestAccess(PrintStream out) {
+ this.out = out;
+ InputStream is = ClassLoader.getSystemResourceAsStream("cadi.properties");
+ try {
+ System.getProperties().load(is);
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ }
+ }
+
+ String keyfile = System.getProperty(Config.CADI_KEYFILE);
+ if(keyfile==null) {
+ System.err.println("No " + Config.CADI_KEYFILE + " in Classpath");
+ } else {
+ try {
+ is = new FileInputStream(keyfile);
+ try {
+ symm = Symm.obtain(is);
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(out);
+ }
+ }
+
+
+
+ }
+
+ public void log(Level level, Object... elements) {
+ boolean first = true;
+ for(int i=0;i<elements.length;++i) {
+ if(first)first = false;
+ else out.print(' ');
+ out.print(elements[i].toString());
+ }
+ out.println();
+ }
+
+ public void log(Exception e, Object... elements) {
+ e.printStackTrace(out);
+ log(Level.ERROR,elements);
+ }
+
+ public void setLogLevel(Level level) {
+
+ }
+
+ @Override
+ public boolean willLog(Level level) {
+ return true;
+ }
+
+ public ClassLoader classLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ public String getProperty(String string, String def) {
+ String rv = System.getProperty(string);
+ return rv==null?def:rv;
+ }
+
+ public void load(InputStream is) throws IOException {
+
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/aaf/src/test/resources/cadi.properties b/aaf/src/test/resources/cadi.properties
new file mode 100644
index 0000000..4f38cf5
--- /dev/null
+++ b/aaf/src/test/resources/cadi.properties
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+##
+## AUTHZ API (authz-service) Properties
+##
+
+cadi_prop_file=com.att.aaf.props;com.att.aaf.common.props
+
+#cadi_trust_all_x509=true
+#cadi_alias=aaf.att
+https.protocols=TLSv1.1,TLSv1.2
+
+cm_url=https://XXX:8150
+
+basic_realm=localized
+basic_warn=false
+localhost_deny=false
+
+cass_group_name=com.att.aaf
+cass_cluster_name=mithrilcsp.sbc.com
+aaf_default_realm=com.att.csp
+
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE
+aaf_id=???
+aaf_password=enc:XXX
+
+aaf_user_expires=3000
+aaf_clean_interval=4000
+
diff --git a/aaf/src/test/resources/log4j.properties b/aaf/src/test/resources/log4j.properties
new file mode 100644
index 0000000..91b81ef
--- /dev/null
+++ b/aaf/src/test/resources/log4j.properties
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] %m %n
+
+# General Apache libraries
+log4j.rootLogger=WARN,stdout
+log4j.logger.org.apache=WARN,stdout
+log4j.logger.dme2=WARN,stdout
+log4j.logger.init=INFO,stdout
+log4j.logger.authz=INFO,stdout
+log4j.logger.audit=WARN,stdout
+
+
+
diff --git a/aaf/src/test/resources/logging.props b/aaf/src/test/resources/logging.props
new file mode 100644
index 0000000..9a30a2a
--- /dev/null
+++ b/aaf/src/test/resources/logging.props
@@ -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
index 0000000..cf85207
--- /dev/null
+++ b/cass/.gitignore
@@ -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
index 0000000..f9676b0
--- /dev/null
+++ b/cass/etc/cadi.properties
@@ -0,0 +1,69 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+##
+## AUTHZ API (authz-service) Properties
+##
+
+## DISCOVERY (DME2) Parameters on the Command Line
+AFT_LATITUDE=38.627345
+AFT_LONGITUDE=-90.193774
+AFT_ENVIRONMENT=AFTUAT
+
+# CADI
+cadi_keyfile=/opt/app/aaf/common/com.att.aaf.keyfile
+cadi_loglevel=WARN
+
+# CASSANDRA Required for APP
+cass_group_name=com.att.aaf
+
+# CASSANDRA Optional
+cass_cluster_name=mithril
+
+# AAF Required for APP
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE
+DME2_EP_REGISTRY_CLASS=DME2FS
+AFT_DME2_EP_REGISTRY_FS_DIR=/Volumes/Data/src/authz/dme2reg
+
+aaf_default_realm=aaf.localized
+aaf_id=XX@NS
+aaf_password=enc:
+cadi_loglevel=DEBUG
+
+# AAF Optional
+# Connection Time Out (milliseconds)
+aaf_conn_timeout=10000
+# User Cache Expiration (milliseconds)
+aaf_user_expires=600000
+# High count... Rough top number of objects held in Cache per cycle. If high is reached, more are
+# recycled next time.
+aaf_high_count=1000
+
+##
+## Localized Passwords
+##
+basic_realm=aaf.localized
+local_users=root@aaf.localized%<PASS>:/dbname
diff --git a/cass/pom.xml b/cass/pom.xml
new file mode 100644
index 0000000..89582d6
--- /dev/null
+++ b/cass/pom.xml
@@ -0,0 +1,115 @@
+<!--
+ ============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">
+ <parent>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.3.2</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <name>CADI Cassandra Plugin</name>
+ <packaging>jar</packaging>
+ <url>https://github.com/att/AAF</url>
+ <description>CADI</description>
+ <artifactId>cadi-cass</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>cadi-aaf</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cassandra</groupId>
+ <artifactId>cassandra-all</artifactId>
+ <version>2.1.14</version>
+ <scope>compile</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jarsigner-plugin</artifactId>
+ </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>
+ </plugins>
+ </build>
+</project>
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
index 0000000..d720e28
--- /dev/null
+++ b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticatedUser.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cass;
+
+import java.security.Principal;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+
+import com.att.cadi.Access;
+
+public class AAFAuthenticatedUser extends AuthenticatedUser implements Principal {
+ private boolean anonymous = false, supr=false, local=false;
+ private String fullName;
+// private Access access;
+
+ public AAFAuthenticatedUser(Access access, String name) {
+ super(name);
+// this.access = access;
+ int endIndex = name.indexOf("@");
+ if(endIndex >= 0) {
+ fullName = name;
+ } else {
+ fullName = name + '@' + AAFBase.default_realm;
+ }
+ }
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ public String getName() {
+ return fullName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.cassandra.auth.AuthenticatedUser#isAnonymous()
+ */
+ @Override
+ public boolean isAnonymous() {
+ return anonymous;
+ }
+
+ public void setAnonymous(boolean anon) {
+ anonymous = anon;
+ }
+
+ public boolean getAnonymous() {
+ return anonymous;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.cassandra.auth.AuthenticatedUser#isSuper()
+ */
+ @Override
+ public boolean isSuper() {
+ return supr;
+ }
+
+ public void setSuper(boolean supr) {
+ this.supr = supr;
+ }
+
+ public boolean getSuper() {
+ return supr;
+ }
+
+ /**
+ * We check Local so we can compare with the right Lur. This is AAF Plugin only.
+ * @return
+ */
+ public boolean isLocal() {
+ return local;
+ }
+
+ public void setLocal(boolean val) {
+ local = val;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AAFAuthenticatedUser)) return false;
+ return ((AuthenticatedUser)o).getName().equals(this.getName());
+ }
+
+ @Override
+ public int hashCode() {
+ //access.log(Level.DEBUG, "AAFAuthentication hashcode ",getName().hashCode());
+ return getName().hashCode();
+ }
+}
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
index 0000000..8228899
--- /dev/null
+++ b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthenticator.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cass;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IAuthenticator;
+import org.apache.cassandra.auth.ISaslAwareAuthenticator;
+import org.apache.cassandra.exceptions.AuthenticationException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.RequestExecutionException;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.CredVal.Type;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+public class AAFAuthenticator extends AAFBase implements ISaslAwareAuthenticator {
+
+ public boolean requireAuthentication() {
+ return true;
+ }
+
+ /**
+ * Invoked to authenticate an user
+ */
+ public AuthenticatedUser authenticate(Map<String, String> credentials) throws AuthenticationException {
+ String username = (String)credentials.get("username");
+ if (username == null) {
+ throw new AuthenticationException("'username' is missing");
+ }
+
+ AAFAuthenticatedUser aau = new AAFAuthenticatedUser(access,username);
+ String fullName=aau.getFullName();
+ access.log(Level.DEBUG, "Authenticating", aau.getName(),"(", fullName,")");
+
+ String password = (String)credentials.get("password");
+ if (password == null) {
+ throw new AuthenticationException("'password' is missing");
+ } else if(password.startsWith("bsf:")) {
+ try {
+ password = Symm.base64noSplit.depass(password);
+ } catch (IOException e) {
+ throw new AuthenticationException("AAF bnf: Password cannot be decoded");
+ }
+ } else if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new AuthenticationException("AAF Encrypted Password cannot be decrypted");
+ }
+ }
+
+ if(localLur!=null) {
+ access.log(Level.DEBUG, "Validating",fullName, "with LocalTaf", password);
+ if(localLur.validate(fullName, Type.PASSWORD, password.getBytes())) {
+ aau.setAnonymous(true);
+ aau.setLocal(true);
+ access.log(Level.DEBUG, fullName, "is authenticated locally");
+ return aau;
+ }
+ }
+
+ String aafResponse;
+ try {
+ access.log(Level.DEBUG, "Validating",fullName, "with AAF");//, password);
+ aafResponse = aafAuthn.validate(fullName, password);
+ if(aafResponse != null) { // Reason for failing.
+ access.log(Level.AUDIT, "AAF reports ",fullName,":",aafResponse);
+ throw new AuthenticationException(aafResponse);
+ }
+ access.log(Level.AUDIT, fullName, "is authenticated"); //,password);
+ // This tells Cassandra to skip checking it's own tables for User Entries.
+ aau.setAnonymous(true);
+ } catch (AuthenticationException ex) {
+ throw ex;
+ } catch(Exception ex) {
+ access.log(ex,"Exception validating user");
+ throw new AuthenticationException("Exception validating user");
+ }
+
+ return aau;
+ }
+
+ public void create(String username, Map<IAuthenticator.Option, Object> options) throws InvalidRequestException, RequestExecutionException {
+ access.log(Level.INFO,"Use AAF CLI to create user");
+ }
+
+ public void alter(String username, Map<IAuthenticator.Option, Object> options) throws RequestExecutionException {
+ access.log(Level.INFO,"Use AAF CLI to alter user");
+ }
+
+ public void drop(String username) throws RequestExecutionException {
+ access.log(Level.INFO,"Use AAF CLI to delete user");
+ }
+
+ public SaslAuthenticator newAuthenticator() {
+ return new ISaslAwareAuthenticator.SaslAuthenticator() {
+ private boolean complete = false;
+ private Map<String, String> credentials;
+
+ public byte[] evaluateResponse(byte[] clientResponse) throws AuthenticationException {
+ this.credentials = decodeCredentials(clientResponse);
+ this.complete = true;
+ return null;
+ }
+
+ public boolean isComplete() {
+ return this.complete;
+ }
+
+ public AuthenticatedUser getAuthenticatedUser() throws AuthenticationException {
+ return AAFAuthenticator.this.authenticate(this.credentials);
+ }
+
+ private Map<String, String> decodeCredentials(byte[] bytes) throws AuthenticationException {
+ access.log(Level.DEBUG,"Decoding credentials from client token");
+ byte[] user = null;
+ byte[] pass = null;
+ int end = bytes.length;
+ for (int i = bytes.length - 1; i >= 0; i--)
+ {
+ if (bytes[i] != 0)
+ continue;
+ if (pass == null)
+ pass = Arrays.copyOfRange(bytes, i + 1, end);
+ else if (user == null)
+ user = Arrays.copyOfRange(bytes, i + 1, end);
+ end = i;
+ }
+
+ if (user == null)
+ throw new AuthenticationException("Authentication ID must not be null");
+ if (pass == null) {
+ throw new AuthenticationException("Password must not be null");
+ }
+ Map<String,String> credentials = new HashMap<String,String>();
+ try {
+ credentials.put(IAuthenticator.USERNAME_KEY, new String(user, Config.UTF_8));
+ credentials.put(IAuthenticator.PASSWORD_KEY, new String(pass, Config.UTF_8));
+ } catch (UnsupportedEncodingException e) {
+ throw new AuthenticationException(e.getMessage());
+ }
+ return credentials;
+ }
+ };
+ }
+
+}
+
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
index 0000000..a923e9b
--- /dev/null
+++ b/cass/src/main/java/com/att/cadi/aaf/cass/AAFAuthorizer.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cass;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IAuthorizer;
+import org.apache.cassandra.auth.IResource;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.auth.PermissionDetails;
+import org.apache.cassandra.exceptions.RequestExecutionException;
+import org.apache.cassandra.exceptions.RequestValidationException;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.aaf.v2_0.AbsAAFLur;
+import com.att.cadi.lur.LocalPermission;
+
+public class AAFAuthorizer extends AAFBase implements IAuthorizer {
+ // Returns every permission on the resource granted to the user.
+ public Set<Permission> authorize(AuthenticatedUser user, IResource resource) {
+ String uname, rname;
+ access.log(Level.DEBUG,"Authorizing",uname=user.getName(),"for",rname=resource.getName());
+
+ Set<Permission> permissions;
+
+ if(user instanceof AAFAuthenticatedUser) {
+ AAFAuthenticatedUser aafUser = (AAFAuthenticatedUser) user;
+ aafUser.setAnonymous(false);
+
+ if(aafUser.isLocal()) {
+ permissions = checkPermissions(aafUser, new LocalPermission(
+ rname.replaceFirst("data", cluster_name)
+ ));
+ } else {
+ permissions = checkPermissions(
+ aafUser,
+ perm_type,
+ ':'+rname.replaceFirst("data", cluster_name).replace('/', ':'));
+ }
+ } else {
+ permissions = Permission.NONE;
+ }
+
+ access.log(Level.INFO,"Permissions on",rname,"for",uname,':', permissions);
+
+ return permissions;
+ }
+
+ /**
+ * Check only for Localized IDs (see cadi.properties)
+ * @param aau
+ * @param perm
+ * @return
+ */
+ private Set<Permission> checkPermissions(AAFAuthenticatedUser aau, LocalPermission perm) {
+ if(localLur.fish(aau.getFullName(), perm)) {
+// aau.setSuper(true);
+ return Permission.ALL;
+ } else {
+ return Permission.NONE;
+ }
+ }
+
+ /**
+ * Check remoted AAF Permissions
+ * @param aau
+ * @param type
+ * @param instance
+ * @return
+ */
+ private Set<Permission> checkPermissions(AAFAuthenticatedUser aau, String type, String instance) {
+ // Can perform ALL actions
+ String fullName = aau.getFullName();
+ PermHolder ph = new PermHolder(aau);
+ aafLur.fishOneOf(fullName, ph,type,instance,actions);
+ return ph.permissions;
+ }
+
+ private class PermHolder {
+ private AAFAuthenticatedUser aau;
+ public PermHolder(AAFAuthenticatedUser aau) {
+ this.aau = aau;
+ }
+ public Set<Permission> permissions = Permission.NONE;
+ public void mutable() {
+ if(permissions==Permission.NONE) {
+ permissions = new HashSet<Permission>();
+ }
+ }
+ };
+
+ /**
+ * This specialty List avoid extra Object Creation, and allows the Lur to do a Vistor on all appropriate Perms
+ */
+ private static final ArrayList<AbsAAFLur.Action<PermHolder>> actions = new ArrayList<AbsAAFLur.Action<PermHolder>>();
+ static {
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "*";
+ }
+
+ public boolean exec(PermHolder a) {
+ a.aau.setSuper(true);
+ a.permissions = Permission.ALL;
+ return true;
+ }
+ });
+
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "SELECT";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.SELECT);
+ return false;
+ }
+ });
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "MODIFY";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.MODIFY);
+ return false;
+ }
+ });
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "CREATE";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.CREATE);
+ return false;
+ }
+ });
+
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "ALTER";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.ALTER);
+ return false;
+ }
+ });
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "DROP";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.DROP);
+ return false;
+ }
+ });
+ actions.add(new AbsAAFLur.Action<PermHolder>() {
+ public String getName() {
+ return "AUTHORIZE";
+ }
+
+ public boolean exec(PermHolder ph) {
+ ph.mutable();
+ ph.permissions.add(Permission.AUTHORIZE);
+ return false;
+ }
+ });
+
+
+ };
+
+
+ public void grant(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String to) throws RequestExecutionException {
+ access.log(Level.INFO, "Use AAF CLI to grant permission(s) to user/role");
+ }
+
+ public void revoke(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String from) throws RequestExecutionException {
+ access.log(Level.INFO,"Use AAF CLI to revoke permission(s) for user/role");
+ }
+
+ public Set<PermissionDetails> list(AuthenticatedUser performer, Set<Permission> permissions, IResource resource, String of) throws RequestValidationException, RequestExecutionException {
+ access.log(Level.INFO,"Use AAF CLI to find the list of permissions");
+ return null;
+ }
+
+ // Called prior to deleting the user with DROP USER query. Internal hook, so no permission checks are needed here.
+ public void revokeAll(String droppedUser) {
+ access.log(Level.INFO,"Use AAF CLI to revoke permission(s) for user/role");
+ }
+
+ // Called after a resource is removed (DROP KEYSPACE, DROP TABLE, etc.).
+ public void revokeAll(IResource droppedResource) {
+ access.log(Level.INFO,"Use AAF CLI to delete the unused permission", droppedResource.getName());
+ }
+
+}
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
index 0000000..32690f4
--- /dev/null
+++ b/cass/src/main/java/com/att/cadi/aaf/cass/AAFBase.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cass;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.cassandra.auth.DataResource;
+import org.apache.cassandra.auth.IAuthenticator;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.exceptions.ConfigurationException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Lur;
+import com.att.cadi.SLF4JAccess;
+import com.att.cadi.aaf.v2_0.AAFAuthn;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AbsAAFLur;
+import com.att.cadi.config.Config;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.lur.LocalLur;
+import com.att.cadi.aaf.AAFPermission;
+
+public abstract class AAFBase {
+ protected static final Set<IAuthenticator.Option> options;
+ protected static final Set<DataResource> dataResource;
+
+ static {
+ options = new HashSet<IAuthenticator.Option>();
+ options.add(IAuthenticator.Option.PASSWORD);
+
+ dataResource = new HashSet<DataResource>();
+ dataResource.add(DataResource.columnFamily("system_auth", "credentials"));
+ }
+
+ protected static Access access;
+ protected static LocalLur localLur;
+ protected static AAFCon<?> aafcon;
+ protected static AAFAuthn<?> aafAuthn;
+ protected static AbsAAFLur<AAFPermission> aafLur;
+ protected static String default_realm;
+ protected static String cluster_name;
+ protected static String perm_type;
+ private static boolean props_ok = false;
+
+ /**
+ * If you use your own Access Class, this must be called before
+ * "setup()" is invoked by Cassandra.
+ *
+ * Otherwise, it will default to reading Properties CADI style.
+ *
+ * @param access
+ */
+ public static void setAccess(Access access) {
+ AAFBase.access = access;
+ }
+
+
+ public void validateConfiguration() throws ConfigurationException {
+ setup();
+ if(!props_ok) {
+ throw new ConfigurationException("AAF not initialized");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public synchronized void setup() {
+ if(aafAuthn == null) {
+ try {
+ if(access==null) {
+ String value = System.getProperty(Config.CADI_PROP_FILES, "cadi.properties");
+ Properties initial = new Properties();
+ URL cadi_props = ClassLoader.getSystemResource(value);
+ if(cadi_props == null) {
+ File cp = new File(value);
+ if(cp.exists()) {
+ InputStream is = new FileInputStream(cp);
+ try {
+ initial.load(is);
+ } finally {
+ is.close();
+ }
+ } else {
+ System.out.printf("%s does not exist as File or in Classpath\n",value);
+ initial.setProperty(Config.CADI_PROP_FILES, value);
+ }
+ } else {
+ InputStream is = cadi_props.openStream();
+ try {
+ initial.load(is);
+ } finally {
+ is.close();
+ }
+ }
+ access = new SLF4JAccess(initial);
+ }
+ props_ok = true;
+ if((perm_type = Config.logProp(access, "cass_group_name",null))==null) {
+ props_ok=false;
+ } else {
+ perm_type = perm_type + ".cass";
+ }
+
+ if((cluster_name = Config.logProp(access,"cass_cluster_name",null))==null) {
+ if((cluster_name = DatabaseDescriptor.getClusterName())==null) {
+ props_ok=false;
+ }
+ }
+
+ if((default_realm = Config.logProp(access, Config.AAF_DEFAULT_REALM, null))==null) {
+ props_ok=false;
+ }
+
+ if(props_ok==false) {
+ return;
+ }
+
+ // AAFLur has pool of DME clients as needed, and Caches Client lookups
+ Lur lur = Config.configLur(access);
+ // Loop through to find AAFLur out of possible Lurs, to reuse AAFCon
+ if(lur instanceof EpiLur) {
+ EpiLur elur = (EpiLur)lur;
+ for(int i=0; (lur = elur.get(i))!=null;++i) {
+ if(lur instanceof AbsAAFLur) {
+ aafLur=(AbsAAFLur<AAFPermission>)lur;
+ aafcon = aafLur.aaf;
+ aafAuthn = aafLur.aaf.newAuthn(aafLur);
+ break;
+ } else if(lur instanceof LocalLur) {
+ localLur = (LocalLur)lur;
+ }
+ }
+ } else if(lur instanceof AbsAAFLur) {
+ aafLur=(AbsAAFLur<AAFPermission>)lur;
+ aafcon = aafLur.aaf;
+ aafAuthn = aafLur.aaf.newAuthn(aafLur);
+ }
+ if(aafAuthn==null) {
+ access.log(Level.INIT,"Failed to instantiate full AAF access");
+ props_ok = false;
+ }
+ } catch (Exception e) {
+ aafAuthn=null;
+ if(access!=null)access.log(e, "Failed to initialize AAF");
+ props_ok = false;
+ }
+ }
+ }
+
+ public Set<DataResource> protectedResources() {
+ access.log(Level.DEBUG, "Data Resource asked for: it's",dataResource.isEmpty()?"":"not","empty");
+ return dataResource;
+ }
+
+ public Set<IAuthenticator.Option> supportedOptions() {
+ access.log(Level.DEBUG, "supportedOptions() called");
+ return options;
+ }
+
+ public Set<IAuthenticator.Option> alterableOptions() {
+ access.log(Level.DEBUG, "alterableOptions() called");
+ return options;
+ }
+
+
+}
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
index 0000000..f25a6b5
--- /dev/null
+++ b/cass/src/test/java/com/att/aaf/cass/JU_CASS.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.aaf.cass;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IResource;
+import org.apache.cassandra.auth.Permission;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.att.cadi.aaf.cass.AAFAuthenticator;
+import com.att.cadi.aaf.cass.AAFAuthorizer;
+
+public class JU_CASS {
+
+ private static AAFAuthenticator aa;
+ private static AAFAuthorizer an;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ System.setProperty("cadi_prop_files", "etc/cadi.properties");
+
+ aa = new AAFAuthenticator();
+ an = new AAFAuthorizer();
+
+ aa.setup();
+ an.setup(); // does nothing after aa.
+
+ aa.validateConfiguration();
+
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() throws Exception {
+ Map<String,String> creds = new HashMap<String,String>();
+ creds.put("username", "XXX@NS");
+ creds.put("password", "enc:???");
+ AuthenticatedUser aaf = aa.authenticate(creds);
+
+ // Test out "aaf_default_domain
+ creds.put("username", "XX");
+ aaf = aa.authenticate(creds);
+
+ IResource resource = new IResource() {
+ public String getName() {
+ return "data/authz";
+ }
+
+ public IResource getParent() {
+ return null;
+ }
+
+ public boolean hasParent() {
+ return false;
+ }
+
+ public boolean exists() {
+ return true;
+ }
+
+ };
+
+ Set<Permission> perms = an.authorize(aaf, resource);
+
+ // Test out "AAF" access
+ creds.put("username", "XXX@NS");
+ creds.put("password", "enc:???");
+ aaf = aa.authenticate(creds);
+ perms = an.authorize(aaf, resource);
+ Assert.assertFalse(perms.isEmpty());
+
+ perms = an.authorize(aaf, resource);
+ Assert.assertFalse(perms.isEmpty());
+
+ }
+
+}
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
index 0000000..9bfc17e
--- /dev/null
+++ b/cass/src/test/java/com/att/cadi/aaf/cass/test/JU_CASS.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.aaf.cass.test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IResource;
+import org.apache.cassandra.auth.Permission;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.att.cadi.aaf.cass.AAFAuthenticator;
+import com.att.cadi.aaf.cass.AAFAuthorizer;
+
+public class JU_CASS {
+
+ private static AAFAuthenticator aa;
+ private static AAFAuthorizer an;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ System.setProperty("cadi_prop_files", "etc/cadi.properties");
+
+ aa = new AAFAuthenticator();
+ an = new AAFAuthorizer();
+
+ aa.setup();
+ an.setup(); // does nothing after aa.
+
+ aa.validateConfiguration();
+
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() throws Exception {
+ Map<String,String> creds = new HashMap<String,String>();
+ creds.put("username", "XXX@NS");
+ creds.put("password", "enc:???");
+ AuthenticatedUser aaf = aa.authenticate(creds);
+
+ // Test out "aaf_default_domain
+ creds.put("username", "XX");
+ aaf = aa.authenticate(creds);
+
+ IResource resource = new IResource() {
+ public String getName() {
+ return "data/authz";
+ }
+
+ public IResource getParent() {
+ return null;
+ }
+
+ public boolean hasParent() {
+ return false;
+ }
+
+ public boolean exists() {
+ return true;
+ }
+
+ };
+
+ Set<Permission> perms = an.authorize(aaf, resource);
+
+ // Test out "AAF" access
+ creds.put("username", "XXX@NS");
+ creds.put("password", "enc:???");
+ aaf = aa.authenticate(creds);
+ perms = an.authorize(aaf, resource);
+ Assert.assertFalse(perms.isEmpty());
+
+ perms = an.authorize(aaf, resource);
+ Assert.assertFalse(perms.isEmpty());
+
+ }
+
+}
diff --git a/client/.gitignore b/client/.gitignore
new file mode 100644
index 0000000..cf85207
--- /dev/null
+++ b/client/.gitignore
@@ -0,0 +1,5 @@
+/bin/
+/target/
+/.classpath
+/.project
+.settings
diff --git a/client/pom.xml b/client/pom.xml
new file mode 100644
index 0000000..562a92a
--- /dev/null
+++ b/client/pom.xml
@@ -0,0 +1,108 @@
+<!--
+ ============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">
+<parent>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.3.2</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <name>CADI Client</name>
+ <artifactId>cadi-client</artifactId>
+ <packaging>jar</packaging>
+ <url>https://github.com/att/AAF</url>
+ <description>CADI</description>
+ <modelVersion>4.0.0</modelVersion>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.att.inno</groupId>
+ <artifactId>rosetta</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>cadi-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.att.aft</groupId>
+ <artifactId>dme2</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jarsigner-plugin</artifactId>
+ </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>
+ </plugins>
+ </build>
+
+</project>
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
index 0000000..843f3b1
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AAFClient.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Access;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.locator.DME2Locator;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class AAFClient {
+ private RosettaEnv env;
+ private Map<Class<?>,RosettaDF<?>> map = new HashMap<Class<?>,RosettaDF<?>>();
+ HMangr hman;
+ HBasicAuthSS ss;
+
+ public AAFClient(RosettaEnv env) throws Exception {
+ this.env = env;
+ Access access = new EnvAccess(env);
+ String user = access.getProperty(Config.AAF_MECHID,null);
+ String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);
+
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ DME2Manager dm = new DME2Manager("APIclient DME2Manager", System.getProperties());
+ DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));
+
+ int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));
+
+ hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");
+ ss = new HBasicAuthSS(user, password, si);
+ }
+
+ public AAFClient(RosettaEnv env, DME2Manager dm) throws Exception {
+ this.env = env;
+ Access access = new EnvAccess(env);
+ String user = access.getProperty(Config.AAF_MECHID,null);
+ String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);
+
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));
+
+ int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));
+
+ hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");
+ ss = new HBasicAuthSS(user, password, si);
+ }
+
+ @SuppressWarnings("unchecked")
+ private synchronized<T> RosettaDF<T> getDF(Class<T> cls) throws APIException {
+ RosettaDF<?> rdf;
+ synchronized (env) {
+ rdf = map.get(cls);
+ if(rdf==null) {
+ rdf = env.newDataFactory(cls);
+ map.put(cls, rdf);
+ }
+ }
+ return (RosettaDF<T>)rdf;
+ }
+
+ // Package on purpose
+ static class Call<T> {
+ protected final static String VOID_CONTENT_TYPE="application/Void+json;version=2.0";
+
+ protected RosettaDF<T> df;
+ protected AAFClient client;
+
+ public Call(AAFClient ac, RosettaDF<T> df) {
+ this.client = ac;
+ this.df = df;
+ }
+ }
+
+
+ /////////// Calls /////////////////
+ /**
+ * Returns a Get Object... same as "get"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Get<T> read(Class<T> cls) throws APIException {
+ return new Get<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Get Object... same as "read"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Get<T> get(Class<T> cls) throws APIException {
+ return new Get<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Post Object... same as "create"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Post<T> post(Class<T> cls) throws APIException {
+ return new Post<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Post Object... same as "post"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Post<T> create(Class<T> cls) throws APIException {
+ return new Post<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Put Object... same as "update"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Put<T> put(Class<T> cls) throws APIException {
+ return new Put<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Put Object... same as "put"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Put<T> update(Class<T> cls) throws APIException {
+ return new Put<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Delete Object
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Delete<T> delete(Class<T> cls) throws APIException {
+ return new Delete<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Delete Object
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public Delete<Void> delete() throws APIException {
+ return new Delete<Void>(this,null);
+ }
+
+ public Put<Void> put() {
+ return new Put<Void>(this,null);
+ }
+
+
+}
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
index 0000000..ef8abf4
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Symm;
+import com.att.cadi.config.SecurityInfoC;
+
+public abstract class AbsBasicAuth<CLIENT> implements SecuritySetter<CLIENT> {
+ protected static final String REPEAT_OFFENDER="This call is aborted because of repeated usage of invalid Passwords";
+ private static final int MAX_TEMP_COUNT = 10;
+ private static final int MAX_SPAM_COUNT = 10000;
+ private static final long WAIT_TIME = 1000*60*4;
+
+ protected final String headValue;
+ protected SecurityInfoC<CLIENT> securityInfo;
+ protected String user;
+ private long lastMiss;
+ private int count;
+
+ public AbsBasicAuth(String user, String pass, SecurityInfoC<CLIENT> si) throws IOException {
+ this.user = user;
+ headValue = "Basic " + Symm.base64.encode(user + ':' + pass);
+ securityInfo = si;
+ lastMiss=0L;
+ count=0;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return user;
+ }
+
+ public boolean isDenied() {
+ if(lastMiss>0 && lastMiss>System.currentTimeMillis()) {
+ return true;
+ } else {
+ lastMiss=0L;
+ return false;
+ }
+ }
+
+ public synchronized int setLastResponse(int httpcode) {
+ if(httpcode == 401) {
+ ++count;
+ if(lastMiss==0L && count>MAX_TEMP_COUNT) {
+ lastMiss=System.currentTimeMillis()+WAIT_TIME;
+ }
+// if(count>MAX_SPAM_COUNT) {
+// System.err.printf("Your service has %d consecutive bad service logins to AAF. \nIt will now exit\n",
+// count);
+// System.exit(401);
+// }
+ if(count%1000==0) {
+ System.err.printf("Your service has %d consecutive bad service logins to AAF. AAF Access will be disabled after %d\n",
+ count,MAX_SPAM_COUNT);
+ }
+
+ } else {
+ lastMiss=0;
+ }
+ return count;
+ }
+
+ public int count() {
+ return count;
+ }
+}
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
index 0000000..3056187
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AbsTransferSS.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.security.Principal;
+
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.TGuardPrincipal;
+import com.att.cadi.principal.TrustPrincipal;
+
+public abstract class AbsTransferSS<CLIENT> implements SecuritySetter<CLIENT> {
+ protected String value;
+ protected SecurityInfoC<CLIENT> securityInfo;
+ protected SecuritySetter<CLIENT> defSS;
+ private Principal principal;
+
+ //Format:<ID>:<APP>:<protocol>[:AS][,<ID>:<APP>:<protocol>]*
+ public AbsTransferSS(Principal principal, String app) {
+ init(principal, app);
+ }
+
+ public AbsTransferSS(Principal principal, String app, SecurityInfoC<CLIENT> si) {
+ init(principal,app);
+ securityInfo = si;
+ this.defSS = si.defSS;
+ }
+
+ private void init(Principal principal, String app) {
+ this.principal=principal;
+ if(principal==null) {
+ return;
+ } else if(principal instanceof BasicPrincipal) {
+ value = principal.getName() + ':' + app + ":BasicAuth:AS";
+ } else if(principal instanceof TrustPrincipal) {
+ TrustPrincipal tp = (TrustPrincipal)principal;
+ // recursive
+ init(tp.original(),app);
+ value += principal.getName() + ':' + app + ":Trust:AS" + ',' + tp.userChain();
+ } else if(principal instanceof TGuardPrincipal) {
+ value = principal.getName() + ':' + app + ":TGUARD:AS";
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return principal==null?"":principal.getName();
+ }
+}
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
index 0000000..9367d4d
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Delete.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Delete<T> extends AAFClient.Call<T> {
+ public Delete(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Result<T> delete(final String pathInfo, final T t) throws Exception {
+ if(t==null) {
+ return (Result<T>)delete(pathInfo);
+ }
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.delete(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+ public Result<Void> delete(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<Void>>() {
+ @Override
+ public Result<Void> code(Rcli<?> client) throws APIException, CadiException {
+ Future<Void> ft = client.delete(pathInfo,VOID_CONTENT_TYPE);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+
+
+}
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
index 0000000..f508029
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/EClient.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.rosetta.env.RosettaDF;
+
+
+public interface EClient<CT> {
+ public void setMethod(String meth);
+ public void setPathInfo(String pathinfo);
+ public void setPayload(Transfer transfer);
+ public void addHeader(String tag, String value);
+ public void setQueryParams(String q);
+ public void setFragment(String f);
+ public void send() throws APIException;
+ public<T> Future<T> futureCreate(Class<T> t);
+ public Future<String> futureReadString();
+ public<T> Future<T> futureRead(RosettaDF<T> df,Data.TYPE type);
+ public<T> Future<T> future(T t);
+ public Future<Void> future(HttpServletResponse resp, int expected) throws APIException;
+
+ public interface Transfer {
+ public void transfer(OutputStream os) throws IOException, APIException;
+ }
+}
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
index 0000000..f331c9a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/EnvAccess.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.inno.env.Decryptor;
+import com.att.inno.env.Env;
+import com.att.inno.env.impl.BasicEnv;
+
+public class EnvAccess implements Access {
+ private Env env;
+
+ /**
+ * String Property tag for files/resources that may contain properties. Can be null.
+ * Resources of ClassLoader will be checked first, if exist. Can be null.
+ * @param env
+ * @param tag
+ * @param cl
+ * @throws IOException
+ */
+ public EnvAccess(BasicEnv env, ClassLoader cl) throws IOException {
+ this.env = env;
+ final Symm s = Symm.obtain(this);
+ env.set(new Decryptor() {
+ private Symm symm = s;
+ @Override
+ public String decrypt(String encrypted) {
+ try {
+ return (encrypted!=null && (encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ } catch (IOException e) {
+ return "";
+ }
+ }
+ }
+ );
+ }
+
+
+ /**
+ * Construct with the Classloader of Env and CADI_PROP_FILES, if possible
+ *
+ * @param env
+ * @throws IOException
+ */
+ public EnvAccess(BasicEnv env) throws IOException {
+ this(env, env.getClass().getClassLoader());
+ }
+
+ @Override
+ public void log(Level level, Object... elements) {
+ switch(level) {
+ case AUDIT:
+ env.audit().log(elements);
+ break;
+ case DEBUG:
+ env.debug().log(elements);
+ break;
+ case ERROR:
+ env.error().log(elements);
+ break;
+ case INFO:
+ env.info().log(elements);
+ break;
+ case INIT:
+ env.init().log(elements);
+ break;
+ case WARN:
+ env.warn().log(elements);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ @Override
+ public void log(Exception e, Object... elements) {
+ env.error().log(e,elements);
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ if(willLog(level)) {
+ log(level,String.format(fmt, elements));
+ }
+ }
+
+
+ @Override
+ public boolean willLog(Level level) {
+ switch(level) {
+ case AUDIT:
+ return env.audit().isLoggable();
+ case DEBUG:
+ return env.debug().isLoggable();
+ case ERROR:
+ return env.error().isLoggable();
+ case INFO:
+ return env.info().isLoggable();
+ case INIT:
+ return env.init().isLoggable();
+ case WARN:
+ return env.warn().isLoggable();
+ default:
+ return false;
+ }
+ }
+
+
+ @Override
+ public void setLogLevel(Level level) {
+ // unused
+ }
+
+ @Override
+ public ClassLoader classLoader() {
+ return env.getClass().getClassLoader();
+ }
+
+ @Override
+ public String getProperty(String string, String def) {
+ return env.getProperty(string, def);
+ }
+
+ @Override
+ public void load(InputStream is) throws IOException {
+ Properties props = new Properties();
+ props.load(is);
+ for(Entry<Object, Object> es :props.entrySet()) {
+ env.setProperty(es.getKey().toString(), es.getValue().toString());
+ }
+ }
+
+ @Override
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return env.decryptor().decrypt(encrypted);
+ }
+
+}
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
index 0000000..1752907
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Future.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+
+public abstract class Future<T> {
+ public T value;
+ public abstract boolean get(int timeout) throws CadiException;
+
+ public abstract int code();
+ public abstract String body();
+ public abstract String header(String tag);
+}
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
index 0000000..d05654d
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Get.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Get<T> extends AAFClient.Call<T> {
+ public Get(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> read(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.read(pathInfo,df);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+}
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
index 0000000..93067f9
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Holder.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+/**
+ * Use to set Variables outside of Anonymous classes.
+ *
+ *
+ * @param <T>
+ */
+public class Holder<T> {
+ private T value;
+ public Holder(T t) {
+ value = t;
+ }
+ public void set(T t) {
+ value = t;
+ }
+
+ public T get() {
+ return value;
+ }
+
+}
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
index 0000000..7cc1b8c
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Post.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Post<T> extends AAFClient.Call<T> {
+ public Post(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> create(final String pathInfo, final T t) throws APIException, CadiException, LocatorException {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.create(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+}
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
index 0000000..37bc7b6
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/PropertyLocator.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Random;
+
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class PropertyLocator implements Locator {
+ private final URI [] orig;
+ private PLItem[] current;
+ private int end;
+ private final Random random;
+
+ /**
+ * comma delimited root url list
+ *
+ * @param locList
+ * @throws LocatorException
+ */
+ public PropertyLocator(String locList) throws LocatorException {
+ if(locList==null)throw new LocatorException("No Location List given for PropertyLocator");
+ String[] locarray = locList.split("\\s*,\\s*");
+ orig = new URI[locarray.length];
+
+ random = new Random();
+
+ for(int i=0;i<locarray.length;++i) {
+ try {
+ orig[i] = new URI(locarray[i]);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+
+ current = new PLItem[orig.length];
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return orig[((PLItem)item).idx];
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return end>0?current[0]:null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return end>0;
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ int spot;
+ if((spot=(((PLItem)item).order+1))>=end)return null;
+ return current[spot];
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ if(--end<=0)return;
+ PLItem pli = (PLItem)item;
+ int i,order;
+ for(i=0;i<end;++i) {
+ if(pli==current[i])break;
+ }
+ order = current[i].order;
+ for(;i<end;++i) {
+ current[i]=current[i+1];
+ current[i].order=order++;
+ }
+ current[end]=pli;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ switch(current.length) {
+ case 0:
+ return null;
+ case 1:
+ return current[0];
+ default:
+ return current[Math.abs(random.nextInt())%end];
+ }
+ }
+
+ @Override
+ public synchronized boolean refresh() {
+ end = orig.length;
+
+ // Build up list
+ for(int i = 0; i < end ; ++i) {
+ if(current[i]==null)current[i]=new PLItem(i);
+ else current[i].idx=current[i].order=i;
+ }
+ return true;
+ }
+
+ private class PLItem implements Item {
+ public int idx,order;
+
+ public PLItem(int i) {
+ idx = order =i;
+ }
+
+ public String toString() {
+ return "Item: " + idx + " order: " + order;
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..033216b
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Put.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Put<T> extends AAFClient.Call<T> {
+ public Put(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> update(final String pathInfo, final T t) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.update(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+ public Result<Void> update(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<Void>>() {
+ @Override
+ public Result<Void> code(Rcli<?> client) throws APIException, CadiException {
+ Future<Void> ft = client.update(pathInfo);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+}
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
index 0000000..d1a1fc2
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/RawClient.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.net.URI;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+public abstract class RawClient {
+ protected static String aafid, aafpass, aafurl;
+ protected static Symm symm;
+
+ protected static boolean init(PrintStream out) {
+ try {
+ String propfile = System.getProperty(Config.CADI_PROP_FILES);
+ if(propfile==null) {
+ propfile = "raw.props";
+ }
+ File pfile = new File(propfile);
+ if(!pfile.exists()) {
+ if(propfile.equals("raw.props")) {
+ out.println("Creating 'raw.props'. Edit for proper values, then run again. Alternatively, set "
+ + Config.CADI_PROP_FILES+" to a cadi properties file");
+ FileOutputStream fos = new FileOutputStream(pfile);
+ PrintStream ps = new PrintStream(fos);
+ try {
+ ps.println("# Use http://www.bing.com/maps to figure out LAT/LONG of an Address");
+ ps.println("AFT_LATITUDE=38.432930");
+ ps.println("AFT_LONGITUDE=-90.432480");
+ ps.println("AFT_ENVIRONMENT=AFTUAT");
+ ps.print(Config.AAF_URL);
+ ps.println("=aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");
+ ps.print(Config.CADI_KEYFILE);
+ ps.println("=<keyfile. use java -jar cadi-core*.jar in lib dir>");
+ ps.println(Config.AAF_MECHID);
+ ps.print("=<your id>");
+ ps.println(Config.AAF_MECHPASS);
+ ps.print("=<your encrypted password. use java -jar cadi-core*.jar in lib dir>");
+ } finally {
+ ps.close();
+ }
+ }
+ } else {
+ FileInputStream fis = new FileInputStream(propfile);
+ try {
+ System.getProperties().load(fis);
+ } finally {
+ fis.close();
+ }
+
+ String cadiKeyFile = System.getProperty(Config.CADI_KEYFILE);
+ aafid = System.getProperty(Config.AAF_MECHID);
+ aafpass = System.getProperty(Config.AAF_MECHPASS);
+ aafurl = System.getProperty(Config.AAF_URL);
+ out.println("Contacting: " + aafurl);
+
+ if(cadiKeyFile==null || aafid==null || aafpass==null || aafurl==null ) {
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(" need to be set in ");
+ out.println(propfile);
+ } else {
+ fis = new FileInputStream(cadiKeyFile);
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ fis.close();
+ }
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ }
+ return false;
+
+ }
+
+ public abstract String call(final PrintStream out, final String meth, final String path) throws Exception;
+
+ public static void main(String[] args) {
+ // Sonar idiocy
+ PrintStream out = System.out;
+
+ try {
+ if(init(out)) {
+ if(args.length<2) {
+ System.out.println("Parameters: <Method> <path>");
+ } else {
+ RawClient client = new DME2();
+ out.println(client.call(out,args[0],args[1]));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ }
+ }
+
+ protected static class DME2 extends RawClient {
+
+ public String call(final PrintStream out, final String meth, final String path) {
+ try {
+ DME2Client client = new DME2Client(new URI(aafurl),10000);
+ client.setCredentials(aafid, symm.depass(aafpass));
+ client.setMethod(meth);
+ client.setContext(path);
+
+ if("GET".equalsIgnoreCase(meth) ||
+ "DELETE".equalsIgnoreCase(meth)) {
+ client.setPayload("");
+ } else if("POST".equalsIgnoreCase(meth) ||
+ "PUT".equalsIgnoreCase(meth)) {
+ int c;
+ StringBuilder sb = new StringBuilder();
+ while((c=System.in.read()) >=0) {
+ sb.append((char)c);
+ }
+ client.setPayload(sb.toString());
+ }
+ return client.sendAndWait(10000);
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ return "";
+ }
+ }
+ }
+}
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
index 0000000..f14645e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Rcli.java
@@ -0,0 +1,697 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Enumeration;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Pool;
+import com.att.inno.env.util.Pool.Pooled;
+import com.att.rosetta.env.RosettaDF;
+
+public abstract class Rcli<CT> {
+ public static final String BLANK = "";
+ public static final String CONTENT_TYPE = "Content-Type";
+ public static final String ACCEPT = "Accept";
+
+ protected static final String POST = "POST";
+ protected static final String GET = "GET";
+ protected static final String PUT = "PUT";
+ protected static final String DELETE = "DELETE";
+ protected TYPE type;
+ protected String apiVersion;
+ protected int readTimeout = 5000;
+ protected int connectionTimeout = 3000;
+ protected URI uri;
+ private String queryParams, fragment;
+ public static Pool<byte[]> buffPool = new Pool<byte[]>(new Pool.Creator<byte[]>() {
+ @Override
+ public byte[] create() throws APIException {
+ return new byte[1024];
+ }
+
+ @Override
+ public void destroy(byte[] t) {
+ }
+
+ @Override
+ public boolean isValid(byte[] t) {
+ return true;
+ }
+
+ @Override
+ public void reuse(byte[] t) {
+ }
+ });
+
+
+ public Rcli() {
+ super();
+ }
+
+ public abstract void setSecuritySetter(SecuritySetter<CT> ss);
+ public abstract SecuritySetter<CT> getSecuritySetter();
+
+
+ public Rcli<CT> forUser(SecuritySetter<CT> ss) {
+ Rcli<CT> rv = clone(uri==null?this.uri:uri,ss);
+ setSecuritySetter(ss);
+ rv.type = type;
+ rv.apiVersion = apiVersion;
+ return rv;
+ }
+
+ protected abstract Rcli<CT> clone(URI uri, SecuritySetter<CT> ss);
+
+ public abstract void invalidate() throws CadiException;
+
+ public Rcli<CT> readTimeout(int millis) {
+ readTimeout = millis;
+ return this;
+ }
+
+ public Rcli<CT> connectionTimeout(int millis) {
+ connectionTimeout = millis;
+ return this;
+ }
+
+ public Rcli<CT> type(TYPE type) {
+ this.type=type;
+ return this;
+ }
+
+ public Rcli<CT> apiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ return this;
+ }
+
+ public boolean isApiVersion(String prospective) {
+ return apiVersion.equals(prospective);
+ }
+
+
+ public String typeString(Class<?> cls) {
+ return "application/"+cls.getSimpleName()+"+"+type.name().toLowerCase()+
+ (apiVersion==null?BLANK:";version="+apiVersion);
+ }
+
+ protected abstract EClient<CT> client() throws CadiException;
+
+
+ public<T> Future<T> create(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(cls));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(cls));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(cls);
+ }
+
+ public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(Void.class);
+ }
+
+
+ public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, accept);
+
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureReadString();
+ }
+
+ public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, accept);
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, typeString(df.getTypeClass()));
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureReadString();
+ }
+
+
+ public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ /**
+ * A method to update with a VOID
+ * @param pathinfo
+ * @param resp
+ * @param expected
+ * @return
+ * @throws APIException
+ * @throws CadiException
+ */
+ public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(Void.class));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+// client.setPayload(new EClient.Transfer() {
+// @Override
+// public void transfer(OutputStream os) throws IOException, APIException {
+// }
+// });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(null);
+ }
+
+ public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+
+ public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.future((T)null);
+ }
+
+ public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.future(null);
+ }
+
+ public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
+ EClient<CT> client = client();
+ URI uri;
+ try {
+ uri = new URI(req.getRequestURI());
+ } catch (Exception e) {
+ throw new CadiException("Invalid incoming URI",e);
+ }
+ String name;
+ for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
+ name = en.nextElement();
+ client.addHeader(name,req.getHeader(name));
+ }
+ client.setQueryParams(req.getQueryString());
+ client.setFragment(uri.getFragment());
+ client.setPathInfo(pathParam);
+ String meth = req.getMethod();
+ client.setMethod(meth);
+ if(!"GET".equals(meth)) {
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ final ServletInputStream is = req.getInputStream();
+ int read;
+ // reuse Buffers
+ Pooled<byte[]> pbuff = buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ }
+ });
+ }
+ client.send();
+ return client.future(resp, expected);
+ }
+
+ public String toString() {
+ return uri.toString();
+ }
+
+ /**
+ * @param queryParams the queryParams to set
+ * @return
+ */
+ public Rcli<CT> setQueryParams(String queryParams) {
+ this.queryParams = queryParams;
+ return this;
+ }
+
+
+ /**
+ * @param fragment the fragment to set
+ * @return
+ */
+ public Rcli<CT> setFragment(String fragment) {
+ this.fragment = fragment;
+ return this;
+ }
+
+ public URI getURI() {
+ return uri;
+ }
+
+}
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
index 0000000..1e4909e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Result.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+public class Result<T> {
+ public final int code;
+ public final T value;
+ public final String error;
+
+ private Result(int code, T value, String error) {
+ this.code = code;
+ this.value = value;
+ this.error = error;
+ }
+
+ public static<T> Result<T> ok(int code,T t) {
+ return new Result<T>(code,t,null);
+ }
+
+ public static<T> Result<T> err(int code,String body) {
+ return new Result<T>(code,null,body);
+ }
+
+ public boolean isOK() {
+ return error==null;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Code: ");
+ sb.append(code);
+ if(error!=null) {
+ sb.append(" = ");
+ sb.append(error);
+ }
+ return sb.toString();
+ }
+}
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
index 0000000..e276837
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Retryable.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.ConnectException;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.inno.env.APIException;
+
+/**
+ *
+ *
+ * @param <RT>
+ * @param <RET>
+ */
+public abstract class Retryable<RET> {
+ // be able to hold state for consistent Connections. Not required for all connection types.
+ public Rcli<?> lastClient;
+ private Locator.Item item;
+
+ public Retryable() {
+ lastClient = null;
+ item = null;
+ }
+
+ public Retryable(Retryable<?> ret) {
+ lastClient = ret.lastClient;
+ item = ret.item;
+ }
+
+ public Locator.Item item(Locator.Item item) {
+ lastClient = null;
+ this.item = item;
+ return item;
+ }
+ public Locator.Item item() {
+ return item;
+ }
+
+ public abstract RET code(Rcli<?> client) throws CadiException, ConnectException, APIException;
+
+ /**
+ * Note, Retryable is tightly coupled to the Client Utilizing. It will not be the wrong type.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public <CLIENT> Rcli<CLIENT> lastClient() {
+ return (Rcli<CLIENT>)lastClient;
+ }
+}
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
index 0000000..6810916
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DEClient.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.handler.DME2RestfulHandler;
+import com.att.aft.dme2.handler.DME2RestfulHandler.ResponseInfo;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.rosetta.env.RosettaDF;
+
+public class DEClient implements EClient<DME2Client> {
+ private DME2Client client;
+ private DME2RestfulHandler replyHandler;
+ private EClient.Transfer payload;
+ private boolean isProxy;
+ private SecuritySetter<DME2Client> ss;
+
+ public DEClient(DME2Manager manager, SecuritySetter<DME2Client> ss, URI uri, long timeout) throws DME2Exception, CadiException {
+ client = new DME2Client(manager,uri,timeout);
+ client.setAllowAllHttpReturnCodes(true);
+ this.ss = ss;
+ ss.setSecurity(client);
+ replyHandler = new DME2RestfulHandler(Rcli.BLANK);
+ client.setReplyHandler(replyHandler);
+ }
+
+ @Override
+ public void setMethod(String meth) {
+ client.setMethod(meth);
+ }
+
+ /**
+ * DME2 can't handle having QueryParams on the URL line, but it is the most natural way, so...
+ *
+ * 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"
+ */
+ public void setPathInfo(String pathinfo) {
+ int qp = pathinfo.indexOf('?');
+ if(qp<0) {
+ client.setContext(isProxy?("/proxy"+pathinfo):pathinfo);
+ } else {
+ client.setContext(isProxy?("/proxy"+pathinfo.substring(0,qp)):pathinfo.substring(0,qp));
+ client.setQueryParams(pathinfo.substring(qp+1));
+ }
+ }
+
+ @Override
+ public void setPayload(EClient.Transfer transfer) {
+ payload = transfer;
+ }
+
+ @Override
+ public void addHeader(String tag, String value) {
+ client.addHeader(tag, value);
+ }
+
+
+ @Override
+ public void setQueryParams(String q) {
+ client.setQueryParams(q);
+ }
+
+ @Override
+ public void setFragment(String f) {
+ // DME2 does not implement this
+ }
+
+ @Override
+ public void send() throws APIException {
+ try {
+ if(payload!=null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ payload.transfer(baos);
+ client.setPayload(new String(baos.toByteArray()));
+ } else {
+ client.setPayload("");
+ }
+ client.send();
+ } catch (DME2Exception e) {
+ throw new APIException(e);
+ } catch (IOException e) {
+ throw new APIException(e);
+ }
+ }
+
+
+ public class DFuture<T> extends Future<T> {
+ protected final DME2RestfulHandler reply;
+ protected ResponseInfo info;
+
+ public DFuture(DME2RestfulHandler reply) {
+ this.reply = reply;
+ }
+
+ protected boolean evalInfo() throws APIException{
+ //return info.getCode()==200;
+ return true;
+ };
+
+ public final boolean get(int timeout) throws CadiException {
+ try {
+ info = reply.getResponse(timeout);
+ ss.setLastResponse(info.getCode());
+ return evalInfo();
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public int code() {
+ return info.getCode();
+ }
+
+ @Override
+ public String body() {
+ return info.getBody();
+ }
+
+ @Override
+ public String header(String tag) {
+ return info.header(tag);
+ }
+
+ }
+
+ @Override
+ public <T> Future<T> futureCreate(Class<T> t) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+
+ return info.getCode()==201;
+ }
+ };
+ }
+
+
+ @Override
+ public Future<String> futureReadString() {
+ return new DFuture<String>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+ if(info.getCode()==200) {
+ value = info.getBody();
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public<T> Future<T> futureRead(final RosettaDF<T> df, final Data.TYPE type) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+ if(info.getCode()==200) {
+ value = df.newData().in(type).load(info.getBody()).asObject();
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public <T> Future<T> future(final T t) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() {
+ if(info.getCode()==200) {
+ value = t;
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public Future<Void> future(HttpServletResponse resp,int expected) throws APIException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setProxy(boolean isProxy) {
+ this.isProxy=isProxy;
+ }
+
+
+}
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
index 0000000..988c92f
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+
+public class DME2BasicAuth extends AbsBasicAuth<DME2Client> {
+ public DME2BasicAuth(String user, String pass, SecurityInfoC<DME2Client> si) throws IOException {
+ super(user,pass,si);
+ }
+
+ public DME2BasicAuth(Access access, SecurityInfoC<DME2Client> si) throws IOException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ si);
+ }
+
+ public DME2BasicAuth(BasicPrincipal bp,SecurityInfoC<DME2Client> si) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ }
+
+ public DME2BasicAuth(Access access) throws IOException, GeneralSecurityException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ new SecurityInfoC<DME2Client>(access));
+ }
+
+ public void setSecurity(DME2Client client) throws CadiException {
+ if(isDenied()) {
+ throw new CadiException(REPEAT_OFFENDER);
+ }
+ client.addHeader("Authorization", headValue);
+ }
+}
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
index 0000000..f64367b
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.SecuritySetter;
+
+public class DME2ClientSS implements SecuritySetter<DME2Client> {
+ private Access access;
+ private String user,crd;
+
+ public DME2ClientSS(Access access, String user, String pass) throws IOException {
+ this.access = access;
+ this.user = user;
+ this.crd = pass;
+ }
+
+ @Override
+ public void setSecurity(DME2Client client) {
+ try {
+ client.setCredentials(user, access.decrypt(crd, false));
+ } catch (IOException e) {
+ access.log(Level.ERROR,e,"Error decrypting DME2 Password");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return user;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
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
index 0000000..b81cf4a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2Locator.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Random;
+
+//
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.api.DME2Server;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class DME2Locator implements Locator {
+ private DME2Manager dm;
+ private DME2Endpoint[] endpoints;
+ private Access access;
+ private String service;
+ private String version;
+ private String routeOffer;
+ private String envContext;
+ private String thisMachine;
+ private String pathInfo;
+ private int thisPort;
+ private boolean removeSelf;
+ private final static Random random = new Random();
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,service,version,envContext,routeOffer,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ this.access = access;
+ if(dm==null) {
+ this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ this.service = service;
+ this.version = version;
+ this.envContext = envContext;
+ this.routeOffer = routeOffer;
+ refresh();
+ DME2Server server = dm.getServer();
+ if(server == null) {
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ try {
+ thisMachine = server.getServerProperties().getHostname();
+ //thisPort = server.getPort();
+ thisPort = server.getServerProperties().getPort();
+ } catch(NullPointerException np) { // BAD BOY, DME2...
+ access.log(Level.ERROR, "WARNING: DME2 threw a NullPointer Exception getting Server Machine and Port");
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ }
+ }
+ this.removeSelf = removeSelf;
+ }
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,aafurl,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ if(aafurl==null) throw new LocatorException("URL is null");
+ this.access = access;
+ if(dm==null) {
+ dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ String[] split = aafurl.split("/");
+ StringBuilder sb = new StringBuilder();
+ boolean dme2Entered = false;
+ for(String s : split) {
+ if(s.startsWith( "service=")) this.service = s.substring(8);
+ else if(s.startsWith("version=")) this.version = s.substring(8);
+ else if(s.startsWith("envContext=")) this.envContext = s.substring(11);
+ else if(s.startsWith("routeOffer=")) {
+ this.routeOffer = s.substring(11);
+ dme2Entered = true;
+ }
+ else if(dme2Entered) {
+ sb.append('/');
+ sb.append(s);
+ }
+ pathInfo = sb.toString();
+ }
+ DME2Server server = dm.getServer();
+ if(server == null) {
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisMachine = server.getServerProperties().getHostname();
+ if(thisMachine==null) { // even if server !=null, apparently, it can be uninitialized
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ try {
+ thisPort = server.getServerProperties().getPort();
+ } catch (Exception e) {
+ thisPort = 0;
+ }
+ }
+ }
+ this.removeSelf=removeSelf;
+ refresh();
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ dm.refresh();
+ endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);
+ if(removeSelf) {
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))
+ endpoints[i]=null;
+ }
+ }
+ return endpoints.length!=0;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e.getMessage());
+ }
+ return false;
+ }
+
+ private String noEndpointsString() {
+ StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");
+ sb.append(service);
+ sb.append('/');
+ sb.append(version);
+ sb.append('/');
+ sb.append(envContext);
+ sb.append('/');
+ sb.append(routeOffer);
+ return sb.toString();
+ }
+
+ @Override
+ public URI get(Locator.Item item) throws LocatorException {
+ if(!hasItems())
+ throw new LocatorException(noEndpointsString());
+ if(item == null)
+ return null;
+
+ Item li = ((Item)item);
+ // if URI has been created, use it
+ if(li.uri!=null)return li.uri;
+
+ // URI not created, create it
+ if(li.idx<endpoints.length) {
+ DME2Endpoint de = endpoints[li.idx];
+ if(de!=null) {
+ try {
+ return li.uri=new URI(de.getProtocol(),null,de.getHost(),de.getPort(),pathInfo,null,null);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return endpoints!=null && endpoints.length>0;
+ }
+
+ @Override
+ public void invalidate(Locator.Item item) throws LocatorException {
+ if(item instanceof Item) {
+ int idx = ((Item)item).idx;
+ if(idx<endpoints.length) {
+ DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.
+ endpoints[idx]=null;
+ boolean noneLeft=true;
+ for(int i=0;i<endpoints.length && noneLeft;++i) {
+ noneLeft = endpoints[i]==null;
+ }
+ if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...
+ for(int i=0;i<endpoints.length && noneLeft;++i) {
+ DME2Endpoint ep = endpoints[i];
+ if(ep != null &&
+ ep.getHost().equals(uhoh.getHost()) &&
+ ep.getPort()==uhoh.getPort()) {
+ endpoints[i]=null;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ public class Item implements Locator.Item {
+ private final int idx;
+ private URI uri;
+ private Item(int i) {
+ idx = i;
+ uri = null;
+ }
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ if(!hasItems()) // checks endpoints
+ if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");
+
+ // Some endpoints in Array are null. Need sub array of usable endpoints
+ int usable[] = new int[endpoints.length];
+ int count=0;
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i]!=null) {
+ usable[count++] = i;
+ }
+ }
+ switch(count) {
+ case 0: refresh(); return null;
+ case 1: return new Item(usable[0]);
+ default:
+ int samemach[] = new int[count];
+ int samecount = 0,closecount=0;
+ // has to be sortable
+ Integer closemach[] = new Integer[count];
+
+ // Analyze for Same Machine or Remote machines
+ for(int i=0;i<count;++i) {
+ DME2Endpoint ep = endpoints[usable[i]];
+ String host = ep.getHost();
+ if(thisMachine.equalsIgnoreCase(host)) {
+ samemach[samecount++] = usable[i];
+ } else {
+ closemach[closecount++] = usable[i];
+ }
+ }
+
+ switch(samecount) {
+ case 0: break;
+ case 1: return new Item(samemach[0]);
+ default: // return randomized is multiple Endpoints on local machine.
+ int i = random.nextInt();
+ return new Item(usable[Math.abs(i%samecount)]);
+ }
+
+ // Analyze for closest remote
+ switch(closecount) {
+ case 0: return null;
+ case 1: return new Item(closemach[0]);
+ default: // return closest machine
+ DoubIndex remote[] = new DoubIndex[closecount];
+ int remotecount = 0;
+ for(int i=0;i<closecount;++i) {
+ DME2Endpoint de = endpoints[usable[i]];
+ remote[remotecount++] = new DoubIndex(de.getDistance(),i);
+ }
+ Arrays.sort(remote,new Comparator<DoubIndex> () {
+ @Override
+ public int compare(DoubIndex a, DoubIndex b) {
+ if(a.d<b.d) return -1;
+ if(a.d>b.d) return 1;
+ return (random.nextInt()%1)==0?1:0;// randomize if the same
+ }
+
+ });
+ return new Item(remote[0].idx);
+ }
+ }
+ }
+
+ private class DoubIndex {
+ public final double d;
+ public final int idx;
+
+ public DoubIndex(double doub, int i) {
+ d = doub;
+ idx = i;
+ }
+ }
+ @Override
+ public Item first() {
+ if(endpoints==null)return null;
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i]!=null)
+ return new Item(i);
+ }
+ return null;
+ }
+
+ @Override
+ public Item next(Locator.Item item) throws LocatorException {
+ if(endpoints==null || endpoints.length==0 || !(item instanceof Item))return null;
+ int idx = ((Item)item).idx +1;
+ for(int i=idx;i<endpoints.length;++i) {
+ if(endpoints[i]!=null)
+ return new Item(i);
+ }
+// This is a mistake.. will start infinite loops
+// // Did not have any at end... try beginning
+// for(int i=0;i<idx-1;++i) {
+// if(endpoints[i]!=null)
+// return new Item(i);
+// }
+// // If still nothing, refresh
+// refresh();
+ return null;
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+}
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
index 0000000..d4612f1
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+
+public class DME2TransferSS extends AbsTransferSS<DME2Client> {
+
+ public DME2TransferSS(Principal principal, String app, SecurityInfoC<DME2Client> si) throws IOException {
+ super(principal, app, si);
+ }
+
+ @Override
+ public void setSecurity(DME2Client client) throws CadiException {
+ if(value!=null) {
+ if(defSS==null) {
+ throw new CadiException("Need App Credentials to send message");
+ }
+ defSS.setSecurity(client);
+ client.addHeader(Config.CADI_USER_CHAIN, value);
+ }
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+}
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
index 0000000..f60f791
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.inno.env.APIException;
+
+
+public class DME2x509SS implements SecuritySetter<DME2Client> {
+ private String alias;
+
+ public DME2x509SS(final String sendAlias, SecurityInfoC<DME2Client> si) throws APIException, IOException, CertificateEncodingException {
+ if((alias=sendAlias) == null) {
+ if(si.default_alias == null) {
+ throw new APIException("JKS Alias is required to use X509SS Security. Use " + Config.CADI_ALIAS +" to set default alias");
+ } else {
+ alias = si.default_alias;
+ }
+ }
+ }
+
+ @Override
+ public void setSecurity(DME2Client dme2) throws CadiException {
+ // DME2Client has to have properties set before creation to work.
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return alias;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+
+}
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
index 0000000..9ff56ca
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DRcli.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.aft.dme2.request.DmeUniformResource;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+
+/**
+ * DME2 Rosetta Client
+ *
+ * JAXB defined JSON or XML over DME2 middleware
+ *
+ *
+ * @param <T>
+ */
+public class DRcli extends Rcli<DME2Client> {
+ // Can be more efficient if tied to manager, apparently. Can pass in null.
+ DME2Manager manager=null;
+ private SecuritySetter<DME2Client> ss;
+ private boolean isProxy;
+
+ public DRcli(URI uri, SecuritySetter<DME2Client> secSet) {
+ this.uri = uri;
+ type = TYPE.JSON;
+ apiVersion = null;
+ ss=secSet;
+ }
+
+ @Override
+ protected DRcli clone(URI uri, SecuritySetter<DME2Client> ss) {
+ return new DRcli(uri,ss);
+ }
+
+
+
+ /**
+ * Note from Thaniga on 11/5. DME2Client is not expected to be reused... need a fresh one
+ * on each transaction, which is expected to cover the Async aspects.
+ *
+ * @return
+ * @throws APIException
+ * @throws DME2Exception
+ */
+ protected EClient<DME2Client> client() throws CadiException {
+ try {
+ DEClient dc = new DEClient(manager,getSecuritySetter(),uri,readTimeout);
+ dc.setProxy(isProxy);
+ return dc;
+ } catch (DME2Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public DRcli setManager(DME2Manager dme2Manager) {
+ manager = dme2Manager;
+ return this;
+ }
+
+ public List<DRcli> all() throws DME2Exception, APIException {
+ ArrayList<DRcli> al = new ArrayList<DRcli>();
+
+ if(manager == null) {
+ manager = DME2Manager.getDefaultInstance();
+ }
+ try {
+ DME2Endpoint[] endp = manager.getEndpoints(new DmeUniformResource(manager.getConfig(),uri));
+ // Convert Searchable Endpoints to Direct Endpoints
+ for(DME2Endpoint de : endp) {
+ al.add(new DRcli(
+ new URI(uri.getScheme(),null,de.getHost(),de.getPort(),null,null,null),ss)
+// new URI(uri.getScheme(),null,de.getHost(),de.getPort(),uri.getPath(),null,null),ss)
+ .setManager(manager)
+ );
+ }
+ } catch (MalformedURLException e) {
+ throw new APIException("Invalid URL",e);
+ } catch (URISyntaxException e) {
+ throw new APIException("Invalid URI",e);
+ }
+ return al;
+ }
+
+ @Override
+ public void invalidate() throws CadiException {
+ try {
+ manager.refresh();
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public void setSecuritySetter(SecuritySetter<DME2Client> ss) {
+ this.ss = ss;
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> getSecuritySetter() {
+ return ss;
+ }
+
+ public void setProxy(boolean isProxy) {
+ this.isProxy = isProxy;
+ }
+
+}
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
index 0000000..498b013
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dnsloc;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class DNSLocator implements Locator {
+ private static enum Status {UNTRIED, OK, INVALID, SLOW};
+ private static final int CHECK_TIME = 3000;
+
+ private String host, protocol;
+ private Access access;
+ private Host[] hosts;
+ private int startPort, endPort;
+ private String suffix;
+
+ public DNSLocator(Access access, String protocol, String host, String range) {
+ this.host = host;
+ this.protocol = protocol;
+ this.access = access;
+ int dash = range.indexOf('-');
+ if(dash<0) {
+ startPort = endPort = Integer.parseInt(range);
+ } else {
+ startPort = Integer.parseInt(range.substring(0,dash));
+ endPort = Integer.parseInt(range.substring(dash + 1));
+ }
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return hosts[((DLItem)item).cnt].uri;
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(Host h : hosts) {
+ if(h.status==Status.OK) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void invalidate(Item item) {
+ DLItem di = (DLItem)item;
+ hosts[di.cnt].status = Status.INVALID;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ // not a good "best"
+ for(int i=0;i<hosts.length;++i) {
+ switch(hosts[i].status) {
+ case OK:
+ return new DLItem(i);
+ case INVALID:
+ break;
+ case SLOW:
+ break;
+ case UNTRIED:
+ try {
+ if(hosts[i].ia.isReachable(CHECK_TIME)) {
+ hosts[i].status = Status.OK;
+ return new DLItem(i);
+ }
+ } catch (IOException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ throw new LocatorException("No Available URIs for " + host);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new DLItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ DLItem di = (DLItem)item;
+ if(++di.cnt<hosts.length) {
+ return di;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ InetAddress[] ias = InetAddress.getAllByName(host);
+ Host[] temp = new Host[ias.length * (1 + endPort - startPort)];
+ int cnt = -1;
+ for(int j=startPort; j<=endPort; ++j) {
+ for(int i=0;i<ias.length;++i) {
+ temp[++cnt] = new Host(ias[i], j, suffix);
+ }
+ }
+ hosts = temp;
+ return true;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e);
+ }
+ return false;
+ }
+
+ private class Host {
+ private URI uri;
+ private InetAddress ia;
+ private Status status;
+
+ public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {
+ ia = inetAddress;
+ uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);
+ status = Status.UNTRIED;
+ }
+ }
+
+ private class DLItem implements Item {
+ public DLItem(int i) {
+ cnt = i;
+ }
+
+ private int cnt;
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+}
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
index 0000000..8d8826e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+
+public class HBasicAuthSS extends AbsBasicAuth<HttpURLConnection> {
+ public HBasicAuthSS(Access access, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ si);
+ }
+
+ public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(user,pass,si);
+ }
+
+ public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {
+ super(user,pass,si);
+ if(asDefault) {
+ si.set(this);
+ }
+ }
+
+ public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ }
+
+ public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ if(asDefault) {
+ si.set(this);
+ }
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(isDenied()) {
+ throw new CadiException(REPEAT_OFFENDER);
+ }
+ huc.addRequestProperty("Authorization" , headValue);
+ if(securityInfo!=null && huc instanceof HttpsURLConnection) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ }
+}
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
index 0000000..d17dcc7
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HClient.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Pool.Pooled;
+import com.att.rosetta.env.RosettaDF;
+
+/**
+ * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
+ * for Rosetta Object Translation
+ *
+ *
+ */
+public class HClient implements EClient<HttpURLConnection> {
+ private URI uri;
+ private ArrayList<Header> headers;
+ private String meth;
+ private String pathinfo;
+ private String query;
+ private String fragment;
+ private Transfer transfer;
+ private SecuritySetter<HttpURLConnection> ss;
+ private HttpURLConnection huc;
+ private int connectTimeout;
+
+ public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
+ if (uri == null) {
+ throw new LocatorException("No Service available to call");
+ }
+ this.uri = uri;
+ this.ss = ss;
+ this.connectTimeout = connectTimeout;
+ pathinfo = query = fragment = "";
+ }
+
+ @Override
+ public void setMethod(String meth) {
+ this.meth = meth;
+ }
+
+ @Override
+ public void setPathInfo(String pathinfo) {
+ this.pathinfo = pathinfo;
+ }
+
+ @Override
+ public void setPayload(Transfer transfer) {
+ this.transfer = transfer;
+ }
+
+ @Override
+ public void addHeader(String tag, String value) {
+ if (headers == null)
+ headers = new ArrayList<Header>();
+ headers.add(new Header(tag, value));
+ }
+
+ @Override
+ public void setQueryParams(String q) {
+ query = q;
+ }
+
+ @Override
+ public void setFragment(String f) {
+ fragment = f;
+ }
+
+ @Override
+ public void send() throws APIException {
+ try {
+ // Build URL from given URI plus current Settings
+ if(uri.getPath()==null) {
+ throw new APIException("Invalid URL entered for HClient");
+ }
+ StringBuilder pi = new StringBuilder(uri.getPath());
+ if(!pathinfo.startsWith("/")) {
+ pi.append('/');
+ }
+ pi.append(pathinfo);
+ URL url = new URI(
+ uri.getScheme(),
+ uri.getUserInfo(),
+ uri.getHost(),
+ uri.getPort(),
+ pi.toString(),
+ query,
+ fragment).toURL();
+ pathinfo=null;
+ query=null;
+ fragment=null;
+ huc = (HttpURLConnection) url.openConnection();
+ if(ss!=null) {
+ ss.setSecurity(huc);
+ }
+ huc.setRequestMethod(meth);
+ if (headers != null)
+ for (Header d : headers) {
+ huc.addRequestProperty(d.tag, d.value);
+ }
+ huc.setDoInput(true);
+ huc.setDoOutput(true);
+ huc.setUseCaches(false);
+ huc.setConnectTimeout(connectTimeout);
+ huc.connect();
+ if (transfer != null) {
+ transfer.transfer(huc.getOutputStream());
+ }
+ // TODO other settings? There's a bunch here.
+ } catch (Exception e) {
+ throw new APIException(e);
+ } finally { // ensure all these are reset after sends
+ meth=pathinfo=null;
+ if(headers!=null) {
+ headers.clear();
+ }
+ pathinfo = query = fragment = "";
+ }
+ }
+
+ public abstract class HFuture<T> extends Future<T> {
+ protected HttpURLConnection huc;
+ protected int respCode;
+ protected String respMessage;
+ protected IOException exception;
+ protected StringBuilder errContent;
+
+ public HFuture(final HttpURLConnection huc) {
+ this.huc = huc;
+ }
+
+ protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
+ return respCode == 200;
+ };
+
+ @Override
+ public final boolean get(int timeout) throws CadiException {
+ try {
+ huc.setReadTimeout(timeout);
+ respCode = huc.getResponseCode();
+ ss.setLastResponse(respCode);
+ if(evalInfo(huc)) {
+ return true;
+ } else {
+ extractError();
+ return false;
+ }
+ } catch (IOException | APIException e) {
+ throw new CadiException(e);
+ } finally {
+ close();
+ }
+ }
+
+ private void extractError() {
+ InputStream is = huc.getErrorStream();
+ try {
+ if(is==null) {
+ is = huc.getInputStream();
+ }
+ if(is!=null) {
+ errContent = new StringBuilder();
+ int c;
+ while((c=is.read())>=0) {
+ errContent.append((char)c);
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ }
+ }
+
+ // Typically only used by Read
+ public StringBuilder inputStreamToString(InputStream is) {
+ // Avoids Carriage returns, and is reasonably efficient, given
+ // the buffer reads.
+ try {
+ StringBuilder sb = new StringBuilder();
+ Reader rdr = new InputStreamReader(is);
+ try {
+ char[] buf = new char[256];
+ int read;
+ while ((read = rdr.read(buf)) >= 0) {
+ sb.append(buf, 0, read);
+ }
+ } finally {
+ rdr.close();
+ }
+ return sb;
+ } catch (IOException e) {
+ exception = e;
+ return null;
+ }
+ }
+
+
+ @Override
+ public int code() {
+ return respCode;
+ }
+
+ public HttpURLConnection huc() {
+ return huc;
+ }
+
+ public IOException exception() {
+ return exception;
+ }
+
+ public String respMessage() {
+ return respMessage;
+ }
+
+ @Override
+ public String header(String tag) {
+ return huc.getHeaderField(tag);
+ }
+
+ public void close() {
+ if(huc!=null) {
+ huc.disconnect();
+ }
+ }
+ }
+
+ @Override
+ public <T> Future<T> futureCreate(Class<T> t) {
+ return new HFuture<T>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) {
+ return respCode==201;
+ }
+
+ @Override
+ public String body() {
+ if (errContent != null) {
+ return errContent.toString();
+
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+ };
+ }
+
+ @Override
+ public Future<String> futureReadString() {
+ return new HFuture<String>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) throws IOException {
+ if (respCode == 200) {
+ StringBuilder sb = inputStreamToString(huc.getInputStream());
+ if (sb != null) {
+ value = sb.toString();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (value != null) {
+ return value;
+ } else if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+
+ };
+ }
+
+ @Override
+ public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
+ return new HFuture<T>(huc) {
+ private Data<T> data;
+
+ public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
+ if (respCode == 200) {
+ data = df.newData().in(type).load(huc.getInputStream());
+ value = data.asObject();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (data != null) {
+ try {
+ return data.asString();
+ } catch (APIException e) {
+ }
+ } else if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+ };
+ }
+
+ @Override
+ public <T> Future<T> future(final T t) {
+ return new HFuture<T>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) {
+ if (respCode == 200) {
+ value = t;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return Integer.toString(respCode);
+ }
+ };
+ }
+
+ @Override
+ public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
+ return new HFuture<Void>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
+ resp.setStatus(respCode);
+ int read;
+ InputStream is;
+ OutputStream os = resp.getOutputStream();
+ if(respCode==expected) {
+ is = huc.getInputStream();
+ // reuse Buffers
+ Pooled<byte[]> pbuff = Rcli.buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ return true;
+ } else {
+ is = huc.getErrorStream();
+ if(is==null) {
+ is = huc.getInputStream();
+ }
+ if(is!=null) {
+ errContent = new StringBuilder();
+ Pooled<byte[]> pbuff = Rcli.buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ return errContent==null?respMessage:errContent.toString();
+ }
+ };
+ }
+
+ private static class Header {
+ public final String tag;
+ public final String value;
+
+ public Header(String t, String v) {
+ this.tag = t;
+ this.value = v;
+ }
+
+ public String toString() {
+ return tag + '=' + value;
+ }
+ }
+
+ public String toString() {
+ return "HttpURLConnection Client configured to " + uri.toString();
+ }
+}
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
index 0000000..78aff4e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HMangr.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.inno.env.APIException;
+
+public class HMangr {
+ private String apiVersion;
+ private int readTimeout, connectionTimeout;
+ public final Locator<URI> loc;
+ private Access access;
+
+ public HMangr(Access access, Locator<URI> loc) {
+ readTimeout = 10000;
+ connectionTimeout=3000;
+ this.loc = loc;
+ this.access = access;
+ }
+
+ /**
+ * Reuse the same service. This is helpful for multiple calls that change service side cached data so that
+ * there is not a speed issue.
+ *
+ * If the service goes down, another service will be substituted, if available.
+ *
+ * @param access
+ * @param loc
+ * @param ss
+ * @param item
+ * @param retryable
+ * @return
+ * @throws URISyntaxException
+ * @throws Exception
+ */
+ public<RET> RET same(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws APIException, CadiException, LocatorException {
+ RET ret = null;
+ boolean retry = true;
+ int retries = 0;
+ Rcli<HttpURLConnection> client = retryable.lastClient();
+ try {
+ do {
+ // if no previous state, get the best
+ if(retryable.item()==null) {
+ retryable.item(loc.best());
+ retryable.lastClient = null;
+ }
+ if(client==null) {
+ Item item = retryable.item();
+ URI uri=loc.get(item);
+ if(uri==null) {
+ loc.invalidate(retryable.item());
+ if(loc.hasItems()) {
+ retryable.item(loc.next(retryable.item()));
+ continue;
+ } else {
+ throw new LocatorException("No clients available for " + loc.toString());
+ }
+ }
+ client = new HRcli(this, uri,item,ss)
+ .connectionTimeout(connectionTimeout)
+ .readTimeout(readTimeout)
+ .apiVersion(apiVersion);
+ } else {
+ client.setSecuritySetter(ss);
+ }
+
+ retry = false;
+ try {
+ ret = retryable.code(client);
+ } catch (APIException | CadiException e) {
+ Item item = retryable.item();
+ loc.invalidate(item);
+ retryable.item(loc.next(item));
+ try {
+ Throwable ec = e.getCause();
+ if(ec instanceof java.net.ConnectException) {
+ if(client!=null && ++retries<2) {
+ access.log(Level.WARN,"Connection refused, trying next available service");
+ retry = true;
+ } else {
+ throw new CadiException("Connection refused, no more available connections to try");
+ }
+ } else if(ec instanceof SSLHandshakeException) {
+ retryable.item(null);
+ throw e;
+ } else if(ec instanceof SocketException) {
+ if("java.net.SocketException: Connection reset".equals(ec.getMessage())) {
+ access.log(Level.ERROR, ec.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
+ }
+ retryable.item(null);
+ throw e;
+ } else {
+ retryable.item(null);
+ throw e;
+ }
+ } finally {
+ client = null;
+ }
+ } catch (ConnectException e) {
+ Item item = retryable.item();
+ loc.invalidate(item);
+ retryable.item(loc.next(item));
+ }
+ } while(retry);
+ } finally {
+ retryable.lastClient = client;
+ }
+ return ret;
+ }
+
+
+ public<RET> RET best(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ if(loc==null) {
+ throw new LocatorException("No Locator Configured");
+ }
+ retryable.item(loc.best());
+ return same(ss,retryable);
+ }
+ public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ return oneOf(ss,retryable,true,null);
+ }
+
+ public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify) throws LocatorException, CadiException, APIException {
+ return oneOf(ss,retryable,notify,null);
+ }
+
+ public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify,String host) throws LocatorException, CadiException, APIException {
+ RET ret = null;
+ // make sure we have all current references:
+ loc.refresh();
+ for(Item li=loc.first();li!=null;li=loc.next(li)) {
+ URI uri=loc.get(li);
+ if(host!=null && !host.equals(uri.getHost())) {
+ break;
+ }
+ try {
+ ret = retryable.code(new HRcli(this,uri,li,ss));
+ access.log(Level.DEBUG,"Success calling",uri,"during call to all services");
+ } catch (APIException | CadiException e) {
+ Throwable t = e.getCause();
+ if(t!=null && t instanceof ConnectException) {
+ loc.invalidate(li);
+ access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
+ } else if(t instanceof SSLHandshakeException) {
+ access.log(Level.ERROR,t.getMessage());
+ loc.invalidate(li);
+ } else if(t instanceof SocketException) {
+ if("java.net.SocketException: Connection reset".equals(t.getMessage())) {
+ access.log(Level.ERROR, t.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
+ }
+ retryable.item(null);
+ throw e;
+ } else {
+ throw e;
+ }
+ } catch (ConnectException e) {
+ loc.invalidate(li);
+ access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
+ }
+ }
+
+ if(ret == null && notify)
+ throw new LocatorException("No available clients to call");
+ return ret;
+ }
+
+
+ public void close() {
+ // TODO Anything here?
+ }
+
+ public HMangr readTimeout(int timeout) {
+ this.readTimeout = timeout;
+ return this;
+ }
+
+ public int readTimeout() {
+ return readTimeout;
+ }
+
+ public void connectionTimeout(int t) {
+ connectionTimeout = t;
+ }
+
+ public int connectionTimout() {
+ return connectionTimeout;
+ }
+
+ public HMangr apiVersion(String version) {
+ apiVersion = version;
+ return this;
+ }
+
+ public String apiVersion() {
+ return apiVersion;
+ }
+
+}
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
index 0000000..a55b55a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HRcli.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+
+/**
+ * DME2 Rosetta Client
+ *
+ * JAXB defined JSON or XML over DME2 middleware
+ *
+ *
+ * @param <T>
+ */
+public class HRcli extends Rcli<HttpURLConnection> {
+ private HMangr hman;
+ private Item item;
+ private SecuritySetter<HttpURLConnection> ss;
+
+ public HRcli(HMangr hman, Item locItem, SecuritySetter<HttpURLConnection> secSet) throws URISyntaxException, LocatorException {
+ item=locItem;
+ uri=hman.loc.get(locItem);
+ this.hman = hman;
+ ss=secSet;
+ type = TYPE.JSON;
+ apiVersion = hman.apiVersion();
+ }
+
+ public HRcli(HMangr hman, URI uri, Item locItem, SecuritySetter<HttpURLConnection> secSet) {
+ locItem=item;
+ this.uri = uri;
+ this.hman = hman;
+ ss=secSet;
+ type = TYPE.JSON;
+ apiVersion = hman.apiVersion();
+ }
+
+ @Override
+ protected HRcli clone(URI uri, SecuritySetter<HttpURLConnection> ss) {
+ return new HRcli(hman,uri,item,ss);
+ }
+
+
+
+ /**
+ * Note from Thaniga on 11/5. DME2Client is not expected to be reused... need a fresh one
+ * on each transaction, which is expected to cover the Async aspects.
+ *
+ * @return
+ * @throws APIException
+ * @throws DME2Exception
+ */
+ protected EClient<HttpURLConnection> client() throws CadiException {
+ try {
+ if(uri==null) {
+ Item item = hman.loc.best();
+ if(item==null) {
+ throw new CadiException("No service available for " + hman.loc.toString());
+ }
+ uri = hman.loc.get(item);
+ }
+ return new HClient(ss,uri,connectionTimeout);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.client.Rcli#setSecuritySetter(com.att.cadi.SecuritySetter)
+ */
+ @Override
+ public void setSecuritySetter(SecuritySetter<HttpURLConnection> ss) {
+ this.ss = ss;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.client.Rcli#getSecuritySetter()
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> getSecuritySetter() {
+ return ss;
+ }
+
+ public void invalidate() throws CadiException {
+ try {
+ hman.loc.invalidate(item);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public HRcli setManager(HMangr hman) {
+ this.hman = hman;
+ return this;
+ }
+
+ public String toString() {
+ return uri.toString();
+ }
+
+}
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
index 0000000..180a341
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HTransferSS.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.security.Principal;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+
+
+public class HTransferSS extends AbsTransferSS<HttpURLConnection> {
+ public HTransferSS(Principal principal, String app) throws IOException {
+ super(principal, app);
+ }
+
+ public HTransferSS(Principal principal, String app, SecurityInfoC<HttpURLConnection> si) {
+ super(principal, app, si);
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(value!=null) {
+ if(defSS==null) {
+ throw new CadiException("Need App Credentials to send message");
+ }
+ defSS.setSecurity(huc);
+ huc.addRequestProperty(Config.CADI_USER_CHAIN, value);
+ }
+ if(securityInfo!=null) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+
+}
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
index 0000000..3022c0f
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HX509SS.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.X509KeyManager;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Chrono;
+
+
+public class HX509SS implements SecuritySetter<HttpURLConnection> {
+ private static final byte[] X509 = "x509 ".getBytes();
+ private PrivateKey priv;
+ private byte[] pub;
+ private String cert;
+ private SecurityInfoC<HttpURLConnection> securityInfo;
+ private String algo;
+ private String alias;
+ private static int count = new SecureRandom().nextInt();
+
+ public HX509SS(SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {
+ this(null,si,false);
+ }
+
+ public HX509SS(SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {
+ this(null,si,asDefault);
+ }
+
+ public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {
+ this(sendAlias, si, false);
+ }
+
+ public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {
+ securityInfo = si;
+ if((alias=sendAlias) == null) {
+ if(si.default_alias == null) {
+ throw new APIException("JKS Alias is required to use X509SS Security. Use " + Config.CADI_ALIAS +" to set default alias");
+ } else {
+ alias = si.default_alias;
+ }
+ }
+
+ priv=null;
+ X509KeyManager[] xkms = si.getKeyManagers();
+ if(xkms==null || xkms.length==0) {
+ throw new APIException("There are no valid keys available in given Keystores. Wrong Keypass? Expired?");
+ }
+ for(int i=0;priv==null&&i<xkms.length;++i) {
+ priv = xkms[i].getPrivateKey(alias);
+ }
+ for(int i=0;cert==null&&i<xkms.length;++i) {
+ X509Certificate[] chain = xkms[i].getCertificateChain(alias);
+ if(chain!=null&&chain.length>0) {
+ algo = chain[0].getSigAlgName();
+ pub = chain[0].getEncoded();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(pub.length*2);
+ ByteArrayInputStream bais = new ByteArrayInputStream(pub);
+ Symm.base64noSplit.encode(bais,baos,X509);
+ cert = baos.toString();
+
+ /*
+ // Inner Test code, uncomment if fix needed
+ bais = new ByteArrayInputStream(baos.toByteArray());
+ baos = new ByteArrayOutputStream(input.length*2);
+ Symm.base64noSplit().decode(bais,baos,5);
+ byte[] output = baos.toByteArray();
+ String reconstitute = output.toString();
+ System.out.println("ok");
+ CertificateFactory certFactory;
+ try {
+ bais = new ByteArrayInputStream(output);
+ certFactory = CertificateFactory.getInstance("X.509");
+ X509Certificate x509 = (X509Certificate)certFactory.generateCertificate(bais);
+ System.out.println(x509.toString());
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ }
+ */
+ }
+ }
+ if(algo==null) {
+ throw new APIException("X509 Security Setter not configured");
+ }
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(huc instanceof HttpsURLConnection) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ if(alias==null) { // must be a one-way
+ huc.setRequestProperty("Authorization", cert);
+
+ // Test Signed content
+ try {
+ String data = "SignedContent["+ inc() + ']' + Chrono.dateTime();
+ huc.setRequestProperty("Data", data);
+
+ Signature sig = Signature.getInstance(algo);
+ sig.initSign(priv);
+ sig.update(data.getBytes());
+ byte[] signature = sig.sign();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(signature.length*1.3));
+ ByteArrayInputStream bais = new ByteArrayInputStream(signature);
+ Symm.base64noSplit.encode(bais, baos);
+ huc.setRequestProperty("Signature", new String(baos.toByteArray()));
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+ }
+
+ private synchronized int inc() {
+ return ++count;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return alias;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+}
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
index 0000000..72a5f73
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/DME2Locator.java
@@ -0,0 +1,346 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Properties;
+import java.util.Random;
+import java.security.SecureRandom;
+
+//import com.att.aft.dme2.api.DME2Endpoint;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.api.DME2Server;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+
+public class DME2Locator implements Locator<URI> {
+ private DME2Manager dm;
+ private DME2Endpoint[] endpoints;
+ private Access access;
+ private String service;
+ private String version;
+ private String routeOffer;
+ private String envContext;
+ private String thisMachine;
+ private String pathInfo;
+ private int thisPort;
+ private boolean removeSelf;
+ private final static SecureRandom random = new SecureRandom();
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,service,version,envContext,routeOffer,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ this.access = access;
+ if(dm==null) {
+ this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ this.service = service;
+ this.version = version;
+ this.envContext = envContext;
+ this.routeOffer = routeOffer;
+ refresh();
+ if(thisMachine==null) {
+ // Can't get from dm...
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisPort = dm.getPort();
+ }
+
+ this.removeSelf = removeSelf;
+ }
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,aafurl,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ if(aafurl==null) {
+ throw new LocatorException("URL is null");
+ }
+ this.access = access;
+ if(dm==null) {
+ Properties dprops;
+ if(access instanceof PropAccess) {
+ dprops = ((PropAccess)access).getDME2Properties();
+ } else {
+ dprops = System.getProperties();
+ }
+ dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",dprops);
+ } else {
+ this.dm = dm;
+ }
+ String[] split = aafurl.split("/");
+ StringBuilder sb = new StringBuilder();
+ boolean dme2Entered = false;
+ for(String s : split) {
+ if(s.startsWith("service=")) {
+ this.service = s.substring(8);
+ } else if(s.startsWith("version=")) {
+ this.version = s.substring(8);
+ } else if(s.startsWith("envContext=")) {
+ this.envContext = s.substring(11);
+ } else if(s.startsWith("routeOffer=")) {
+ this.routeOffer = s.substring(11);
+ dme2Entered = true;
+ } else if(dme2Entered) {
+ sb.append('/');
+ sb.append(s);
+ }
+ }
+ pathInfo = sb.toString();
+ thisMachine = dm.getHostname();
+ if(thisMachine==null) {
+ // Can't get from dm...
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisPort = dm.getPort();
+ }
+ this.removeSelf=removeSelf;
+ refresh();
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ dm.refresh();
+ //endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);
+ if(removeSelf) {
+// for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))
+// endpoints[i]=null;
+ }
+ //}
+ //return endpoints.length!=0;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e.getMessage());
+ }
+ return false;
+ }
+
+ private String noEndpointsString() {
+ StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");
+ sb.append(service);
+ sb.append('/');
+ sb.append(version);
+ sb.append('/');
+ sb.append(envContext);
+ sb.append('/');
+ sb.append(routeOffer);
+ return sb.toString();
+ }
+
+ @Override
+ public URI get(Locator.Item item) throws LocatorException {
+ if(!hasItems())
+ throw new LocatorException(noEndpointsString());
+ if(item == null)
+ return null;
+
+ DME2Item li = ((DME2Item)item);
+ // if URI has been created, use it
+ if(li.uri!=null)return li.uri;
+
+ // URI not created, create it
+// if(li.idx<endpoints.length) {
+// DME2Endpoint de = endpoints[li.idx];
+// if(de!=null) {
+// try {
+// return li.uri=new URI(de.getProtocol().toLowerCase(),null,de.getHost(),de.getPort(),pathInfo,null,null);
+// } catch (URISyntaxException e) {
+// throw new LocatorException(e);
+// }
+// }
+// }
+ return null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ //return endpoints!=null && endpoints.length>0;
+ return true;
+ }
+
+ @Override
+ public void invalidate(Locator.Item item) throws LocatorException {
+ if(item instanceof DME2Item) {
+ int idx = ((DME2Item)item).idx;
+// if(idx<endpoints.length) {
+// DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.
+// endpoints[idx]=null;
+// boolean noneLeft=true;
+// for(int i=0;i<endpoints.length && noneLeft;++i) {
+// noneLeft = endpoints[i]==null;
+// }
+// if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...
+// for(int i=0;i<endpoints.length && noneLeft;++i) {
+// DME2Endpoint ep = endpoints[i];
+// if(ep != null &&
+// ep.getHost().equals(uhoh.getHost()) &&
+// ep.getPort()==uhoh.getPort()) {
+// endpoints[i]=null;
+// }
+// }
+// }
+//
+// }
+ }
+ }
+
+ public class DME2Item implements Locator.Item {
+ private final int idx;
+ private URI uri;
+ private DME2Item(int i) {
+ idx = i;
+ uri = null;
+ }
+ }
+
+ @Override
+ public DME2Item best() throws LocatorException {
+ if(!hasItems()) // checks endpoints
+ if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");
+
+ // Some endpoints in Array are null. Need sub array of usable endpoints
+ //int usable[] = new int[endpoints.length];
+ int count=0;
+int[] usable = null;
+ // for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i]!=null) {
+// usable[count++] = i;
+// }
+// }
+ switch(count) {
+ case 0: refresh(); return null;
+ case 1: return new DME2Item(usable[0]);
+ default:
+ int samemach[] = new int[count];
+ int samecount = 0,closecount=0;
+ // has to be sortable
+ Integer closemach[] = new Integer[count];
+
+ // Analyze for Same Machine or Remote machines
+// for(int i=0;i<count;++i) {
+// DME2Endpoint ep = endpoints[usable[i]];
+// String host = ep.getHost();
+// if(thisMachine.equalsIgnoreCase(host)) {
+// samemach[samecount++] = usable[i];
+// } else {
+// closemach[closecount++] = usable[i];
+// }
+// }
+
+ switch(samecount) {
+ case 0: break;
+ case 1: return new DME2Item(samemach[0]);
+ default: // return randomized is multiple Endpoints on local machine.
+ int i = random.nextInt();
+ return new DME2Item(usable[Math.abs(i%samecount)]);
+ }
+
+ // Analyze for closest remote
+ switch(closecount) {
+ case 0: return null;
+ case 1: return new DME2Item(closemach[0]);
+ default: // return closest machine
+ DoubIndex remote[] = new DoubIndex[closecount];
+ int remotecount = 0;
+ for(int i=0;i<closecount;++i) {
+ //DME2Endpoint de = endpoints[usable[i]];
+ // remote[remotecount++] = new DoubIndex(de.getDistance(),i);
+ }
+ Arrays.sort(remote,new Comparator<DoubIndex> () {
+ @Override
+ public int compare(DoubIndex a, DoubIndex b) {
+ if(a.d<b.d) return -1;
+ if(a.d>b.d) return 1;
+ return (random.nextInt()%1)==0?1:0;// randomize if the same
+ }
+
+ });
+ return new DME2Item(remote[0].idx);
+ }
+ }
+ }
+
+ private static class DoubIndex {
+ public final double d;
+ public final int idx;
+
+ public DoubIndex(double doub, int i) {
+ d = doub;
+ idx = i;
+ }
+ }
+ @Override
+ public DME2Item first() {
+// if(endpoints==null)return null;
+// for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i]!=null)
+// return new DME2Item(i);
+// }
+ return null;
+ }
+
+ @Override
+ public DME2Item next(Locator.Item item) throws LocatorException {
+ //if(endpoints==null || endpoints.length==0 || !(item instanceof DME2Item))return null;
+ int idx = ((DME2Item)item).idx +1;
+// for(int i=idx;i<endpoints.length;++i) {
+// if(endpoints[i]!=null)
+// return new DME2Item(i);
+// }
+// This is a mistake.. will start infinite loops
+// // Did not have any at end... try beginning
+// for(int i=0;i<idx-1;++i) {
+// if(endpoints[i]!=null)
+// return new Item(i);
+// }
+// // If still nothing, refresh
+// refresh();
+ return null;
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
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
index 0000000..9fbf2d4
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/DNSLocator.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Access.Level;
+
+public class DNSLocator implements Locator<URI> {
+ private static enum Status {UNTRIED, OK, INVALID, SLOW};
+ private static final int CHECK_TIME = 3000;
+
+ private String host, protocol;
+ private Access access;
+ private Host[] hosts;
+ private int startPort, endPort;
+ private String suffix;
+
+ public DNSLocator(Access access, String protocol, String host, String range) {
+ this.host = host;
+ this.protocol = protocol;
+ this.access = access;
+ int dash = range.indexOf('-');
+ if(dash<0) {
+ startPort = endPort = Integer.parseInt(range);
+ } else {
+ startPort = Integer.parseInt(range.substring(0,dash));
+ endPort = Integer.parseInt(range.substring(dash + 1));
+ }
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return hosts[((DLItem)item).cnt].uri;
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(Host h : hosts) {
+ if(h.status==Status.OK) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void invalidate(Item item) {
+ DLItem di = (DLItem)item;
+ hosts[di.cnt].status = Status.INVALID;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ // not a good "best"
+ for(int i=0;i<hosts.length;++i) {
+ switch(hosts[i].status) {
+ case OK:
+ return new DLItem(i);
+ case INVALID:
+ break;
+ case SLOW:
+ break;
+ case UNTRIED:
+ try {
+ if(hosts[i].ia.isReachable(CHECK_TIME)) {
+ hosts[i].status = Status.OK;
+ return new DLItem(i);
+ }
+ } catch (IOException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ throw new LocatorException("No Available URIs for " + host);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new DLItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ DLItem di = (DLItem)item;
+ if(++di.cnt<hosts.length) {
+ return di;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ InetAddress[] ias = InetAddress.getAllByName(host);
+ Host[] temp = new Host[ias.length * (1 + endPort - startPort)];
+ int cnt = -1;
+ for(int j=startPort; j<=endPort; ++j) {
+ for(int i=0;i<ias.length;++i) {
+ temp[++cnt] = new Host(ias[i], j, suffix);
+ }
+ }
+ hosts = temp;
+ return true;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e);
+ }
+ return false;
+ }
+
+ private class Host {
+ private URI uri;
+ private InetAddress ia;
+ private Status status;
+
+ public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {
+ ia = inetAddress;
+ uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);
+ status = Status.UNTRIED;
+ }
+ }
+
+ private class DLItem implements Item {
+ public DLItem(int i) {
+ cnt = i;
+ }
+
+ private int cnt;
+ }
+
+ public void destroy() {}
+}
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
index 0000000..ecbdfaa
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.LocatorException;
+import com.att.cadi.http.HClient;
+import com.att.cadi.http.HX509SS;
+
+public class HClientHotPeerLocator extends HotPeerLocator<HClient> {
+ private final HX509SS ss;
+
+ public HClientHotPeerLocator(Access access, String urlstr, long invalidateTime, String localLatitude,
+ String localLongitude, HX509SS ss) throws LocatorException {
+ super(access, urlstr, invalidateTime, localLatitude, localLongitude);
+
+ this.ss = ss;
+ }
+
+ @Override
+ protected HClient _newClient(String clientInfo) throws LocatorException {
+ try {
+ int idx = clientInfo.indexOf('/');
+ return new HClient(ss,new URI("https://"+(idx<0?clientInfo:clientInfo.substring(0, idx))),3000);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+
+ @Override
+ protected HClient _invalidate(HClient client) {
+ return null;
+ }
+
+ @Override
+ protected void _destroy(HClient client) {
+ }
+}
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
index 0000000..f8a1546
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.routing.GreatCircle;
+import com.att.inno.env.util.Split;
+
+/**
+ * This Locator is to handle Hot Peer load protection, when the Servers are
+ * 1) Static
+ * 2) Well known client URL
+ *
+ * The intention is to change traffic over to the Hot Peer, if a server goes down, and reinstate
+ * when it is back up.
+ *
+ * Example of this kind of Service is a MS Certificate Server
+ *
+ *
+ *
+ * @param <CLIENT>
+ */
+public abstract class HotPeerLocator<CLIENT> implements Locator<CLIENT> {
+ private final String[] urlstrs;
+ private final CLIENT[] clients;
+ private final long[] failures;
+ private final double[] distances;
+ private int preferred;
+ private long invalidateTime;
+ private Thread refreshThread;
+ protected Access access;
+
+ /**
+ * Construct: Expect one or more Strings in the form:
+ * 192.555.112.223:39/38.88087/-77.30122
+ * separated by commas
+ *
+ * @param trans
+ * @param urlstr
+ * @param invalidateTime
+ * @param localLatitude
+ * @param localLongitude
+ * @throws LocatorException
+ */
+ @SuppressWarnings("unchecked")
+ protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException {
+ this.access = access;
+ urlstrs = Split.split(',', urlstr);
+ clients = (CLIENT[])new Object[urlstrs.length];
+ failures = new long[urlstrs.length];
+ distances= new double[urlstrs.length];
+ this.invalidateTime = invalidateTime;
+
+ double distance = Double.MAX_VALUE;
+ for(int i=0;i<urlstrs.length;++i) {
+ String[] info = Split.split('/', urlstrs[i]);
+ if(info.length<3) {
+ throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long");
+ }
+ try {
+ clients[i] = _newClient(urlstrs[i]);
+ failures[i] = 0L;
+ } catch(LocatorException le) {
+ failures[i] = System.currentTimeMillis()+invalidateTime;
+ }
+
+ double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude);
+ distances[i]=d;
+
+ // find preferred server
+ if(d<distance) {
+ preferred = i;
+ distance=d;
+ }
+ }
+
+ access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]);
+ for(int i=0;i<urlstrs.length;++i) {
+ if(i!=preferred) {
+ access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]);
+ }
+ }
+ }
+
+ protected abstract CLIENT _newClient(String hostInfo) throws LocatorException;
+ /**
+ * If client can reconnect, then return. Otherwise, destroy and return null;
+ * @param client
+ * @return
+ * @throws LocatorException
+ */
+ protected abstract CLIENT _invalidate(CLIENT client);
+
+ protected abstract void _destroy(CLIENT client);
+
+ @Override
+ public Item best() throws LocatorException {
+ if(failures[preferred]==0L) {
+ return new HPItem(preferred);
+ } else {
+ long now = System.currentTimeMillis();
+ double d = Double.MAX_VALUE;
+ int best = -1;
+ boolean tickle = false;
+ // try for best existing client
+ for(int i=0;i<urlstrs.length;++i) {
+ if(failures[i]<now && distances[i]<d) {
+ if(clients[i]!=null) {
+ best = i;
+ break;
+ } else {
+ tickle = true; // There's some failed clients which can be restored
+ }
+ }
+ }
+ if(best<0 && tickle) {
+ tickle=false;
+ if(refresh()) {
+ // try again
+ for(int i=0;i<urlstrs.length;++i) {
+ if(failures[i]==0L && distances[i]<d) {
+ if(clients[i]!=null) {
+ best = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * If a valid client is available, but there are some that can refresh, return the client immediately
+ * but start a Thread to do the background Client setup.
+ */
+ if(tickle) {
+ synchronized(clients) {
+ if(refreshThread==null) {
+ refreshThread = new Thread(new Runnable(){
+ @Override
+ public void run() {
+ refresh();
+ refreshThread = null;
+ }
+ });
+ refreshThread.setDaemon(true);
+ refreshThread.start();
+ }
+ }
+ }
+
+ if(best<0) {
+ throw new LocatorException("No Clients available");
+ }
+
+
+ return new HPItem(best);
+ }
+ }
+
+
+ @Override
+ public CLIENT get(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ CLIENT c = clients[hpi.idx];
+ if(c==null) {
+ if(failures[hpi.idx]>System.currentTimeMillis()) {
+ throw new LocatorException("Client requested is invalid");
+ } else {
+ synchronized(clients) {
+ c = _newClient(urlstrs[hpi.idx]);
+ failures[hpi.idx]=0L;
+ }
+ }
+ } else if(failures[hpi.idx]>0){
+ throw new LocatorException("Client requested is invalid");
+ }
+ return c;
+ }
+
+ public String info(Item item) {
+ HPItem hpi = (HPItem)item;
+ if(hpi!=null && hpi.idx<urlstrs.length) {
+ return urlstrs[hpi.idx];
+ } else {
+ return "Invalid Item";
+ }
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]!=null && failures[i]==0L) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ failures[hpi.idx] = System.currentTimeMillis() + invalidateTime;
+ CLIENT c = clients[hpi.idx];
+ clients[hpi.idx] = _invalidate(c);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new HPItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ if(++hpi.idx>=clients.length) {
+ return null;
+ }
+ return hpi;
+ }
+
+ @Override
+ public boolean refresh() {
+ boolean force = !hasItems(); // If no Items at all, reset
+ boolean rv = true;
+ long now = System.currentTimeMillis();
+ for(int i=0;i<clients.length;++i) {
+ if(failures[i]>0L && (failures[i]<now || force)) { // retry
+ try {
+ synchronized(clients) {
+ if(clients[i]==null) {
+ clients[i]=_newClient(urlstrs[i]);
+ }
+ failures[i]=0L;
+ }
+ } catch (LocatorException e) {
+ failures[i]=now+invalidateTime;
+ rv = false;
+ }
+ }
+ }
+ return rv;
+ }
+
+ @Override
+ public void destroy() {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]!=null) {
+ _destroy(clients[i]);
+ clients[i] = null;
+ }
+ }
+ }
+
+ private static class HPItem implements Item {
+ private int idx;
+
+ public HPItem(int i) {
+ idx = i;
+ }
+ }
+
+
+ /*
+ * Convenience Functions
+ */
+ public CLIENT bestClient() throws LocatorException {
+ return get(best());
+ }
+
+ public boolean invalidate(CLIENT client) throws LocatorException {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference
+ invalidate(new HPItem(i));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
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
index 0000000..011e42c
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/PropertyLocator.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.security.SecureRandom;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.inno.env.util.Split;
+
+public class PropertyLocator implements Locator<URI> {
+ private final URI [] orig;
+ private PLItem[] current;
+ private int end;
+ private final SecureRandom random;
+ private URI[] resolved;
+ private long lastRefreshed=0L;
+ private long minRefresh;
+ private long backgroundRefresh;
+
+ public PropertyLocator(String locList) throws LocatorException {
+ this(locList,10000L, 1000*60*20); // defaults, do not refresh more than once in 10 seconds, Refresh Locator every 20 mins.
+ }
+ /**
+ * comma delimited root url list
+ *
+ * @param locList
+ * @throws LocatorException
+ */
+ public PropertyLocator(String locList, long minRefreshMillis, long backgroundRefreshMillis) throws LocatorException {
+ minRefresh = minRefreshMillis;
+ backgroundRefresh = backgroundRefreshMillis;
+ if(locList==null) {
+ throw new LocatorException("No Location List given for PropertyLocator");
+ }
+ String[] locarray = Split.split(',',locList);
+ List<URI> uriList = new ArrayList<URI>();
+
+ random = new SecureRandom();
+
+ for(int i=0;i<locarray.length;++i) {
+ try {
+ int range = locarray[i].indexOf(":[");
+ if(range<0) {
+ uriList.add(new URI(locarray[i]));
+ } else {
+ int dash = locarray[i].indexOf('-',range+2);
+ int brac = locarray[i].indexOf(']',dash+1);
+ int start = Integer.parseInt(locarray[i].substring(range+2, dash));
+ int end = Integer.parseInt(locarray[i].substring(dash+1, brac));
+ for(int port=start;port<=end;++port) {
+ uriList.add(new URI(locarray[i].substring(0, range+1)+port));
+ }
+ }
+ } catch (NumberFormatException nf) {
+ throw new LocatorException("Invalid URI format: " + locarray[i]);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+ orig = new URI[uriList.size()];
+ uriList.toArray(orig);
+
+ refresh();
+ new Timer("PropertyLocator Refresh Timer",true).scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ refresh();
+ }
+ }, backgroundRefresh,backgroundRefresh);
+
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ synchronized(orig) {
+ if(item==null) {
+ return null;
+ } else {
+ return resolved[((PLItem)item).idx];
+ }
+ }
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return end>0?current[0]:null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return end>0;
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ if(item==null) {
+ return null;
+ } else {
+ int spot;
+ if((spot=(((PLItem)item).order+1))>=end)return null;
+ return current[spot];
+ }
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ if(--end<=0) {
+ refresh();
+ return;
+ }
+ PLItem pli = (PLItem)item;
+ int i,order;
+ for(i=0;i<end;++i) {
+ if(pli==current[i])break;
+ }
+ order = current[i].order;
+ for(;i<end;++i) {
+ current[i]=current[i+1];
+ current[i].order=order++;
+ }
+ current[end]=pli;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ if(current.length==0) {
+ refresh();
+ }
+ switch(current.length) {
+ case 0:
+ return null;
+ case 1:
+ return current[0];
+ default:
+ return current[Math.abs(random.nextInt())%current.length];
+ }
+ }
+
+ @Override
+ public synchronized boolean refresh() {
+ if(System.currentTimeMillis()>lastRefreshed) {
+ // Build up list
+ List<URI> resolve = new ArrayList<URI>();
+ String realname;
+ for(int i = 0; i < orig.length ; ++i) {
+ try {
+ InetAddress ia[] = InetAddress.getAllByName(orig[i].getHost());
+
+ URI o,n;
+ for(int j=0;j<ia.length;++j) {
+ o = orig[i];
+ Socket socket = new Socket();
+ try {
+ realname=ia[j].getCanonicalHostName();
+ socket.connect(new InetSocketAddress(realname,o.getPort()),3000);
+ if(socket.isConnected()) {
+ n = new URI(
+ o.getScheme(),
+ o.getUserInfo(),
+ realname,
+ o.getPort(),
+ o.getPath(),
+ o.getQuery(),
+ o.getFragment()
+ );
+ resolve.add(n);
+ }
+ } catch (IOException e) {
+ } finally {
+ if(!socket.isClosed()) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // nothing to do.
+ }
+ }
+ }
+ }
+ } catch (UnknownHostException | URISyntaxException e) {
+ // Note: Orig Name already known as valid, based on constructor
+ }
+ }
+ end=resolve.size();
+ PLItem[] newCurrent;
+ if(current==null || current.length!=end) {
+ newCurrent = new PLItem[end];
+ } else {
+ newCurrent = current;
+ }
+
+ for(int i=0; i< end; ++i) {
+ if(newCurrent[i]==null){
+ newCurrent[i]=new PLItem(i);
+ } else {
+ newCurrent[i].idx=newCurrent[i].order=i;
+ }
+ }
+ synchronized(orig) {
+ resolved = new URI[end];
+ resolve.toArray(resolved);
+ current = newCurrent;
+ }
+ lastRefreshed = System.currentTimeMillis()+minRefresh;
+ return !resolve.isEmpty();
+ } else {
+ return false;
+ }
+ }
+
+ private class PLItem implements Item {
+ public int idx,order;
+
+ public PLItem(int i) {
+ idx = order =i;
+ }
+
+ public String toString() {
+ return "Item: " + idx + " order: " + order;
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(URI uri : orig) {
+ boolean isResolved=false;
+ if(uri!=null) {
+ if(first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(uri.toString());
+ sb.append(" [");
+ for(URI u2 : resolved) {
+ if(uri.equals(u2)) {
+ isResolved = true;
+ break;
+ }
+ }
+ sb.append(isResolved?"X]\n":" ]");
+ }
+ }
+ return sb.toString();
+ }
+
+ public void destroy() {
+ }
+}
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
index 0000000..5a58920
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/routing/GreatCircle.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.routing;
+
+import com.att.inno.env.util.Split;
+
+public class GreatCircle {
+ // Note: multiplying by this constant is faster than calling Math equivalent function
+ private static final double DEGREES_2_RADIANS = Math.PI/180.0;
+
+ public static final double DEGREES_2_NM = 60;
+ public static final double DEGREES_2_KM = DEGREES_2_NM * 1.852; // 1.852 is exact ratio per 1929 Standard Treaty, adopted US 1954
+ public static final double DEGREES_2_MI = DEGREES_2_NM * 1.1507795;
+
+ /**
+ *
+ * Calculate the length of an arc on a perfect sphere based on Latitude and Longitudes of two points
+ * Parameters are in Degrees (i.e. the coordinate system you get from GPS, Mapping WebSites, Phones, etc)
+ *
+ * L1 = Latitude of point A
+ * G1 = Longitude of point A
+ * L2 = Latitude of point B
+ * G2 = Longitude of point B
+ *
+ * d = acos (sin(L1)*sin(L2) + cos(L1)*cos(L2)*cos(G1 - G2))
+ *
+ * Returns answer in Degrees
+ *
+ * Since there are 60 degrees per nautical miles, you can convert to NM by multiplying by 60
+ *
+ * Essential formula from a Princeton website, the "Law of Cosines" method.
+ *
+ * Refactored cleaned up for speed 3/8/2013
+ *
+ * @param latA
+ * @param lonA
+ * @param latB
+ * @param lonB
+ * @return
+ */
+ public static double calc(double latA, double lonA, double latB, double lonB) {
+ // Formula requires Radians. Expect Params to be Coordinates (Degrees)
+ // Simple ratio, quicker than calling Math.toRadians()
+ latA *= DEGREES_2_RADIANS;
+ lonA *= DEGREES_2_RADIANS;
+ latB *= DEGREES_2_RADIANS;
+ lonB *= DEGREES_2_RADIANS;
+
+ return Math.acos(
+ Math.sin(latA) * Math.sin(latB) +
+ Math.cos(latA) * Math.cos(latB) * Math.cos(lonA-lonB)
+ )
+ / DEGREES_2_RADIANS;
+ }
+
+ /**
+ * Convert from "Lat,Long Lat,Long" String format
+ * "Lat,Long,Lat,Long" Format
+ * or all four entries "Lat Long Lat Long"
+ *
+ * (Convenience function)
+ *
+ * Since Distance is positive, a "-1" indicates an error in String formatting
+ */
+ public static double calc(String ... coords) {
+ try {
+ String [] array;
+ switch(coords.length) {
+ case 1:
+ array = Split.split(',',coords[0]);
+ if(array.length!=4)return -1;
+ return calc(
+ Double.parseDouble(array[0]),
+ Double.parseDouble(array[1]),
+ Double.parseDouble(array[2]),
+ Double.parseDouble(array[3])
+ );
+ case 2:
+ array = Split.split(',',coords[0]);
+ String [] array2 = Split.split(',',coords[1]);
+ if(array.length!=2 || array2.length!=2)return -1;
+ return calc(
+ Double.parseDouble(array[0]),
+ Double.parseDouble(array[1]),
+ Double.parseDouble(array2[0]),
+ Double.parseDouble(array2[1])
+ );
+ case 4:
+ return calc(
+ Double.parseDouble(coords[0]),
+ Double.parseDouble(coords[1]),
+ Double.parseDouble(coords[2]),
+ Double.parseDouble(coords[3])
+ );
+
+ default:
+ return -1;
+ }
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
+}
+
+///**
+//* Haverside method, from Princeton
+//*
+//* @param alat
+//* @param alon
+//* @param blat
+//* @param blon
+//* @return
+//*/
+//public static double calc3(double alat, double alon, double blat, double blon) {
+// alat *= DEGREES_2_RADIANS;
+// alon *= DEGREES_2_RADIANS;
+// blat *= DEGREES_2_RADIANS;
+// blon *= DEGREES_2_RADIANS;
+// return 2 * Math.asin(
+// Math.min(1, Math.sqrt(
+// Math.pow(Math.sin((blat-alat)/2), 2) +
+// (Math.cos(alat)*Math.cos(blat)*
+// Math.pow(
+// Math.sin((blon-alon)/2),2)
+// )
+// )
+// )
+// )
+// / DEGREES_2_RADIANS;
+//}
+//
+
+
+
+//This is a MEAN radius. The Earth is not perfectly spherical
+// public static final double EARTH_RADIUS_KM = 6371.0;
+// public static final double EARTH_RADIUS_NM = 3440.07;
+// public static final double KM_2_MILES_RATIO = 0.621371192;
+///**
+//* Code on Internet based on Unknown book. Lat/Long is in Degrees
+//* @param alat
+//* @param alon
+//* @param blat
+//* @param blon
+//* @return
+//*/
+//public static double calc1(double alat, double alon, double blat, double blon) {
+// alat *= DEGREES_2_RADIANS;
+// alon *= DEGREES_2_RADIANS;
+// blat *= DEGREES_2_RADIANS;
+// blon *= DEGREES_2_RADIANS;
+//
+// // Reused values
+// double cosAlat,cosBlat;
+//
+// return Math.acos(
+// ((cosAlat=Math.cos(alat))*Math.cos(alon)*(cosBlat=Math.cos(blat))*Math.cos(blon)) +
+// (cosAlat*Math.sin(alon)*cosBlat*Math.sin(blon)) +
+// (Math.sin(alat)*Math.sin(blat))
+// )/DEGREES_2_RADIANS;
+//
+//}
+
+/*
+* This method was 50% faster than calculation 1, and 75% than the Haverside method
+* Also, since it's based off of Agree standard Degrees of the Earth, etc, the calculations are more exact,
+* at least for Nautical Miles and Kilometers
+*/
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
index 0000000..a7b2f41
--- /dev/null
+++ b/client/src/test/java/com/client/test/BasicDME2Client.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.net.URI;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Manager;
+
+public class BasicDME2Client {
+ public static void main(String[] args) {
+ try {
+ Properties props = System.getProperties();
+
+ DME2Manager dm = new DME2Manager("DME2Manager TestBasicDME2Client",props);
+ URI uri = new URI(System.getProperty("aaf_url"));
+ DME2Client client = new DME2Client(dm,uri,3000);
+
+ System.out.println(props.getProperty("aaf_id"));
+ client.setCredentials(props.getProperty("aaf_id"),props.getProperty("aaf_password"));
+
+ String path = String.format("/authz/perms/user/%s@csp.att.com",args.length>0?args[0]:"xx9999");
+ System.out.printf("Path: %s\n",path);
+ client.addHeader("Accept", "application/Perms+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*");
+ client.setMethod("GET");
+ client.setContext(path);
+ client.setPayload("");// Note: Even on "GET", you need a String in DME2
+
+ String o = client.sendAndWait(5000); // There are other Asynchronous call options, see DME2 Docs
+ if(o==null) {
+ System.out.println('[' + o + ']' + " (blank is good)");
+ }
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
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
index 0000000..fcd14c8
--- /dev/null
+++ b/client/src/test/java/com/client/test/JU_DNSLocator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import com.att.cadi.locator.DNSLocator;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Locator.Item;
+
+public class JU_DNSLocator {
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() {
+
+ DNSLocator dl = new DNSLocator(new PropAccess(), "https", "aaf.it.att.com","8150-8152");
+ try {
+ Item item = dl.best();
+ URI uri = dl.get(item);
+ URL url = uri.toURL();
+ URLConnection conn = url.openConnection();
+ conn.connect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
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
index 0000000..be8e587
--- /dev/null
+++ b/client/src/test/java/com/client/test/JU_PropertyLocator.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.net.URI;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import com.att.cadi.Locator.Item;
+import com.att.cadi.locator.PropertyLocator;
+
+public class JU_PropertyLocator {
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() throws Exception {
+ PropertyLocator pl = new PropertyLocator("https://localhost:2345,https://fred.wilma.com:26444,https://tom.jerry.com:534");
+
+ Item i;
+ int count;
+ boolean print = false;
+ for(int j=0;j<900000;++j) {
+ count = 0;
+ for(i = pl.first();i!=null;i=pl.next(i)) {
+ URI loc = pl.get(i);
+ if(print)System.out.println(loc.toString());
+ ++count;
+ }
+ assertEquals(3,count);
+ assertTrue(pl.hasItems());
+ if(print)System.out.println("---");
+ pl.invalidate(pl.best());
+
+ count = 0;
+ for(i = pl.first();i!=null;i=pl.next(i)) {
+ URI loc = pl.get(i);
+ if(print)System.out.println(loc.toString());
+ ++count;
+ }
+
+ assertEquals(2,count);
+ assertTrue(pl.hasItems());
+ if(print)System.out.println("---");
+ pl.invalidate(pl.best());
+
+ count = 0;
+ for(i = pl.first();i!=null;i=pl.next(i)) {
+ URI loc = pl.get(i);
+ if(print)System.out.println(loc.toString());
+ ++count;
+ }
+
+ assertEquals(1,count);
+ assertTrue(pl.hasItems());
+ if(print)System.out.println("---");
+ pl.invalidate(pl.best());
+
+ count = 0;
+ for(i = pl.first();i!=null;i=pl.next(i)) {
+ URI loc = pl.get(i);
+ if(print)System.out.println(loc.toString());
+ ++count;
+ }
+
+ assertEquals(0,count);
+ assertFalse(pl.hasItems());
+
+ pl.refresh();
+ }
+ }
+
+}
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
index 0000000..6f82146
--- /dev/null
+++ b/client/src/test/java/com/client/test/PaulUzee.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.URI;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Access;
+import com.att.cadi.Locator;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.dme2.DME2Locator;
+
+public class PaulUzee {
+ public static void main(String[] args) {
+ try {
+ // You'll want to put this on Command line "-D" probably
+ Properties props = System.getProperties();
+ props.put("AFT_LATITUDE","32.780140");
+ props.put("AFT_LONGITUDE","-96.800451");
+ props.put("AFT_ENVIRONMENT","AFTPRD");
+
+ //
+ // Use an "Access" class to hook up logging, properties, etc.
+ // Make one that ties into your code's logging, property mechanism, etc.
+ //
+ Access access = new PaulAccess();
+
+ DME2Manager dm = new DME2Manager("Paul Uzee's Test",props);
+ Locator loc = new DME2Locator(access ,dm,"com.att.authz.AuthorizationService","2.0","PROD","DEFAULT");
+
+
+ for(Item item = loc.first(); item!=null; item=loc.next(item)) {
+ URI location = (URI) loc.get(item);
+ access.log(Level.INFO,location);
+ access.log(Level.INFO,location.getScheme());
+ access.log(Level.INFO,location.getHost());
+ access.log(Level.INFO, location.getPort());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private static class PaulAccess implements Access {
+ private Level willWrite = Level.INFO;
+
+ @Override
+ public ClassLoader classLoader() {
+ return getClass().getClassLoader();
+ }
+
+ @Override
+ public String decrypt(String data, boolean def) throws IOException {
+ return data;
+ }
+
+ @Override
+ public String getProperty(String tag, String def) {
+ return System.getProperty(tag, def);
+ }
+
+ @Override
+ public void load(InputStream is) throws IOException {
+ System.getProperties().load(is);
+ }
+
+ @Override
+ public void log(Level level, Object... obj) {
+ if(level.compareTo(willWrite)<0) return;
+ PrintStream ps;
+ switch(level) {
+ case DEBUG:
+ case AUDIT:
+ case ERROR:
+ case WARN:
+ ps = System.err;
+ break;
+ case INFO:
+ case INIT:
+ default:
+ ps = System.out;
+ }
+ boolean first = true;
+ for(Object o : obj) {
+ if(first)first=false;
+ else ps.print(' ');
+ ps.print(o.toString());
+ }
+ ps.println();
+ }
+
+ @Override
+ public void log(Exception e, Object... obj) {
+ Object[] objs = new Object[obj.length+1];
+ objs[0]=e.getMessage();
+ System.arraycopy(objs, 1, obj, 0, obj.length);
+ log(Level.ERROR,e,objs);
+ }
+
+ @Override
+ public void setLogLevel(Level l) {
+ willWrite = l;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)
+ */
+ @Override
+ public boolean willLog(Level level) {
+ return true;
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ // TODO Auto-generated method stub
+
+ }
+ };
+}
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
index 0000000..3724f1b
--- /dev/null
+++ b/client/src/test/java/com/client/test/TestAccess.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+
+public class TestAccess implements Access {
+ private Symm symm;
+
+ public TestAccess() {
+ symm = Symm.obtain(this);
+ }
+
+ public void log(Level level, Object... elements) {
+ boolean first = true;
+ for(int i=0;i<elements.length;++i) {
+ if(first)first = false;
+ else System.out.print(' ');
+ System.out.print(elements[i].toString());
+ }
+ System.out.println();
+ }
+
+ public void log(Exception e, Object... elements) {
+ e.printStackTrace();
+ log(Level.ERROR,elements);
+ }
+
+ public void setLogLevel(Level level) {
+
+ }
+
+ public ClassLoader classLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ public String getProperty(String string, String def) {
+ String rv = System.getProperty(string);
+ return rv==null?def:rv;
+ }
+
+ public void load(InputStream is) throws IOException {
+
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)
+ */
+ @Override
+ public boolean willLog(Level level) {
+ return true;
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..5e5e822
--- /dev/null
+++ b/client/src/test/java/com/client/test/TestDME2Client.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.io.FileInputStream;
+import java.net.URI;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Symm;
+
+public class TestDME2Client {
+ public static void main(String[] args) {
+ try {
+ Properties props = System.getProperties();
+ props.put("AFT_LATITUDE","32.780140");
+ props.put("AFT_LONGITUDE","-96.800451");
+ props.put("AFT_ENVIRONMENT","AFTUAT");
+
+ //props.put("keyStore","/Volumes/Data/src/authz/common/aaf.att.jks");
+ props.put("AFT_DME2_KEYSTORE","/Volumes/Data/src/authz/common/aaf.att.jks");
+ props.put("AFT_DME2_KEYSTORE_PASSWORD","enc:???");
+ props.put("AFT_DME2_TRUSTSTORE","/Volumes/Data/src/authz/common/truststore.jks");
+ props.put("AFT_DME2_TRUSTSTORE_PASSWORD","enc:???");
+
+ // Local Testing on dynamic IP PC ***ONLY***
+// props.put("DME2_EP_REGISTRY_CLASS","DME2FS");
+// props.put("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");
+// props.put("AFT_DME2_SSL_TRUST_ALL", "true");
+
+ Symm symm;
+ FileInputStream keyfile=new FileInputStream("/Volumes/Data/src/authz/common/keyfile");
+ try {
+ symm=Symm.obtain(keyfile);
+ } finally {
+ keyfile.close();
+ }
+
+ DME2Manager dm = new DME2Manager("DME2Manager TestHClient",props);
+ // Standard RESOLVE format
+ String prefix;
+ URI uri =
+// new URI(
+// "https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE"
+// );
+// prefix = "";
+// Direct Format
+// new URI("https://mithrilcsp.sbc.com:8100/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");
+// prefix = "";
+// Go through PROXY
+// new URI("https://mithrilcsp.sbc.com:8095");
+// prefix = "/proxy";
+
+// new URI("https://mithrilcsp.sbc.com:8095");
+ new URI("https://DME2RESOLVE/service=com.att.authz.authz-gw/version=2.0/envContext=UAT/routeOffer=BAU_SE");
+// prefix = "";
+ prefix = "/proxy";
+ DME2Client client = new DME2Client(dm,uri,3000);
+
+ client.setCredentials("XX@NS", symm.depass("enc:???"));
+
+ client.addHeader("Accept", "text/plain");
+ client.setMethod("GET");
+ client.setContext(prefix+"/authn/basicAuth");
+ client.setPayload("");// Note: Even on "GET", you need a String in DME2
+
+ String o = client.sendAndWait(5000); // There are other Asynchronous call options, see DME2 Docs
+
+ System.out.println('[' + o + ']' + " (blank is good)");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
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
index 0000000..61bc76a
--- /dev/null
+++ b/client/src/test/java/com/client/test/TestDME2RcliClient.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.net.URI;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Access;
+import com.att.cadi.client.Future;
+import com.att.cadi.dme2.DME2ClientSS;
+import com.att.cadi.dme2.DRcli;
+
+public class TestDME2RcliClient {
+ public static void main(String[] args) {
+ try {
+ Properties props = System.getProperties();
+ props.put("AFT_LATITUDE","32.780140");
+ props.put("AFT_LONGITUDE","-96.800451");
+ props.put("AFT_ENVIRONMENT","AFTUAT");
+// props.put("DME2_EP_REGISTRY_CLASS","DME2FS");
+// props.put("AFT_DME2_EP_REGISTRY_FS_DIR","/Volumes/Data/src/authz/dme2reg");
+
+ props.put("cadi_keystore","/Volumes/Data/src/authz/common/aaf.att.jks");
+ props.put("cadi_keystore_password","enc:???");
+ props.put("cadi_truststore","/Volumes/Data/src/authz/common/truststore.jks");
+ props.put("cadi_truststore_password","enc:???");
+ props.put("cadi_keyfile", "/Volumes/Data/src/authz/common/keyfile");
+
+ // Local Testing on dynamic IP PC ***ONLY***
+// props.put("cadi_trust_all_x509", "true");
+
+
+
+ URI uri = new URI("https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");
+
+ Access access = new TestAccess();
+ DME2Manager dm = new DME2Manager("DME2Manager TestHClient",props);
+ DRcli client = new DRcli(
+ uri,
+ new DME2ClientSS(access,"XX@NS","enc:???"));
+
+ client.setManager(dm)
+ .apiVersion("2.0")
+ .readTimeout(3000);
+
+ Future<String> ft = client.read("/authz/nss/com.att.aaf","text/json");
+ if(ft.get(10000)) {
+ System.out.println("Hurray,\n"+ft.body());
+ } else {
+ System.out.println("not quite: " + ft.code());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
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
index 0000000..0c6a162
--- /dev/null
+++ b/client/src/test/java/com/client/test/TestHClient.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.client.test;
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.locator.DME2Locator;
+import com.att.inno.env.APIException;
+
+public class TestHClient {
+ public static void main(String[] args) {
+ try {
+ PropAccess access = new PropAccess();
+ DME2Manager dm = new DME2Manager("DME2Manager TestHClient",access.getProperties());
+ Locator<URI> loc = new DME2Locator(access,dm,"com.att.authz.AuthorizationService","2.0","DEV","BAU_SE");
+
+ for(Item item = loc.first(); item!=null; item=loc.next(item)) {
+ System.out.println(loc.get(item));
+ }
+
+
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ SecuritySetter<HttpURLConnection> ss = new HBasicAuthSS("m12345@aaf.att.com",
+ access.decrypt("enc:7K6yjLQqha_S9yApkIul2K_by5Moemcos1HRAVnhMXu",false), si);
+// SecuritySetter<HttpURLConnection> ss = new X509SS(si, "aaf");
+
+ HMangr hman = new HMangr(access,loc);
+ try {
+ hman.best(ss, new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> cli) throws APIException, CadiException {
+ Future<String> ft = cli.read("/authz/nss/com.att.aaf","text/json");
+ if(ft.get(10000)) {
+ System.out.println("Hurray,\n"+ft.body());
+ } else {
+ System.out.println("not quite: " + ft.code());
+ }
+ return null;
+ }});
+ } finally {
+ hman.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/core/.gitignore b/core/.gitignore
new file mode 100644
index 0000000..cf85207
--- /dev/null
+++ b/core/.gitignore
@@ -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
index 0000000..d60fc23
--- /dev/null
+++ b/core/conf/cadi.properties
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------------
+# ============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.
+# *
+#-------------------------------------------------------------------------------
+###############################################################################
+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
+###############################################################################
+# This is a normal Java Properties File
+# Comments are with Pound Signs at beginning of lines,
+# and multi-line expression of properties can be obtained by backslash at end of line
+
+# Certain machines have several possible machine names, and
+# the right one may not be reported. This is especially
+# important for CSP Authorization, which will only
+# function on official AT&T domains.
+hostname=veeger.mo.sbc.com
+
+port=2533
+
+# CSP has Production mode (active users) or DEVL mode (for
+# Testing purposes... Bogus users)
+#csp_domain=DEVL
+csp_domain=PROD
+
+# Report all AUTHN and AUTHZ activity
+loglevel=AUDIT
+
+#
+# BasicAuth and other User/Password support
+#
+# The realm reported on BasicAuth callbacks
+basic_realm=spiderman.agile.att.com
+users=ks%xiVUs_25_1jqGdJ24hqy43Gi;
+groups=aaf:Jd8bb3jslg88b@spiderman.agile.att.com%7sZCPBZ_8iWbslqdjWFIDLgTZlm9ung0ym-G,\
+ jg1555,lg2384,rd8227,tp007s,pe3617;
+
+
+# Keyfile (with relative path) for encryption. This file
+# should be marked as ReadOnly by Only the running process
+# for security's sake
+keyfile=conf/keyfile
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..15c7e63
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,131 @@
+<!--
+ ============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">
+ <parent>
+ <groupId>com.att.cadi</groupId>
+ <artifactId>parent</artifactId>
+ <relativePath>..</relativePath>
+ <version>1.3.2</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <name>CADI Core Framework (Code, Access, Data, Identity)</name>
+ <artifactId>cadi-core</artifactId>
+ <packaging>jar</packaging>
+ <url>https://github.com/att/AAF</url>
+ <description>CADI</description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <!-- Must put this in to turn on Signing, but Configuration itself is
+ in Parent -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jarsigner-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>com.att.cadi.CmdLine</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Sealed>true</Sealed>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>test-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </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>
+ </plugins>
+ </build>
+
+</project>
diff --git a/core/src/assemble/cadi.xml b/core/src/assemble/cadi.xml
new file mode 100644
index 0000000..0bbb8e8
--- /dev/null
+++ b/core/src/assemble/cadi.xml
@@ -0,0 +1,47 @@
+<!--
+ ============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.
+ *
+-->
+<assembly>
+ <id>test</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory></outputDirectory>
+ <outputFileNameMapping></outputFileNameMapping>
+ <unpack>true</unpack>
+ <scope>runtime</scope>
+ <!-- includes>
+ <include>com.att.cssa:env*</include>
+ </includes -->
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>target/classes</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/core/src/assemble/poll.xml b/core/src/assemble/poll.xml
new file mode 100644
index 0000000..c33dd83
--- /dev/null
+++ b/core/src/assemble/poll.xml
@@ -0,0 +1,47 @@
+<!--
+ ============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.
+ *
+-->
+<assembly>
+ <id>app</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory></outputDirectory>
+ <outputFileNameMapping></outputFileNameMapping>
+ <unpack>true</unpack>
+ <scope>runtime</scope>
+ <!-- includes>
+ <include>web</include>
+ </includes -->
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>target/classes</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
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
index 0000000..4041ae5
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/AES.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.att.cadi.util.Chmod;
+
+public class AES {
+ public static final String AES = AES.class.getSimpleName();
+ public static final int AES_KEY_SIZE = 128; // 256 isn't supported on all JDKs.
+
+ private Cipher aesCipher;
+ private SecretKeySpec aeskeySpec;
+
+ public AES() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
+ aesCipher = Cipher.getInstance(AES);
+ aeskeySpec = new SecretKeySpec(newKey().getEncoded(), AES);
+ }
+
+ public static SecretKey newKey() throws NoSuchAlgorithmException {
+ KeyGenerator kgen = KeyGenerator.getInstance(AES);
+ kgen.init(AES_KEY_SIZE);
+ return kgen.generateKey();
+ }
+
+ public AES(File keyfile) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
+ aesCipher = Cipher.getInstance(AES);
+ byte[] aesKey = new byte[AES_KEY_SIZE/8];
+ FileInputStream fis = new FileInputStream(keyfile);
+ try {
+ fis.read(aesKey);
+ } finally {
+ fis.close();
+ }
+ aeskeySpec = new SecretKeySpec(aesKey,AES);
+ }
+
+ public AES(byte[] aeskey, int offset, int len) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
+ aesCipher = Cipher.getInstance(AES);
+ aeskeySpec = new SecretKeySpec(aeskey,offset,len,AES);
+ }
+
+ public byte[] encrypt(byte[] in) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+ aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);
+ return aesCipher.doFinal(in);
+ }
+
+ public byte[] decrypt(byte[] in) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+ aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec);
+ return aesCipher.doFinal(in);
+ }
+
+ public void save(File keyfile) throws IOException {
+ FileOutputStream fis = new FileOutputStream(keyfile);
+ try {
+ fis.write(aeskeySpec.getEncoded());
+ } finally {
+ fis.close();
+ }
+ Chmod.to400.chmod(keyfile);
+ }
+
+ public CipherOutputStream outputStream(OutputStream os, boolean encrypt) {
+ try {
+ if(encrypt) {
+ aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);
+ } else {
+ aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec);
+ }
+ } catch (InvalidKeyException e) {
+ // KeySpec created earlier... no chance being wrong.
+ }
+ return new CipherOutputStream(os,aesCipher);
+ }
+
+ public CipherInputStream inputStream(InputStream is, boolean encrypt) {
+ try {
+ if(encrypt) {
+ aesCipher.init(Cipher.ENCRYPT_MODE,aeskeySpec);
+ } else {
+ aesCipher.init(Cipher.DECRYPT_MODE,aeskeySpec);
+ }
+ } catch (InvalidKeyException e) {
+ // KeySpec created earlier... no chance being wrong.
+ }
+
+ return new CipherInputStream(is,aesCipher);
+ }
+}
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
index 0000000..bb76e3d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/AbsCachedPrincipal.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+public abstract class AbsCachedPrincipal<TAF> implements CachedPrincipal {
+ protected TAF taf;
+
+ protected AbsCachedPrincipal(TAF taf) {
+ this.taf = taf;
+ }
+
+}
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
index 0000000..0229a71
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/AbsUserCache.java
@@ -0,0 +1,409 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal.Resp;
+
+/**
+ * Implement Fast lookup and Cache for Local User Info
+ *
+ * Include ability to add and remove Users
+ *
+ * Also includes a Timer Thread (when necessary) to invoke cleanup on expiring Credentials
+ *
+ *
+ */
+public abstract class AbsUserCache<PERM extends Permission> {
+ static final int MIN_INTERVAL = 15000;
+ static final int MAX_INTERVAL = 1000*60*5; // 5 mins
+ private static Timer timer;
+ // Map of userName to User
+ private final Map<String, User<PERM>> userMap;
+ private final Map<String, Miss> missMap;
+ private Clean clean;
+ protected Access access;
+// private final static Permission teaser = new LocalPermission("***NoPERM****");
+
+ protected AbsUserCache(Access access, long cleanInterval, int highCount, int usageCount) {
+ this.access = access;
+ userMap = new ConcurrentHashMap<String, User<PERM>>();
+ missMap = new TreeMap<String,Miss>();
+ if(cleanInterval>0) {
+ cleanInterval = Math.max(MIN_INTERVAL, cleanInterval);
+ synchronized(AbsUserCache.class) { // Lazy instantiate.. in case there is no cleanup needed
+ if(timer==null) {
+ timer = new Timer("CADI Cleanup Timer",true);
+ }
+
+ timer.schedule(clean = new Clean(access, cleanInterval, highCount, usageCount), cleanInterval, cleanInterval);
+ access.log(Access.Level.INIT, "Cleaning Thread initialized with interval of",cleanInterval, "ms and max objects of", highCount);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public AbsUserCache(AbsUserCache<PERM> cache) {
+ this.access = cache.access;
+ userMap = cache.userMap;
+ missMap = cache.missMap;
+ synchronized(AbsUserCache.class) {
+ if(cache.clean!=null && cache.clean.lur==null && this instanceof CachingLur) {
+ cache.clean.lur=(CachingLur<PERM>)this;
+ }
+ }
+ }
+
+ protected void setLur(CachingLur<PERM> lur) {
+ if(clean!=null)clean.lur = lur;
+
+ }
+
+ protected void addUser(User<PERM> user) {
+ userMap.put(user.principal.getName(), user);
+ }
+
+ // Useful for looking up by WebToken, etc.
+ protected void addUser(String key, User<PERM> user) {
+ userMap.put(key, user);
+ }
+
+ /**
+ * Add miss to missMap. If Miss exists, or too many tries, returns false.
+ *
+ * otherwise, returns true to allow another attempt.
+ *
+ * @param key
+ * @param bs
+ * @return
+ */
+ protected boolean addMiss(String key, byte[] bs) {
+ Miss miss = missMap.get(key);
+ if(miss==null) {
+ synchronized(missMap) {
+ missMap.put(key, new Miss(bs,clean==null?MIN_INTERVAL:clean.timeInterval));
+ }
+ return true;
+ }
+ return miss.add(bs);
+ }
+
+ protected Miss missed(String key) {
+ return missMap.get(key);
+ }
+
+ protected User<PERM> getUser(String userName) {
+ User<PERM> u = userMap.get(userName);
+ if(u!=null) {
+ u.incCount();
+ }
+ return u;
+ }
+
+ protected User<PERM> getUser(Principal principal) {
+ return getUser(principal.getName());
+ }
+
+ /**
+ * Removes User from the Cache
+ * @param user
+ */
+ protected void remove(User<PERM> user) {
+ userMap.remove(user.principal.getName());
+ }
+
+ /**
+ * Removes user from the Cache
+ *
+ * @param user
+ */
+ public void remove(String user) {
+ Object o = userMap.remove(user);
+ if(o!=null) {
+ access.log(Level.INFO, user,"removed from Client Cache by Request");
+ }
+ }
+
+ /**
+ * Clear all users from the Client Cache
+ */
+ public void clearAll() {
+ userMap.clear();
+ }
+
+ public final List<DumpInfo> dumpInfo() {
+ List<DumpInfo> rv = new ArrayList<DumpInfo>();
+ for(User<PERM> user : userMap.values()) {
+ rv.add(new DumpInfo(user));
+ }
+ return rv;
+ }
+
+ /**
+ * The default behavior of a LUR is to not handle something exclusively.
+ */
+ public boolean handlesExclusively(Permission pond) {
+ return false;
+ }
+
+ /**
+ * Container calls when cleaning up...
+ *
+ * If overloading in Derived class, be sure to call "super.destroy()"
+ */
+ public void destroy() {
+ if(timer!=null) {
+ timer.purge();
+ timer.cancel();
+ }
+ }
+
+
+
+ // Simple map of Group name to a set of User Names
+ // private Map<String, Set<String>> groupMap = new HashMap<String, Set<String>>();
+
+ /**
+ * Class to hold a small subset of the data, because we don't want to expose actual Permission or User Objects
+ */
+ public final class DumpInfo {
+ public String user;
+ public List<String> perms;
+
+ public DumpInfo(User<PERM> user) {
+ this.user = user.principal.getName();
+ perms = new ArrayList<String>(user.perms.keySet());
+ }
+ }
+
+ /**
+ * Clean will examine resources, and remove those that have expired.
+ *
+ * If "highs" have been exceeded, then we'll expire 10% more the next time. This will adjust after each run
+ * without checking contents more than once, making a good average "high" in the minimum speed.
+ *
+ *
+ */
+ private final class Clean extends TimerTask {
+ private final Access access;
+ private CachingLur<PERM> lur;
+
+ // The idea here is to not be too restrictive on a high, but to Expire more items by
+ // shortening the time to expire. This is done by judiciously incrementing "advance"
+ // when the "highs" are exceeded. This effectively reduces numbers of cached items quickly.
+ private final int high;
+ private long advance;
+ private final long timeInterval;
+ private final int usageTriggerCount;
+
+ public Clean(Access access, long cleanInterval, int highCount, int usageTriggerCount) {
+ this.access = access;
+ lur = null;
+ high = highCount;
+ timeInterval = cleanInterval;
+ advance = 0;
+ this.usageTriggerCount=usageTriggerCount;
+ }
+ public void run() {
+ int renewed = 0;
+ int count = 0;
+ int total = 0;
+ try {
+ // look at now. If we need to expire more by increasing "now" by "advance"
+ ArrayList<User<PERM>> al = new ArrayList<User<PERM>>(userMap.values().size());
+ al.addAll(0, userMap.values());
+ long now = System.currentTimeMillis() + advance;
+ for(User<PERM> user : al) {
+ ++total;
+ if(user.count>usageTriggerCount) {
+ // access.log(Level.AUDIT, "Checking Thread", new Date(now));
+ boolean touched = false, removed=false;
+ if(user.principal instanceof CachedPrincipal) {
+ CachedPrincipal cp = (CachedPrincipal)user.principal;
+ if(cp.expires() < now) {
+ switch(cp.revalidate()) {
+ case INACCESSIBLE:
+ access.log(Level.AUDIT, "AAF Inaccessible. Keeping credentials");
+ break;
+ case REVALIDATED:
+ user.resetCount();
+ // access.log(Level.AUDIT, "CACHE revalidated credentials");
+ touched = true;
+ break;
+ default:
+ user.resetCount();
+ remove(user);
+ ++count;
+ removed = true;
+ break;
+ }
+ }
+ }
+
+ // access.log(Level.AUDIT, "User Perm Expires", new Date(user.permExpires));
+ if(!removed && lur!=null && user.permExpires<= now ) {
+ // access.log(Level.AUDIT, "Reloading");
+ if(lur.reload(user).equals(Resp.REVALIDATED)) {
+ user.renewPerm();
+ access.log(Level.DEBUG, "Reloaded Perms for",user);
+ touched = true;
+ }
+ }
+ user.resetCount();
+ if(touched) {
+ ++renewed;
+ }
+
+ } else {
+ if(user.permExpired()) {
+ remove(user);
+ ++count;
+ }
+ }
+ }
+
+ // Clean out Misses
+ int missTotal = missMap.keySet().size();
+ int miss = 0;
+ if(missTotal>0) {
+ ArrayList<String> keys = new ArrayList<String>(missTotal);
+ keys.addAll(missMap.keySet());
+ for(String key : keys) {
+ Miss m = missMap.get(key);
+ if(m!=null && m.timestamp<System.currentTimeMillis()) {
+ synchronized(missMap) {
+ missMap.remove(key);
+ }
+ access.log(Level.INFO, key, "has been removed from Missed Credential Map (" + m.tries + " invalid tries)");
+ ++miss;
+ }
+ }
+ }
+
+ if(count+renewed+miss>0) {
+ access.log(Level.INFO, (lur==null?"Cache":lur.getClass().getSimpleName()), "removed",count,
+ "and renewed",renewed,"expired Permissions out of", total,"and removed", miss, "password misses out of",missTotal);
+ }
+
+ // If High (total) is reached during this period, increase the number of expired services removed for next time.
+ // There's no point doing it again here, as there should have been cleaned items.
+ if(total>high) {
+ // advance cleanup by 10%, without getting greater than timeInterval.
+ advance = Math.min(timeInterval, advance+(timeInterval/10));
+ } else {
+ // reduce advance by 10%, without getting lower than 0.
+ advance = Math.max(0, advance-(timeInterval/10));
+ }
+ } catch (Exception e) {
+ access.log(Level.ERROR,e.getMessage());
+ }
+ }
+ }
+
+ public static class Miss {
+ private static final int MAX_TRIES = 3;
+
+ long timestamp;
+ byte[][] array;
+
+ private long timetolive;
+
+ private int tries;
+
+ public Miss(byte[] first, long timeInterval) {
+ array = new byte[MAX_TRIES][];
+ array[0]=first;
+ timestamp = System.currentTimeMillis() + timeInterval;
+ this.timetolive = timeInterval;
+ tries = 1;
+ }
+
+ public boolean mayContinue(byte[] bs) {
+ if(++tries > MAX_TRIES) return false;
+ for(byte[] a : array) {
+ if(a==null)return true;
+ if(equals(a,bs)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public synchronized boolean add(byte[] bc) {
+ if(++tries>MAX_TRIES)return false;
+ timestamp = System.currentTimeMillis()+timetolive;
+ for(int i=0;i<MAX_TRIES;++i) {
+ if(array[i]==null) {
+ array[i]=bc;
+ return true; // add to array, and allow more tries
+ } else if(equals(array[i],bc)) {
+ return false;
+ }
+ }
+ return false; // no more tries until cache cleared.
+ }
+
+ private boolean equals(byte[] src, byte[] target) {
+ if(target.length==src.length) {
+ for(int j=0;j<src.length;++j) {
+ if(src[j]!=target[j]) return false;
+ }
+ return true; // same length and same chars
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Report on state
+ */
+ public String toString() {
+ return getClass().getSimpleName() +
+ " Cache:\n Users Cached: " +
+ userMap.size() +
+ "\n Misses Saved: " +
+ missMap.size() +
+ '\n';
+
+ }
+
+ public void clear(Principal p, StringBuilder sb) {
+ sb.append(toString());
+ userMap.clear();
+ missMap.clear();
+ access.log(Level.AUDIT, p.getName(),"has cleared User Cache in",getClass().getSimpleName());
+ sb.append("Now cleared\n");
+ }
+
+}
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
index 0000000..34ae9d4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Access.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Various Environments require different logging mechanisms, or at least allow
+ * for different ones. We need the Framework to be able to hook into any particular instance of logging
+ * mechanism, whether it be a Logging Object within a Servlet Context, or a direct library like log4j.
+ * This interface, therefore, allows maximum pluggability in a variety of different app styles.
+ *
+ *
+ */
+public interface Access {
+ // levels to use
+ public enum Level {
+ DEBUG(0x1), INFO(0x10), AUDIT(0x100), WARN(0x2000), ERROR(0x4000), INIT(0x8000),NONE(0XFFFF);
+ private final int bit;
+
+ Level(int ord) {
+ bit = ord;
+ }
+
+ public boolean inMask(int mask) {
+ return (mask & bit) == bit;
+ }
+
+ public int addToMask(int mask) {
+ return mask | bit;
+ }
+
+ public int delFromMask(int mask) {
+ return mask & ~bit;
+ }
+
+ public int toggle(int mask) {
+ if(inMask(mask)) {
+ return delFromMask(mask);
+ } else {
+ return addToMask(mask);
+ }
+ }
+
+
+ public int maskOf() {
+ int mask=0;
+ for(Level l : values()) {
+ if(ordinal()<l.ordinal()) {
+ mask|=l.bit;
+ }
+ }
+ return mask;
+ }
+ }
+
+ /**
+ * Write a variable list of Object's text via the toString() method with appropriate space, etc.
+ * @param elements
+ */
+ public void log(Level level, Object ... elements);
+
+ /**
+ * Printf mechanism for Access
+ * @param level
+ * @param fmt
+ * @param elements
+ */
+ public void printf(Level level, String fmt, Object ... elements);
+
+ /**
+ * Check if message will log before constructing
+ * @param level
+ * @return
+ */
+ public boolean willLog(Level level);
+
+ /**
+ * Write the contents of an exception, followed by a variable list of Object's text via the
+ * toString() method with appropriate space, etc.
+ *
+ * The Loglevel is always "ERROR"
+ *
+ * @param elements
+ */
+ public void log(Exception e, Object ... elements);
+
+ /**
+ * Set the Level to compare logging too
+ */
+ public void setLogLevel(Level level);
+
+ /**
+ * It is important in some cases to create a class from within the same Classloader that created
+ * Security Objects. Specifically, it's pretty typical for Web Containers to separate classloaders
+ * so as to allow Apps with different dependencies.
+ * @return
+ */
+ public ClassLoader classLoader();
+
+ public String getProperty(String string, String def);
+
+ public void load(InputStream is) throws IOException;
+
+ /**
+ * if "anytext" is true, then decryption will always be attempted. Otherwise, only if starts with
+ * Symm.ENC
+ * @param encrypted
+ * @param anytext
+ * @return
+ * @throws IOException
+ */
+ public String decrypt(String encrypted, boolean anytext) throws IOException;
+
+ public static final Access NULL = new Access() {
+ public void log(Level level, Object... elements) {
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ }
+
+ public void log(Exception e, Object... elements) {
+ }
+
+ public ClassLoader classLoader() {
+ return this.classLoader();
+ }
+
+ public String getProperty(String string, String def) {
+ return null;
+ }
+
+ public void load(InputStream is) throws IOException {
+ }
+
+ public void setLogLevel(Level level) {
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return encrypted;
+ }
+
+ @Override
+ public boolean willLog(Level level) {
+ return false;
+ }
+ };
+
+
+}
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
index 0000000..f2411c4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/BasicCred.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+/**
+ * An Interface for testing on Requests to see if we can get a User and Password
+ * It works for CadiWrap, but also, Container Specific Wraps (aka Tomcat) should also
+ * implement.
+ *
+ *
+ */
+public interface BasicCred extends GetCred {
+ public void setUser(String user);
+ public void setCred(byte[] passwd);
+ public String getUser();
+}
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
index 0000000..cc9b40d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/BufferedCadiWrap.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * BufferedCadiWrap exists to additionally wrap the InputStream with a BufferedInputStream to engage the
+ * "mark()/release()" API of InputStream.
+ *
+ * This is a requirement for Re-Reading Content for brain-dead Middleware such as SOAP WS-Security.
+ *
+ * Framework needs to set the TafResp and Lur (typically) later in the
+ *
+ *
+ */
+public class BufferedCadiWrap extends CadiWrap {
+ private BufferedServletInputStream sis;
+
+ public BufferedCadiWrap(HttpServletRequest request) {
+ super(request, null, null); // will need to set TafResp and Lur separately
+ sis = null;
+ }
+
+
+ // @Override
+ public BufferedServletInputStream getInputStream() throws IOException {
+// System.out.println("getInputStream() from Buffered CadiWrap... sis = " + sis);
+// try {
+// throw new Exception("OK, here's where we are...");
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+ if(sis==null) {
+ sis = new BufferedServletInputStream(super.getInputStream());
+// } else {
+// try {
+// System.out.println("sis has " + sis.buffered() + " buffered bytes, and reports " + sis.available() + " available");
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+ }
+ return sis;
+ }
+
+ // @Override
+ public BufferedReader getReader() throws IOException {
+// System.out.println("getReader() from Buffered CadiWrap... sis = " + sis);
+// try {
+// throw new Exception("OK, here's where we are...");
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+ return new BufferedReader(new InputStreamReader(getInputStream()));
+ }
+}
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
index 0000000..88114b2
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/BufferedServletInputStream.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletInputStream;
+
+/**
+ * BufferedServletInputStream
+ *
+ * There are cases in brain-dead middleware (SOAP) where they store routing information in the content.
+ *
+ * In HTTP, this requires reading the content from the InputStream which, of course, cannot be re-read.
+ *
+ * BufferedInputStream exists to implement the "Mark" protocols for Streaming, which will enable being
+ * re-read. Unfortunately, J2EE chose to require a "ServletInputStream" as an abstract class, rather than
+ * an interface, which requires we create a delegating pattern, rather than the preferred inheriting pattern.
+ *
+ * Unfortunately, the standard "BufferedInputStream" cannot be used, because it simply creates a byte array
+ * in the "mark(int)" method of that size. This is not appropriate for this application, because the Header
+ * can be potentially huge, and if a buffer was allocated to accommodate all possibilities, the cost of memory
+ * allocation would be too large for high performance transactions.
+ *
+ *
+ *
+ */
+public class BufferedServletInputStream extends ServletInputStream {
+ private static final int NONE = 0;
+ private static final int STORE = 1;
+ private static final int READ = 2;
+
+ private InputStream is;
+ private int state = NONE;
+ private Capacitor capacitor;
+
+ public BufferedServletInputStream(InputStream is) {
+ this.is = is;
+ capacitor = null;
+ }
+
+
+ // @Override
+ public int read() throws IOException {
+ int value=-1;
+ if(capacitor==null) {
+ value=is.read();
+ } else {
+ switch(state) {
+ case STORE:
+ value = is.read();
+ if(value>=0) {
+ capacitor.put((byte)value);
+ }
+ break;
+ case READ:
+ value = capacitor.read();
+ if(value<0) {
+ capacitor.done();
+ capacitor=null; // all done with buffer
+ value = is.read();
+ }
+ }
+ }
+ return value;
+ }
+
+ // @Override
+ public int read(byte[] b) throws IOException {
+ return read(b,0,b.length);
+ }
+
+
+ // @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int count = -1;
+ if(capacitor==null) {
+ count = is.read(b,off,len);
+ } else {
+ switch(state) {
+ case STORE:
+ count = is.read(b, off, len);
+ if(count>0) {
+ capacitor.put(b, off, count);
+ }
+ break;
+ case READ:
+ count = capacitor.read(b, off, len);
+// System.out.println("Capacitor read " + count);
+ if(count<=0) {
+ capacitor.done();
+ capacitor=null; // all done with buffer
+ }
+ if(count<len) {
+ int temp = is.read(b, count, len-count);
+// System.out.println("Capacitor done, stream read " + temp);
+ if(temp>0) { // watch for -1
+ count+=temp;
+ } else {
+ if(count<=0)count = temp; // must account for Stream coming back -1
+ }
+ }
+ break;
+ }
+ }
+// System.out.println("read reports " + count);
+ return count;
+ }
+
+ // @Override
+ public long skip(long n) throws IOException {
+ long skipped = capacitor.skip(n);
+ if(skipped<n) {
+ skipped += is.skip(n-skipped);
+ }
+ return skipped;
+ }
+
+
+ // @Override
+ public int available() throws IOException {
+ int count = is.available();
+ if(capacitor!=null)count+=capacitor.available();
+ return count;
+ }
+
+ /**
+ * Return just amount buffered (for debugging purposes, mostly)
+ * @return
+ */
+ public int buffered() {
+ return capacitor.available();
+ }
+
+
+ // @Override
+ public void close() throws IOException {
+ if(capacitor!=null) {
+ capacitor.done();
+ capacitor=null;
+ }
+ is.close();
+ }
+
+
+ /**
+ * Note: Readlimit is ignored in this implementation, because the need was for unknown buffer size which wouldn't
+ * require allocating and dumping huge chunks of memory every use, or risk overflow.
+ */
+ // @Override
+ public synchronized void mark(int readlimit) {
+ switch(state) {
+ case NONE:
+ capacitor = new Capacitor();
+ break;
+ case READ:
+ capacitor.done();
+ break;
+ // ignore case STORE:
+ }
+ state = STORE;
+ }
+
+
+ /**
+ * Reset Stream
+ *
+ * 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
+ * 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.
+ *
+ */
+ // @Override
+ public synchronized void reset() throws IOException {
+ switch(state) {
+ case STORE:
+ capacitor.setForRead();
+ state = READ;
+ break;
+ case READ:
+ capacitor.reset();
+ break;
+// throw new IOException("InputStream is already in READ state");
+ case NONE:
+ throw new IOException("InputStream has not been marked");
+ }
+ }
+
+
+ // @Override
+ public boolean markSupported() {
+ return true;
+ }
+}
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
index 0000000..741d579
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CachedPrincipal.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+
+/**
+ * Cached Principals need to be able to revalidate in the background.
+ *
+ *
+ */
+public interface CachedPrincipal extends Principal {
+ public enum Resp {NOT_MINE,UNVALIDATED,REVALIDATED,INACCESSIBLE,DENIED};
+
+ /**
+ * Re-validate with Creator
+ *
+ * @return
+ */
+ public abstract Resp revalidate();
+
+ /**
+ * Store when last updated.
+ * @return
+ */
+ public abstract long expires();
+}
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
index 0000000..b7a194f
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CachingLur.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+
+import com.att.cadi.CachedPrincipal.Resp;
+
+
+public interface CachingLur<PERM extends Permission> extends Lur {
+ public abstract void remove(String user);
+ public abstract Resp reload(User<PERM> user);
+ public abstract void setDebug(String commaDelimIDsOrNull);
+ public abstract void clear(Principal p, StringBuilder sb);
+}
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
index 0000000..123b394
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CadiException.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+/**
+ * CADI Specific Exception
+ */
+public class CadiException extends Exception {
+ /**
+ * Generated ID
+ */
+ private static final long serialVersionUID = -4180145363107742619L;
+
+ public CadiException() {
+ super();
+ }
+
+ public CadiException(String message) {
+ super(message);
+ }
+
+ public CadiException(Throwable cause) {
+ super(cause);
+ }
+
+ public CadiException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
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
index 0000000..1961c6e
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CadiWrap.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.filter.NullPermConverter;
+import com.att.cadi.filter.PermConverter;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.taf.TafResp;
+
+
+
+/**
+ * Inherit the HttpServletRequestWrapper, which calls methods of delegate it's created with, but
+ * overload the key security mechanisms with CADI mechanisms
+ *
+ * This works with mechanisms working strictly with HttpServletRequest (i.e. Servlet Filters)
+ *
+ * Specialty cases, i.e. Tomcat, which for their containers utilize their own mechanisms and Wrappers, you may
+ * need something similar. See AppServer specific code (i.e. tomcat) for these.
+ *
+ *
+ */
+public class CadiWrap extends HttpServletRequestWrapper implements HttpServletRequest, BasicCred {
+ private Principal principal;
+ private Lur lur;
+ private String user; // used to set user/pass from brain-dead protocols like WSSE
+ private byte[] password;
+ private PermConverter pconv;
+ private Access access;
+
+ /**
+ * Standard Wrapper constructor for Delegate pattern
+ * @param request
+ */
+ public CadiWrap(HttpServletRequest request, TafResp tafResp, Lur lur) {
+ super(request);
+ principal = tafResp.getPrincipal();
+ access = tafResp.getAccess();
+ this.lur = lur;
+ pconv = NullPermConverter.singleton();
+ }
+
+ /**
+ * Standard Wrapper constructor for Delegate pattern, with PermConverter
+ * @param request
+ */
+ public CadiWrap(HttpServletRequest request, TafResp tafResp, Lur lur, PermConverter pc) {
+ super(request);
+ principal = tafResp.getPrincipal();
+ access = tafResp.getAccess();
+ this.lur = lur;
+ pconv = pc;
+ }
+
+
+ /**
+ * Part of the HTTP Security API. Declare the User associated with this HTTP Transaction.
+ * CADI does this by reporting the name associated with the Principal obtained, if any.
+ */
+// @Override
+ public String getRemoteUser() {
+ return principal==null?null:principal.getName();
+ }
+
+ /**
+ * Part of the HTTP Security API. Return the User Principal associated with this HTTP
+ * Transaction.
+ */
+// @Override
+ public Principal getUserPrincipal() {
+ return principal;
+ }
+
+ /**
+ * This is the key API call for AUTHZ in J2EE. Given a Role (String passed in), is the user
+ * associated with this HTTP Transaction allowed to function in this Role?
+ *
+ * For CADI, we pass the responsibility for determining this to the "LUR", which may be
+ * determined by the Enterprise.
+ *
+ * Note: Role check is also done in "CadiRealm" in certain cases...
+ *
+ *
+ */
+// @Override
+ public boolean isUserInRole(String perm) {
+ return perm==null?false:checkPerm(access,"(HttpRequest)",principal,pconv,lur,perm);
+ }
+
+ public static boolean checkPerm(Access access, String caller, Principal principal, PermConverter pconv, Lur lur, String perm) {
+ if(principal== null) {
+ access.log(Level.AUDIT,caller, "No Principal in Transaction");
+ return false;
+ } else {
+ perm = pconv.convert(perm);
+ if(lur.fish(principal,lur.createPerm(perm))) {
+ access.log(Level.DEBUG,caller, principal.getName(), "has", perm);
+ return true;
+ } else {
+ access.log(Level.DEBUG,caller, principal.getName(), "does not have", perm);
+ return false;
+ }
+ }
+
+ }
+
+ /**
+ * CADI Function (Non J2EE standard). GetPermissions will read the Permissions from AAF (if configured) and Roles from Local Lur, etc
+ * as implemented with lur.fishAll
+ *
+ * To utilize, the Request must be a "CadiWrap" object, then call.
+ */
+ public List<Permission> getPermissions(Principal p) {
+ List<Permission> perms = new ArrayList<Permission>();
+ lur.fishAll(p, perms);
+ return perms;
+ }
+ /**
+ * Allow setting of tafResp and lur after construction
+ *
+ * This can happen if the CadiWrap is constructed in a Valve other than CadiValve
+ */
+ public void set(TafResp tafResp, Lur lur) {
+ principal = tafResp.getPrincipal();
+ access = tafResp.getAccess();
+ this.lur = lur;
+ }
+
+ public String getUser() {
+ if(user==null && principal!=null) {
+ user = principal.getName();
+ }
+ return user;
+ }
+
+ public byte[] getCred() {
+ return password;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public void setCred(byte[] passwd) {
+ password = passwd;
+ }
+
+ public CadiWrap setPermConverter(PermConverter pc) {
+ pconv = pc;
+ return this;
+ }
+
+ // Add a feature
+ public void invalidate(String id) {
+ if(lur instanceof EpiLur) {
+ ((EpiLur)lur).remove(id);
+ } else if(lur instanceof CachingLur) {
+ ((CachingLur<?>)lur).remove(id);
+ }
+ }
+
+ public Lur getLur() {
+ return lur;
+ }
+}
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
index 0000000..0745875
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Capacitor.java
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * Capacitor
+ *
+ * Storage mechanism for read data, specifically designed for InputStreams.
+ *
+ * The Standard BufferedInputStream requires a limit to be set for buffered reading, which is
+ * impractical for reading SOAP headers, which can be quite large.
+ *
+ */
+public class Capacitor {
+ private static final int DEFAULT_CHUNK = 256;
+ private ArrayList<ByteBuffer> bbs = new ArrayList<ByteBuffer>();
+ private ByteBuffer curr = null;
+ private int idx;
+
+ // Maintain a private RingBuffer for Memory, for efficiency
+ private static ByteBuffer[] ring = new ByteBuffer[16];
+ private static int start, end;
+
+
+ public void put(byte b) {
+ if(curr == null || curr.remaining()==0) { // ensure we have a "curr" buffer ready for data
+ curr = ringGet();
+ bbs.add(curr);
+ }
+ curr.put(b);
+ }
+
+ public int read() {
+ if(curr!=null) {
+ if(curr.remaining()>0) { // have a buffer, use it!
+ return curr.get();
+ } else if(idx<bbs.size()){ // Buffer not enough, get next one from array
+ if(idx<bbs.size()) {
+ curr=bbs.get(idx++);
+ return curr.get();
+ }
+ }
+ } // if no curr buffer, treat as end of stream
+ return -1;
+ }
+
+ /**
+ * read into an array like Streams
+ *
+ * @param array
+ * @param offset
+ * @param length
+ * @return
+ */
+ public int read(byte[] array, int offset, int length) {
+ if(curr==null)return -1;
+ int len;
+ int count=0;
+ while(length>0) { // loop through while there's data needed
+ if((len=curr.remaining())>length) { // if enough data in curr buffer, use this code
+ curr.get(array,offset,length);
+ count+=length;
+ length=0;
+ } else { // get data from curr, mark how much is needed to fulfil, and loop for next curr.
+ curr.get(array,offset,len);
+ count+=len;
+ offset+=len;
+ length-=len;
+ if(idx<bbs.size()) {
+ curr=bbs.get(idx++);
+ } else {
+ length=0; // stop, and return the count of how many we were able to load
+ }
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Put an array of data into Capacitor
+ *
+ * @param array
+ * @param offset
+ * @param length
+ */
+ public void put(byte[] array, int offset, int length) {
+ if(curr == null || curr.remaining()==0) {
+ curr = ringGet();
+ bbs.add(curr);
+ }
+
+ int len;
+ while(length>0) {
+ if((len=curr.remaining())>length) {
+ curr.put(array,offset,length);
+ length=0;
+ } else {
+// System.out.println(new String(array));
+ curr.put(array,offset,len);
+ length-=len;
+ offset+=len;
+ curr = ringGet();
+ bbs.add(curr);
+ }
+ }
+ }
+
+ /**
+ * Move state from Storage mode into Read mode, changing all internal buffers to read mode, etc
+ */
+ public void setForRead() {
+ for(ByteBuffer bb : bbs) {
+ bb.flip();
+ }
+ if(bbs.isEmpty()) {
+ curr = null;
+ idx = 0;
+ } else {
+ curr=bbs.get(0);
+ idx=1;
+ }
+ }
+
+ /**
+ * reuse all the buffers
+ */
+ public void done() {
+ for(ByteBuffer bb : bbs) {
+ ringPut(bb);
+ }
+ bbs.clear();
+ curr = null;
+ }
+
+ /**
+ * Declare amount of data available to be read at once.
+ *
+ * @return
+ */
+ public int available() {
+ int count = 0;
+ for(ByteBuffer bb : bbs) {
+ count+=bb.remaining();
+ }
+ return count;
+ }
+
+ /**
+ * Returns how many are left that were not skipped
+ * @param n
+ * @return
+ */
+ public long skip(long n) {
+ long skipped=0L;
+ int skip;
+ while(n>0) {
+ if(n<(skip=curr.remaining())) {
+ curr.position(curr.position()+(int)n);
+ skipped+=skip;
+ n=0;
+ } else {
+ curr.position(curr.limit());
+
+ skipped-=skip;
+ if(idx<bbs.size()) {
+ curr=bbs.get(idx++);
+ n-=skip;
+ } else {
+ n=0;
+ }
+ }
+ }
+ return skipped;
+ }
+ /**
+ * 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
+ * in a standalone mode.
+ */
+ public void reset() {
+ for(ByteBuffer bb : bbs) {
+ bb.position(0);
+ }
+ if(bbs.isEmpty()) {
+ curr = null;
+ idx = 0;
+ } else {
+ curr=bbs.get(0);
+ idx=1;
+ }
+ }
+
+ /*
+ * Ring Functions. Reuse allocated memory
+ */
+ private ByteBuffer ringGet() {
+ ByteBuffer bb = null;
+ synchronized(ring) {
+ bb=ring[start];
+ ring[start]=null;
+ if(bb!=null && ++start>15)start=0;
+ }
+ if(bb==null) {
+ bb=ByteBuffer.allocate(DEFAULT_CHUNK);
+ } else {
+ bb.clear();// refresh reused buffer
+ }
+ return bb;
+ }
+
+ private void ringPut(ByteBuffer bb) {
+ synchronized(ring) {
+ ring[end]=bb; // if null or not, BB will just be Garbage collected
+ if(++end>15)end=0;
+ }
+ }
+
+}
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
index 0000000..2d19234
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CmdLine.java
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.NoSuchAlgorithmException;
+
+import com.att.cadi.util.Chmod;
+import com.att.cadi.util.JsonOutputStream;
+
+
+
+/**
+ * A Class to run on command line to determine suitability of environment for certain TAFs.
+ *
+ * For instance, CSP supports services only in certain domains, and while dynamic host
+ * lookups on the machine work in most cases, sometimes, names and IPs are unexpected (and
+ * invalid) for CSP because of multiple NetworkInterfaces, etc
+ *
+ *
+ */
+public class CmdLine {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ if(args.length>0) {
+ if("digest".equalsIgnoreCase(args[0]) && (args.length>2 || (args.length>1 && System.console()!=null))) {
+ String keyfile;
+ String password;
+ if(args.length>2) {
+ password = args[1];
+ keyfile = args[2];
+ } else {
+ keyfile = args[1];
+ password = new String(System.console().readPassword("Type here (keystrokes hidden): "));
+ }
+
+ try {
+ Symm symm;
+ FileInputStream fis = new FileInputStream(keyfile);
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ fis.close();
+ }
+ symm.enpass(password, System.out);
+ System.out.println();
+ System.out.flush();
+ return;
+ /* testing code... don't want it exposed
+ System.out.println(" ******** Testing *********");
+ for(int i=0;i<100000;++i) {
+ System.out.println(args[1]);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ b64.enpass(args[1], baos);
+ String pass;
+ System.out.println(pass=new String(baos.toByteArray()));
+ ByteArrayOutputStream reconstituted = new ByteArrayOutputStream();
+ b64.depass(pass, reconstituted);
+ String r = reconstituted.toString();
+ System.out.println(r);
+ if(!r.equals(args[1])) {
+ System.err.println("!!!!! STOP - ERROR !!!!!");
+ return;
+ }
+ System.out.println();
+ }
+ System.out.flush();
+ */
+
+ } catch (IOException e) {
+ System.err.println("Cannot digest password");
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+// . Oh, well, Deployment services need this behavior. I will put this code in, but leave it undocumented.
+// One still needs access to the keyfile to read.
+// July 2016 - thought of a tool "CMPass" to reguritate from properties, but only if allowed.
+ } else if("regurgitate".equalsIgnoreCase(args[0]) && args.length>2) {
+ try {
+ Symm symm;
+ FileInputStream fis = new FileInputStream(args[2]);
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ fis.close();
+ }
+ boolean isFile = false;
+ if("-i".equals(args[1]) || (isFile="-f".equals(args[1]))) {
+ BufferedReader br;
+ if(isFile) {
+ if(args.length<4) {
+ System.err.println("Filename in 4th position");
+ return;
+ }
+ br = new BufferedReader(new FileReader(args[3]));
+ } else {
+ br = new BufferedReader(new InputStreamReader(System.in));
+ }
+ try {
+ String line;
+ boolean cont = false;
+ StringBuffer sb = new StringBuffer();
+ JsonOutputStream jw = new JsonOutputStream(System.out);
+ while((line=br.readLine())!=null) {
+ if(cont) {
+ int end;
+ if((end=line.indexOf('"'))>=0) {
+ sb.append(line,0,end);
+ cont=false;
+ } else {
+ sb.append(line);
+ }
+ } else {
+ int idx;
+ if((idx = line.indexOf(' '))>=0
+ && (idx = line.indexOf(' ',++idx))>0
+ && (idx = line.indexOf('=',++idx))>0
+ && (idx = line.indexOf('=',++idx))>0
+ ) {
+ System.out.println(line.substring(0, idx-5));
+ int start = idx+2;
+ int end;
+ if((end=line.indexOf('"',start))<0) {
+ end = line.length();
+ cont = true;
+ }
+ sb.append(line,start,end);
+ }
+ }
+ if(sb.length()>0) {
+ symm.depass(sb.toString(),jw);
+ if(!cont) {
+ System.out.println();
+ }
+ }
+ System.out.flush();
+ sb.setLength(0);
+ if(!cont) {
+ jw.resetIndent();
+ }
+ }
+ } finally {
+ if(isFile) {
+ br.close();
+ }
+ }
+ } else {
+ symm.depass(args[1], System.out);
+ }
+ System.out.println();
+ System.out.flush();
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot regurgitate password");
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ } else if("encode64".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ Symm.base64.encode(args[1], System.out);
+ System.out.println();
+ System.out.flush();
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot encode Base64 with " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ } else if("decode64".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ Symm.base64.decode(args[1], System.out);
+ System.out.println();
+ System.out.flush();
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot decode Base64 text from " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ } else if("encode64url".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ Symm.base64url.encode(args[1], System.out);
+ System.out.println();
+ System.out.flush();
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot encode Base64url with " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ } else if("decode64url".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ Symm.base64url.decode(args[1], System.out);
+ System.out.println();
+ System.out.flush();
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot decode Base64url text from " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ } else if("md5".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ System.out.println(Hash.encryptMD5asStringHex(args[1]));
+ System.out.flush();
+ } catch (NoSuchAlgorithmException e) {
+ System.err.println("Cannot hash MD5 from " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ return;
+ } else if("sha256".equalsIgnoreCase(args[0]) && args.length>1) {
+ try {
+ if(args.length>2) {
+ int salt = Integer.parseInt(args[2]);
+ System.out.println(Hash.hashSHA256asStringHex(args[1],salt));
+ } else {
+ System.out.println(Hash.hashSHA256asStringHex(args[1]));
+ }
+ } catch (NoSuchAlgorithmException e) {
+ System.err.println("Cannot hash SHA256 text from " + args[1]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+ System.out.flush();
+ return;
+ } else if("keygen".equalsIgnoreCase(args[0])) {
+ try {
+ if(args.length>1) {
+ File f = new File(args[1]);
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ fos.write(Symm.baseCrypt().keygen());
+ fos.flush();
+ } finally {
+ fos.close();
+ Chmod.to400.chmod(f);
+ }
+ } else {
+ // create a Symmetric Key out of same characters found in base64
+ System.out.write(Symm.baseCrypt().keygen());
+ System.out.flush();
+ }
+ return;
+ } catch (IOException e) {
+ System.err.println("Cannot create a key " + args[0]);
+ System.err.println(" \""+ e.getMessage() + '"');
+ }
+
+ } else if("passgen".equalsIgnoreCase(args[0])) {
+ int numDigits;
+ if(args.length <= 1) {
+ numDigits = 24;
+ } else {
+ numDigits = Integer.parseInt(args[1]);
+ if(numDigits<8)numDigits = 8;
+ }
+ String pass;
+ boolean noLower,noUpper,noDigits,noSpecial,repeats;
+ do {
+ pass = Symm.randomGen(numDigits);
+ noLower=noUpper=noDigits=noSpecial=true;
+ repeats=false;
+ int c=-1,last;
+ for(int i=0;i<numDigits;++i) {
+ last = c;
+ c = pass.charAt(i);
+ if(c==last) {
+ repeats=true;
+ break;
+ }
+
+ if(noLower) {
+ noLower=!(c>=0x61 && c<=0x7A);
+ continue;
+ }
+ if(noUpper) {
+ noUpper=!(c>=0x41 && c<=0x5A);
+ continue;
+ }
+ if(noDigits) {
+ noDigits=!(c>=0x30 && c<=0x39);
+ continue;
+ }
+ if(noSpecial) {
+ noSpecial = "+!@#$%^&*(){}[]?:;,.".indexOf(c)<0;
+ continue;
+ }
+
+ break;
+ }
+ } while(noLower || noUpper || noDigits || noSpecial || repeats);
+ System.out.println(pass.substring(0,numDigits));
+ } else if("urlgen".equalsIgnoreCase(args[0])) {
+ int numDigits;
+ if(args.length < 1) {
+ numDigits = 24;
+ } else {
+ numDigits = Integer.parseInt(args[1]);
+ }
+ System.out.println(Symm.randomGen(Symm.base64url.codeset, numDigits).substring(0,numDigits));
+
+ } else if("csptest".equalsIgnoreCase(args[0])) {
+ try {
+ System.out.println("CSP Compatibility test");
+
+ String hostName = InetAddress.getLocalHost().getCanonicalHostName();
+
+ System.out.println(" Your automatic hostname is reported as \"" + hostName + "\"\n");
+ System.out.flush();
+ return;
+ } catch (UnknownHostException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ } else {
+ System.out.println("Usage: java -jar <this jar> ...");
+ System.out.println(" keygen [<keyfile>] (Generates Key on file, or Std Out)");
+ System.out.println(" digest <keyfile> (Encrypts to Key with \"keyfile\")");
+ System.out.println(" passgen <digits> (Generate Password of given size)");
+ System.out.println(" urlgen <digits> (Generate URL field of given size)");
+ System.out.println(" csptest (Tests for CSP compatibility)");
+ System.out.println(" encode64 <your text> (Encodes to Base64)");
+ System.out.println(" decode64 <base64 encoded text> (Decodes from Base64)");
+ System.out.println(" encode64url <your text> (Encodes to Base64 URL charset)");
+ System.out.println(" decode64url <base64url encoded text> (Decodes from Base64 URL charset)");
+ System.out.println(" sha256 <text> (Digest String into SHA256 Hash)");
+ System.out.println(" md5 <text> (Digest String into MD5 Hash)");
+ }
+ System.exit(1);
+ }
+
+}
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
index 0000000..4f5576d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Connector.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+public interface Connector {
+ public Lur newLur() throws CadiException;
+}
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
index 0000000..040781d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/CredVal.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+/**
+ * UserPass
+ *
+ * The essential interface required by BasicAuth to determine if a given User/Password combination is
+ * valid. This is done as an interface.
+ *
+ */
+public interface CredVal {
+ public enum Type{PASSWORD};
+ /**
+ * Validate if the User/Password combination matches records
+ * @param user
+ * @param pass
+ * @return
+ */
+ public boolean validate(String user, Type type, byte[] cred);
+}
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
index 0000000..f5289f0
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/GetCred.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+public interface GetCred {
+ byte[] getCred();
+}
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
index 0000000..190049f
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Hash.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class Hash {
+ private static char hexDigit[] = "0123456789abcdef".toCharArray();
+
+/////////////////////////////////
+// MD5
+/////////////////////////////////
+ /**
+ * Encrypt MD5 from Byte Array to Byte Array
+ * @param input
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static byte[] encryptMD5 (byte[] input) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(input);
+ return md.digest();
+ }
+
+ /**
+ * Encrypt MD5 from Byte Array to Byte Array
+ * @param input
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static byte[] encryptMD5 (byte[] input, int offset, int length) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(input,offset,length);
+ return md.digest();
+ }
+
+
+
+ /**
+ * Convenience Function: Encrypt MD5 from String to String Hex representation
+ *
+ * @param input
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static String encryptMD5asStringHex(String input) throws NoSuchAlgorithmException {
+ byte[] output = encryptMD5(input.getBytes());
+ StringBuilder sb = new StringBuilder("0x");
+ for (byte b : output) {
+ sb.append(hexDigit[(b >> 4) & 0x0f]);
+ sb.append(hexDigit[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+
+/////////////////////////////////
+// SHA256
+/////////////////////////////////
+ /**
+ * SHA256 Hashing
+ */
+ public static byte[] hashSHA256(byte[] input) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(input);
+ return md.digest();
+ }
+
+ /**
+ * SHA256 Hashing
+ */
+ public static byte[] hashSHA256(byte[] input, int offset, int length) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(input,offset,length);
+ return md.digest();
+ }
+
+ /**
+ * Convenience Function: Hash from String to String Hex representation
+ *
+ * @param input
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static String hashSHA256asStringHex(String input) throws NoSuchAlgorithmException {
+ byte[] output = hashSHA256(input.getBytes());
+ StringBuilder sb = new StringBuilder("0x");
+ for (byte b : output) {
+ sb.append(hexDigit[(b >> 4) & 0x0f]);
+ sb.append(hexDigit[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convenience Function: Hash from String to String Hex representation
+ *
+ * @param input
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static String hashSHA256asStringHex(String input, int salt) throws NoSuchAlgorithmException {
+ byte[] in = input.getBytes();
+ ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + in.length);
+ bb.putInt(salt);
+ bb.put(input.getBytes());
+ byte[] output = Hash.hashSHA256(bb.array());
+ StringBuilder sb = new StringBuilder("0x");
+ for (byte b : output) {
+ sb.append(hexDigit[(b >> 4) & 0x0f]);
+ sb.append(hexDigit[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Compare two byte arrays for equivalency
+ * @param ba1
+ * @param ba2
+ * @return
+ */
+ public static boolean isEqual(byte ba1[], byte ba2[]) {
+ if(ba1.length!=ba2.length)return false;
+ for(int i = 0;i<ba1.length; ++i) {
+ if(ba1[i]!=ba2[i])return false;
+ }
+ return true;
+ }
+
+ public static int compareTo(byte[] a, byte[] b) {
+ int end = Math.min(a.length, b.length);
+ int compare = 0;
+ for(int i=0;compare == 0 && i<end;++i) {
+ compare = a[i]-b[i];
+ }
+ if(compare==0)compare=a.length-b.length;
+ return compare;
+ }
+
+ public static String toHex(byte[] ba) {
+ StringBuilder sb = new StringBuilder("0x");
+ for (byte b : ba) {
+ sb.append(hexDigit[(b >> 4) & 0x0f]);
+ sb.append(hexDigit[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+
+ public static byte[] fromHex(String s) throws CadiException{
+ if(!s.startsWith("0x")) {
+ throw new CadiException("HexString must start with \"0x\"");
+ }
+ boolean high = true;
+ int c;
+ byte b;
+ byte[] ba = new byte[(s.length()-2)/2];
+ int idx;
+ for(int i=2;i<s.length();++i) {
+ c = s.charAt(i);
+ if(c>=0x30 && c<=0x39) {
+ b=(byte)(c-0x30);
+ } else if(c>=0x61 && c<=0x66) {
+ b=(byte)(c-0x57); // account for "A"
+ } else if(c>=0x41 && c<=0x46) {
+ b=(byte)(c-0x37);
+ } else {
+ throw new CadiException("Invalid char '" + c + "' in HexString");
+ }
+ idx = (i-2)/2;
+ if(high) {
+ ba[idx]=(byte)(b<<4);
+ high = false;
+ } else {
+ ba[idx]|=b;
+ high = true;
+ }
+ }
+ return ba;
+ }
+
+}
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
index 0000000..a1593bb
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Locator.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+public interface Locator<T> {
+ public T get(Locator.Item item) throws LocatorException;
+ public boolean hasItems();
+ public void invalidate(Locator.Item item) throws LocatorException;
+ public Locator.Item best() throws LocatorException;
+ public Item first() throws LocatorException;
+ public Item next(Item item) throws LocatorException;
+ public boolean refresh();
+ public void destroy();
+
+ public interface Item {}
+}
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
index 0000000..b9260b9
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/LocatorException.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+public class LocatorException extends Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4267929804321134469L;
+
+ public LocatorException(String arg0) {
+ super(arg0);
+ }
+
+ public LocatorException(Throwable arg0) {
+ super(arg0);
+ }
+
+ public LocatorException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+ public LocatorException(CharSequence cs) {
+ super(cs.toString());
+ }
+
+}
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
index 0000000..7ca94c9
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Lur.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+import java.util.List;
+
+
+
+/**
+ * LUR: Local User Registry
+ *
+ * Concept by Robert Garskof, Implementation by Jonathan Gathman
+ *
+ * Where we can keep local copies of users and roles for faster Authorization when asked.
+ *
+ * Note: Author cannot resist the mental image of using a Fishing Lure to this LUR pattern
+ *
+ *
+ */
+public interface Lur {
+ /**
+ * Allow the Lur, which has correct Permission access, to create and hand back.
+ */
+ public Permission createPerm(String p);
+
+ /**
+ * Fish for Principals in a Pond
+ *
+ * or more boringly, is the User identified within a named collection representing permission.
+ *
+ * @param principalName
+ * @return
+ */
+ public boolean fish(Principal bait, Permission pond);
+
+ /**
+ * Fish all the Principals out a Pond
+ *
+ * For additional humor, pronounce the following with a Southern Drawl, "FishOil"
+ *
+ * or more boringly, load the List with Permissions found for Principal
+ *
+ * @param principalName
+ * @return
+ */
+ public void fishAll(Principal bait, List<Permission> permissions);
+
+ /**
+ * Allow implementations to disconnect, or cleanup resources if unneeded
+ */
+ public void destroy();
+
+ /**
+ * Does this LUR handle this pond exclusively? Important for EpiLUR to determine whether
+ * to try another (more expensive) LUR
+ * @param pond
+ * @return
+ */
+ public boolean handlesExclusively(Permission pond);
+
+ /**
+ * What domain of User does this LUR support? (used to avoid asking when not possible)
+ *
+ * @param bait
+ * @return
+ */
+ public boolean supports(String userName);
+
+ /**
+ * Clear: Clear any Caching, if exists
+ */
+ public void clear(Principal p, StringBuilder report);
+}
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
index 0000000..b8cd56e
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Permission.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+public interface Permission {
+ public String permType();
+ public String getKey();
+ public boolean match(Permission p);
+}
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
index 0000000..25573a0
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/PropAccess.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfo;
+
+public class PropAccess implements Access {
+ private static final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+
+ public static Level DEFAULT = Level.AUDIT;
+
+ private Symm symm;
+ private int level;
+ private Properties props;
+ private List<String> recursionProtection = null;
+ private PrintStream out;
+
+ private String name;
+
+ public PropAccess() {
+ out=System.out;
+ init(null);
+ }
+
+ /**
+ * This Constructor soley exists to instantiate Servlet Context Based Logging that will call "init" later.
+ * @param sc
+ */
+ protected PropAccess(Object o) {
+ out=System.out;
+ props = new Properties();
+ }
+
+ public PropAccess(String ... args) {
+ this(System.out,args);
+ }
+
+ public PropAccess(PrintStream ps, String[] args) {
+ out=ps==null?System.out:ps;
+ Properties nprops=new Properties();
+ int eq;
+ for(String arg : args) {
+ if((eq=arg.indexOf('='))>0) {
+ nprops.setProperty(arg.substring(0, eq),arg.substring(eq+1));
+ }
+ }
+ init(nprops);
+ }
+
+ public PropAccess(Properties p) {
+ this(System.out,p);
+ }
+
+ public PropAccess(PrintStream ps, Properties p) {
+ out=ps==null?System.out:ps;
+ init(p);
+ }
+
+ protected void init(Properties p) {
+ // Make sure these two are set before any changes in Logging
+ name = "cadi";
+ level=DEFAULT.maskOf();
+
+ props = new Properties();
+ // First, load related System Properties
+ for(Entry<Object,Object> es : System.getProperties().entrySet()) {
+ String key = es.getKey().toString();
+ for(String start : new String[] {"cadi_","aaf_","cm_","csp_"}) {
+ if(key.startsWith(start)) {
+ props.put(key, es.getValue());
+ }
+ }
+ }
+ // Second, overlay or fill in with Passed in Props
+ if(p!=null) {
+ props.putAll(p);
+ }
+
+ // Third, load any Chained Property Files
+ load(props.getProperty(Config.CADI_PROP_FILES));
+
+ String sLevel = props.getProperty(Config.CADI_LOGLEVEL);
+ if(sLevel!=null) {
+ level=Level.valueOf(sLevel).maskOf();
+ }
+ // Setup local Symmetrical key encryption
+ if(symm==null) {
+ symm = Symm.obtain(this);
+ }
+
+ name = props.getProperty(Config.CADI_LOGNAME, name);
+
+ // Critical - if no Security Protocols set, then set it. We'll just get messed up if not
+ if(props.get(Config.CADI_PROTOCOLS)==null) {
+ props.setProperty(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT);
+ }
+ }
+
+ private void load(String cadi_prop_files) {
+ String prevKeyFile = props.getProperty(Config.CADI_KEYFILE);
+
+ if(cadi_prop_files!=null) {
+ int prev = 0, end = cadi_prop_files.length();
+ int idx;
+ String filename;
+ while(prev<end) {
+ idx = cadi_prop_files.indexOf(File.pathSeparatorChar,prev);
+ if(idx<0) {
+ idx = end;
+ }
+ File file = new File(filename=cadi_prop_files.substring(prev,idx));
+ if(file.exists()) {
+ printf(Level.INIT,"Loading CADI Properties from %s",file.getAbsolutePath());
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ props.load(fis);
+ // Recursively Load
+ String chainProp = props.getProperty(Config.CADI_PROP_FILES);
+ if(chainProp!=null) {
+ if(recursionProtection==null) {
+ recursionProtection = new ArrayList<String>();
+ recursionProtection.add(cadi_prop_files);
+ }
+ if(!recursionProtection.contains(chainProp)) {
+ recursionProtection.add(chainProp);
+ load(chainProp); // recurse
+ }
+ }
+ } finally {
+ fis.close();
+ }
+ } catch (Exception e) {
+ log(e,filename,"cannot be opened");
+ }
+ } else {
+ printf(Level.WARN,"Warning: recursive CADI Property %s does not exist",file.getAbsolutePath());
+ }
+ prev = idx+1;
+ }
+ }
+ // Reset Symm if Keyfile Changes:
+ String newKeyFile = props.getProperty(Config.CADI_KEYFILE);
+ if((prevKeyFile==null && newKeyFile!=null) || (newKeyFile!=null && !newKeyFile.equals(prevKeyFile))) {
+ symm = Symm.obtain(this);
+ prevKeyFile=newKeyFile;
+ }
+
+ String loglevel = props.getProperty(Config.CADI_LOGLEVEL);
+ if(loglevel!=null) {
+ try {
+ level=Level.valueOf(loglevel).maskOf();
+ } catch (IllegalArgumentException e) {
+ printf(Level.ERROR,"%s=%s is an Invalid Log Level",Config.CADI_LOGLEVEL,loglevel);
+ }
+ }
+ }
+
+ @Override
+ public void load(InputStream is) throws IOException {
+ props.load(is);
+ load(props.getProperty(Config.CADI_PROP_FILES));
+ }
+
+ @Override
+ public void log(Level level, Object ... elements) {
+ if(willLog(level)) {
+ StringBuilder sb = buildMsg(level, elements);
+ out.println(sb);
+ out.flush();
+ }
+ }
+
+ protected StringBuilder buildMsg(Level level, Object[] elements) {
+ StringBuilder sb = new StringBuilder(iso8601.format(new Date()));
+ sb.append(' ');
+ sb.append(level.name());
+ sb.append(" [");
+ sb.append(name);
+
+ int end = elements.length;
+ if(end<=0) {
+ sb.append("] ");
+ } else {
+ int idx = 0;
+ if(elements[idx] instanceof Integer) {
+ sb.append('-');
+ sb.append(elements[idx]);
+ ++idx;
+ }
+ sb.append("] ");
+ String s;
+ boolean first = true;
+ for(Object o : elements) {
+ if(o!=null) {
+ s=o.toString();
+ if(first) {
+ first = false;
+ } else {
+ int l = s.length();
+ if(l>0) {
+ switch(s.charAt(l-1)) {
+ case ' ':
+ break;
+ default:
+ sb.append(' ');
+ }
+ }
+ }
+ sb.append(s);
+ }
+ }
+ }
+ return sb;
+ }
+
+ @Override
+ public void log(Exception e, Object... elements) {
+ log(Level.ERROR,e.getMessage(),elements);
+ e.printStackTrace(System.err);
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ if(willLog(level)) {
+ log(level,String.format(fmt, elements));
+ }
+ }
+
+ @Override
+ public void setLogLevel(Level level) {
+ this.level = level.maskOf();
+ }
+
+ @Override
+ public boolean willLog(Level level) {
+ return level.inMask(this.level);
+ }
+
+ @Override
+ public ClassLoader classLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ @Override
+ public String getProperty(String tag, String def) {
+ return props.getProperty(tag,def);
+ }
+
+ @Override
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+ public String encrypt(String unencrypted) throws IOException {
+ return Symm.ENC+symm.enpass(unencrypted);
+ }
+
+ //////////////////
+ // Additional
+ //////////////////
+ public String getProperty(String tag) {
+ return props.getProperty(tag);
+ }
+
+
+ public Properties getProperties() {
+ return props;
+ }
+
+ public void setProperty(String tag, String value) {
+ if(value!=null) {
+ props.put(tag, value);
+ if(Config.CADI_KEYFILE.equals(tag)) {
+ // reset decryption too
+ symm = Symm.obtain(this);
+ }
+ }
+ }
+
+ public Properties getDME2Properties() {
+ return Config.getDME2Props(this);
+ }
+
+}
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
index 0000000..ded7b2d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Revalidator.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+public interface Revalidator<TRANS> {
+ /**
+ * Re-Validate Credential
+ *
+ * @param prin
+ * @return
+ */
+ public CachedPrincipal.Resp revalidate(TRANS trans, CachedPrincipal prin);
+
+}
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
index 0000000..e3d8451
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/SLF4JAccess.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SLF4JAccess extends PropAccess {
+ private static final Logger slf4j = LoggerFactory.getLogger("AAF");
+
+ public SLF4JAccess(final Properties initial) throws CadiException {
+ super(initial);
+ }
+
+ public void log(Level level, Object... elements) {
+ switch(level) {
+ case AUDIT:
+ slf4j.info(msg(elements).toString());
+ break;
+ case DEBUG:
+ slf4j.debug(msg(elements).toString());
+ break;
+ case ERROR:
+ slf4j.error(msg(elements).toString());
+ break;
+ case INFO:
+ slf4j.info(msg(elements).toString());
+ break;
+ case INIT:
+ slf4j.info(msg(elements).toString());
+ break;
+ case WARN:
+ slf4j.warn(msg(elements).toString());
+ break;
+ default:
+ slf4j.info(msg(elements).toString());
+ break;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)
+ */
+ @Override
+ public boolean willLog(Level level) {
+ switch(level) {
+ case DEBUG:
+ return slf4j.isDebugEnabled();
+ case ERROR:
+ return slf4j.isErrorEnabled();
+ case WARN:
+ return slf4j.isWarnEnabled();
+// case INFO:
+// case INIT:
+// case AUDIT:
+ default:
+ return slf4j.isInfoEnabled();
+ }
+ }
+
+ private StringBuilder msg(Object ... elements) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(Object o : elements) {
+ if(first) first = false;
+ else {
+ sb.append(' ');
+ }
+ sb.append(o.toString());
+ }
+ return sb;
+ }
+
+ public void log(Exception e, Object... elements) {
+ slf4j.error(msg(elements).toString(),e);
+ }
+
+}
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
index 0000000..dadbd06
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/SecuritySetter.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+/**
+ * Apply any particular security mechanism
+ *
+ * This allows the definition of various mechanisms involved outside of DRcli jars
+ *
+ *
+ */
+public interface SecuritySetter<CT> {
+ public String getID();
+
+ public void setSecurity(CT client) throws CadiException;
+
+ /**
+ * Returns number of bad logins registered
+ * @param respCode
+ * @return
+ */
+ public int setLastResponse(int respCode);
+}
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
index 0000000..896f824
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/ServletContextAccess.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+import java.util.Enumeration;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+
+import com.att.cadi.config.Config;
+
+public class ServletContextAccess extends PropAccess {
+
+ private ServletContext context;
+
+ public ServletContextAccess(FilterConfig filterConfig) {
+ super(filterConfig); // protected contstructor... does not have "init" called.
+ context = filterConfig.getServletContext();
+
+ for(Enumeration<?> en = filterConfig.getInitParameterNames();en.hasMoreElements();) {
+ String name = (String)en.nextElement();
+ setProperty(name, filterConfig.getInitParameter(name));
+ }
+ init(getProperties());
+ Config.getDME2Props(this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.PropAccess#log(com.att.cadi.Access.Level, java.lang.Object[])
+ */
+ @Override
+ public void log(Level level, Object... elements) {
+ if(willLog(level)) {
+ StringBuilder sb = buildMsg(level, elements);
+ context.log(sb.toString());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.PropAccess#log(java.lang.Exception, java.lang.Object[])
+ */
+ @Override
+ public void log(Exception e, Object... elements) {
+ StringBuilder sb = buildMsg(Level.ERROR, elements);
+ context.log(sb.toString(),e);
+ }
+
+ public ServletContext context() {
+ return context;
+ }
+}
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
index 0000000..dc4c992
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/StrLur.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.util.List;
+
+
+
+/**
+ * StrLUR: Implements fish with String, skipping the need to be a Principal where it doesn't make sense.
+ *
+ *
+ */
+public interface StrLur extends Lur {
+ /**
+ * Fish for Principals in a Pond
+ *
+ * or more boringly, is the User identified within a named collection representing permission.
+ *
+ * @param principalName
+ * @return
+ */
+ public boolean fish(String bait, Permission pond);
+
+ /**
+ * Fish all the Principals out a Pond
+ *
+ * For additional humor, pronounce the following with a Southern Drawl, "FishOil"
+ *
+ * or more boringly, load the List with Permissions found for Principal
+ *
+ * @param principalName
+ * @return
+ */
+ public void fishAll(String bait, List<Permission> permissions);
+}
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
index 0000000..0b34b58
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Symm.java
@@ -0,0 +1,812 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Random;
+
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.config.Config;
+
+/**
+ * Key Conversion, primarily "Base64"
+ *
+ * Base64 is required for "Basic Authorization", which is an important part of the overall CADI Package.
+ *
+ * Note: This author found that there is not a "standard" library for Base64 conversion within Java.
+ * The source code implementations available elsewhere were surprisingly inefficient, requiring, for
+ * instance, multiple string creation, on a transaction pass. Integrating other packages that might be
+ * efficient enough would put undue Jar File Dependencies given this Framework should have none-but-Java
+ * dependencies.
+ *
+ * The essential algorithm is good for a symmetrical key system, as Base64 is really just
+ * a symmetrical key that everyone knows the values.
+ *
+ * This code is quite fast, taking about .016 ms for encrypting, decrypting and even .08 for key
+ * generation. The speed quality, especially of key generation makes this a candidate for a short term token
+ * used for identity.
+ *
+ * It may be used to easily avoid placing Clear-Text passwords in configurations, etc. and contains
+ * supporting functions such as 2048 keyfile generation (see keygen). This keyfile should, of course,
+ * be set to "400" (Unix) and protected as any other mechanism requires.
+ *
+ * However, this algorithm has not been tested against hackers. Until such a time, utilize more tested
+ * packages to protect Data, especially sensitive data at rest (long term).
+ *
+ */
+public class Symm {
+ private static final byte[] DOUBLE_EQ = new byte[] {'=','='};
+ public static final String ENC = "enc:";
+ private static final SecureRandom random = new SecureRandom();
+
+ public final char[] codeset;
+ private final int splitLinesAt;
+ private final String encoding;
+ private final Convert convert;
+ private final boolean endEquals;
+ //Note: AES Encryption is not Thread Safe. It is Synchronized
+ private static AES aes = null; // only initialized from File, and only if needed for Passwords
+
+ /**
+ * This is the standard base64 Key Set.
+ * RFC 2045
+ */
+ public static final Symm base64 = new Symm(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()
+ ,76, Config.UTF_8,true);
+
+ public static final Symm base64noSplit = new Symm(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()
+ ,Integer.MAX_VALUE, Config.UTF_8,true);
+
+ /**
+ * This is the standard base64 set suitable for URLs and Filenames
+ * RFC 4648
+ */
+ public static final Symm base64url = new Symm(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray()
+ ,76, Config.UTF_8,true);
+
+ /**
+ * A Password set, using US-ASCII
+ * RFC 4648
+ */
+ public static final Symm encrypt = new Symm(base64url.codeset,1024, "US-ASCII", false);
+
+ /**
+ * A typical set of Password Chars
+ * Note, this is too large to fit into the algorithm. Only use with PassGen
+ */
+ private static char passChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+!@#$%^&*(){}[]?:;,.".toCharArray();
+
+
+
+ /**
+ * Use this to create special case Case Sets and/or Line breaks
+ *
+ * If you don't know why you need this, use the Singleton Method
+ *
+ * @param codeset
+ * @param split
+ */
+ public Symm(char[] codeset, int split, String charset, boolean useEndEquals) {
+ this.codeset = codeset;
+ splitLinesAt = split;
+ encoding = charset;
+ endEquals = useEndEquals;
+ char prev = 0, curr=0, first = 0;
+ int offset=Integer.SIZE; // something that's out of range for integer array
+
+ // There can be time efficiencies gained when the underlying keyset consists mainly of ordered
+ // data (i.e. abcde...). Therefore, we'll quickly analyze the keyset. If it proves to have
+ // too much entropy, the "Unordered" algorithm, which is faster in such cases is used.
+ ArrayList<int[]> la = new ArrayList<int[]>();
+ for(int i=0;i<codeset.length;++i) {
+ curr = codeset[i];
+ if(prev+1==curr) { // is next character in set
+ prev = curr;
+ } else {
+ if(offset!=Integer.SIZE) { // add previous range
+ la.add(new int[]{first,prev,offset});
+ }
+ first = prev = curr;
+ offset = curr-i;
+ }
+ }
+ la.add(new int[]{first,curr,offset});
+ if(la.size()>codeset.length/3) {
+ convert = new Unordered(codeset);
+ } else { // too random to get speed enhancement from range algorithm
+ int[][] range = new int[la.size()][];
+ la.toArray(range);
+ convert = new Ordered(range);
+ }
+ }
+
+ public Symm copy(int lines) {
+ return new Symm(codeset,lines,encoding,endEquals);
+ }
+
+ // Only used by keygen, which is intentionally randomized. Therefore, always use unordered
+ private Symm(char[] codeset, Symm parent) {
+ this.codeset = codeset;
+ splitLinesAt = parent.splitLinesAt;
+ endEquals = parent.endEquals;
+ encoding = parent.encoding;
+ convert = new Unordered(codeset);
+ }
+
+ /**
+ * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.
+ * @return
+ */
+ @Deprecated
+ public static final Symm base64() {
+ return base64;
+ }
+
+ /**
+ * Obtain the base64() behavior of this class, for use in standard BASIC AUTH mechanism, etc.
+ * No Line Splitting
+ * @return
+ */
+ @Deprecated
+ public static final Symm base64noSplit() {
+ return base64noSplit;
+ }
+
+ /**
+ * Obtain the base64 "URL" behavior of this class, for use in File Names, etc. (no "/")
+ */
+ @Deprecated
+ public static final Symm base64url() {
+ return base64url;
+ }
+
+ /**
+ * Obtain a special ASCII version for Scripting, with base set of base64url use in File Names, etc. (no "/")
+ */
+ public static final Symm baseCrypt() {
+ return encrypt;
+ }
+
+ /*
+ * Note: AES Encryption is NOT thread-safe. Must surround entire use with synchronized
+ */
+ private synchronized void exec(AESExec exec) throws IOException {
+ if(aes == null) {
+ try {
+ byte[] bytes = new byte[AES.AES_KEY_SIZE/8];
+ int offset = (Math.abs(codeset[0])+47)%(codeset.length-bytes.length);
+ for(int i=0;i<bytes.length;++i) {
+ bytes[i] = (byte)codeset[i+offset];
+ }
+ aes = new AES(bytes,0,bytes.length);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+ exec.exec(aes);
+ }
+
+ private static interface AESExec {
+ public void exec(AES aes) throws IOException;
+ }
+
+ public byte[] encode(byte[] toEncrypt) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(toEncrypt.length*1.25));
+ encode(new ByteArrayInputStream(toEncrypt),baos);
+ return baos.toByteArray();
+ }
+
+ public byte[] decode(byte[] encrypted) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(encrypted.length*1.25));
+ decode(new ByteArrayInputStream(encrypted),baos);
+ return baos.toByteArray();
+ }
+
+ /**
+ * Helper function for String API of "Encode"
+ * use "getBytes" with appropriate char encoding, etc.
+ *
+ * @param str
+ * @return
+ * @throws IOException
+ */
+ public String encode(String str) throws IOException {
+ byte[] array;
+ try {
+ array = str.getBytes(encoding);
+ } catch (IOException e) {
+ array = str.getBytes(); // take default
+ }
+ // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*1.363)); // account for 4 bytes for 3 and a byte or two more
+
+ encode(new ByteArrayInputStream(array),baos);
+ return baos.toString(encoding);
+ }
+
+ /**
+ * Helper function for the String API of "Decode"
+ * use "getBytes" with appropriate char encoding, etc.
+ * @param str
+ * @return
+ * @throws IOException
+ */
+ public String decode(String str) throws IOException {
+ byte[] array;
+ try {
+ array = str.getBytes(encoding);
+ } catch (IOException e) {
+ array = str.getBytes(); // take default
+ }
+ // Calculate expected size to avoid any buffer expansion copies within the ByteArrayOutput code
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(array.length*.76)); // Decoding is 3 bytes for 4. Allocate slightly more than 3/4s
+ decode(new ByteArrayInputStream(array), baos);
+ return baos.toString(encoding);
+ }
+
+ /**
+ * Convenience Function
+ *
+ * encode String into InputStream and call encode(InputStream, OutputStream)
+ *
+ * @param string
+ * @param out
+ * @throws IOException
+ */
+ public void encode(String string, OutputStream out) throws IOException {
+ encode(new ByteArrayInputStream(string.getBytes()),out);
+ }
+
+ /**
+ * Convenience Function
+ *
+ * encode String into InputStream and call decode(InputStream, OutputStream)
+ *
+ * @param string
+ * @param out
+ * @throws IOException
+ */
+ public void decode(String string, OutputStream out) throws IOException {
+ decode(new ByteArrayInputStream(string.getBytes()),out);
+ }
+
+ public void encode(InputStream is, OutputStream os, byte[] prefix) throws IOException {
+ os.write(prefix);
+ encode(is,os);
+ }
+
+ /**
+ * encode InputStream onto Output Stream
+ *
+ * @param is
+ * @param estimate
+ * @return
+ * @throws IOException
+ */
+ public void encode(InputStream is, OutputStream os) throws IOException {
+ // StringBuilder sb = new StringBuilder((int)(estimate*1.255)); // try to get the right size of StringBuilder from start.. slightly more than 1.25 times
+ int prev=0;
+ int read, idx=0, line=0;
+ boolean go;
+ do {
+ read = is.read();
+ if(go = read>=0) {
+ if(line>=splitLinesAt) {
+ os.write('\n');
+ line = 0;
+ }
+ switch(++idx) { // 1 based reading, slightly faster ++
+ case 1: // ptr is the first 6 bits of read
+ os.write(codeset[read>>2]);
+ prev = read;
+ break;
+ case 2: // ptr is the last 2 bits of prev followed by the first 4 bits of read
+ os.write(codeset[((prev & 0x03)<<4) | (read>>4)]);
+ prev = read;
+ break;
+ default: //(3+)
+ // Char 1 is last 4 bits of prev plus the first 2 bits of read
+ // Char 2 is the last 6 bits of read
+ os.write(codeset[(((prev & 0xF)<<2) | (read>>6))]);
+ if(line==splitLinesAt) { // deal with line splitting for two characters
+ os.write('\n');
+ line=0;
+ }
+ os.write(codeset[(read & 0x3F)]);
+ ++line;
+ idx = 0;
+ prev = 0;
+ }
+ ++line;
+ } else { // deal with any remaining bits from Prev, then pad
+ switch(idx) {
+ case 1: // just the last 2 bits of prev
+ os.write(codeset[(prev & 0x03)<<4]);
+ if(endEquals)os.write(DOUBLE_EQ);
+ break;
+ case 2: // just the last 4 bits of prev
+ os.write(codeset[(prev & 0xF)<<2]);
+ if(endEquals)os.write('=');
+ break;
+ }
+ idx = 0;
+ }
+
+ } while(go);
+ }
+
+ public void decode(InputStream is, OutputStream os, int skip) throws IOException {
+ is.skip(skip);
+ decode(is,os);
+ }
+
+ /**
+ * Decode InputStream onto OutputStream
+ * @param is
+ * @param os
+ * @throws IOException
+ */
+ public void decode(InputStream is, OutputStream os) throws IOException {
+ int read, idx=0;
+ int prev=0, index;
+ while((read = is.read())>=0) {
+ index = convert.convert(read);
+ if(index>=0) {
+ switch(++idx) { // 1 based cases, slightly faster ++
+ case 1: // index goes into first 6 bits of prev
+ prev = index<<2;
+ break;
+ case 2: // write second 2 bits of into prev, write byte, last 4 bits go into prev
+ os.write((byte)(prev|(index>>4)));
+ prev = index<<4;
+ break;
+ case 3: // first 4 bits of index goes into prev, write byte, last 2 bits go into prev
+ os.write((byte)(prev|(index>>2)));
+ prev = index<<6;
+ break;
+ default: // (3+) | prev and last six of index
+ os.write((byte)(prev|(index&0x3F)));
+ idx = prev = 0;
+ }
+ }
+ };
+ os.flush();
+ }
+
+ /**
+ * Interface to allow this class to choose which algorithm to find index of character in Key
+ *
+ */
+ private interface Convert {
+ public int convert(int read) throws IOException;
+ }
+
+ /**
+ * Ordered uses a range of orders to compare against, rather than requiring the investigation
+ * of every character needed.
+ *
+ */
+ private static final class Ordered implements Convert {
+ private int[][] range;
+ public Ordered(int[][] range) {
+ this.range = range;
+ }
+ public int convert(int read) throws IOException {
+ switch(read) {
+ case -1:
+ case '=':
+ case '\n':
+ return -1;
+ }
+ for(int i=0;i<range.length;++i) {
+ if(read >= range[i][0] && read<=range[i][1]) {
+ return read-range[i][2];
+ }
+ }
+ throw new IOException("Unacceptable Character in Stream");
+ }
+ }
+
+ /**
+ * Unordered, i.e. the key is purposely randomized, simply has to investigate each character
+ * until we find a match.
+ *
+ */
+ private static final class Unordered implements Convert {
+ private char[] codec;
+ public Unordered(char[] codec) {
+ this.codec = codec;
+ }
+ public int convert(int read) throws IOException {
+ switch(read) {
+ case -1:
+ case '=':
+ case '\n':
+ return -1;
+ }
+ for(int i=0;i<codec.length;++i) {
+ if(codec[i]==read)return i;
+ }
+ // don't give clue in Encryption mode
+ throw new IOException("Unacceptable Character in Stream");
+ }
+ }
+
+ /**
+ * Generate a 2048 based Key from which we extract our code base
+ *
+ * @return
+ * @throws IOException
+ */
+ public byte[] keygen() throws IOException {
+ byte inkey[] = new byte[0x600];
+ new SecureRandom().nextBytes(inkey);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(0x800);
+ base64url.encode(new ByteArrayInputStream(inkey), baos);
+ return baos.toByteArray();
+ }
+
+ // A class allowing us to be less predictable about significant digits (i.e. not picking them up from the
+ // beginning, and not picking them up in an ordered row. Gives a nice 2048 with no visible patterns.
+ private class Obtain {
+ private int last;
+ private int skip;
+ private int length;
+ private byte[] key;
+
+ private Obtain(Symm b64, byte[] key) {
+ skip = Math.abs(key[key.length-13]%key.length);
+ if((key.length&0x1) == (skip&0x1)) { // if both are odd or both are even
+ ++skip;
+ }
+ length = b64.codeset.length;
+ last = 17+length%59; // never start at beginning
+ this.key = key;
+ }
+
+ private int next() {
+ return Math.abs(key[(++last*skip)%key.length])%length;
+ }
+ };
+
+ /**
+ * Obtain a Symm from "keyfile" (Config.KEYFILE) property
+ *
+ * @param acesss
+ * @return
+ */
+ public static Symm obtain(Access access) {
+ Symm symm = Symm.baseCrypt();
+
+ String keyfile = access.getProperty(Config.CADI_KEYFILE,null);
+ if(keyfile!=null) {
+ File file = new File(keyfile);
+ try {
+ access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getCanonicalPath());
+ } catch (IOException e1) {
+ access.log(Level.INIT, Config.CADI_KEYFILE,"points to",file.getAbsolutePath());
+ }
+ if(file.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ }
+ }
+ } catch (IOException e) {
+ access.log(e, "Cannot load keyfile");
+ }
+ }
+ }
+ return symm;
+ }
+ /**
+ * Create a new random key
+ */
+ public Symm obtain() throws IOException {
+ byte inkey[] = new byte[0x800];
+ new SecureRandom().nextBytes(inkey);
+ return obtain(inkey);
+ }
+
+ /**
+ * Obtain a Symm from 2048 key from a String
+ *
+ * @param key
+ * @return
+ * @throws IOException
+ */
+ public static Symm obtain(String key) throws IOException {
+ return obtain(new ByteArrayInputStream(key.getBytes()));
+ }
+
+ /**
+ * Obtain a Symm from 2048 key from a Stream
+ *
+ * @param is
+ * @return
+ * @throws IOException
+ */
+ public static Symm obtain(InputStream is) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ base64url.decode(is, baos);
+ } catch (IOException e) {
+ // don't give clue
+ throw new IOException("Invalid Key");
+ }
+ byte[] bkey = baos.toByteArray();
+ if(bkey.length<0x88) { // 2048 bit key
+ throw new IOException("Invalid key");
+ }
+ return baseCrypt().obtain(bkey);
+ }
+
+ /**
+ * Convenience for picking up Keyfile
+ *
+ * @param f
+ * @return
+ * @throws IOException
+ */
+ public static Symm obtain(File f) throws IOException {
+ FileInputStream fis = new FileInputStream(f);
+ try {
+ return obtain(fis);
+ } finally {
+ fis.close();
+ }
+ }
+ /**
+ * Decrypt into a String
+ *
+ * Convenience method
+ *
+ * @param password
+ * @return
+ * @throws IOException
+ */
+ public String enpass(String password) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ enpass(password,baos);
+ return new String(baos.toByteArray());
+ }
+
+ /**
+ * Create an encrypted password, making sure that even short passwords have a minimum length.
+ *
+ * @param password
+ * @param os
+ * @throws IOException
+ */
+ public void enpass(final String password, final OutputStream os) throws IOException {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ byte[] bytes = password.getBytes();
+ if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
+ dos.write(bytes);
+ } else {
+
+ Random r = new SecureRandom();
+ int start = 0;
+ byte b;
+ for(int i=0;i<3;++i) {
+ dos.writeByte(b=(byte)r.nextInt());
+ start+=Math.abs(b);
+ }
+ start%=0x7;
+ for(int i=0;i<start;++i) {
+ dos.writeByte(r.nextInt());
+ }
+ dos.writeInt((int)System.currentTimeMillis());
+ int minlength = Math.min(0x9,bytes.length);
+ dos.writeByte(minlength); // expect truncation
+ if(bytes.length<0x9) {
+ for(int i=0;i<bytes.length;++i) {
+ dos.writeByte(r.nextInt());
+ dos.writeByte(bytes[i]);
+ }
+ // make sure it's long enough
+ for(int i=bytes.length;i<0x9;++i) {
+ dos.writeByte(r.nextInt());
+ }
+ } else {
+ dos.write(bytes);
+ }
+ }
+
+ // 7/21/2016 jg add AES Encryption to the mix
+ exec(new AESExec() {
+ @Override
+ public void exec(AES aes) throws IOException {
+ CipherInputStream cis = aes.inputStream(new ByteArrayInputStream(baos.toByteArray()), true);
+ try {
+ encode(cis,os);
+ } finally {
+ os.flush();
+ cis.close();
+ }
+ }
+ });
+ synchronized(ENC) {
+ }
+ }
+
+ /**
+ * Decrypt a password into a String
+ *
+ * Convenience method
+ *
+ * @param password
+ * @return
+ * @throws IOException
+ */
+ public String depass(String password) throws IOException {
+ if(password==null)return null;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ depass(password,baos);
+ return new String(baos.toByteArray());
+ }
+
+ /**
+ * Decrypt a password
+ *
+ * Skip Symm.ENC
+ *
+ * @param password
+ * @param os
+ * @return
+ * @throws IOException
+ */
+ public long depass(final String password, final OutputStream os) throws IOException {
+ int offset = password.startsWith(ENC)?4:0;
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final ByteArrayInputStream bais = new ByteArrayInputStream(password.getBytes(),offset,password.length()-offset);
+ exec(new AESExec() {
+ @Override
+ public void exec(AES aes) throws IOException {
+ CipherOutputStream cos = aes.outputStream(baos, false);
+ decode(bais,cos);
+ cos.close(); // flush
+ }
+ });
+ byte[] bytes = baos.toByteArray();
+ DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));
+ long time;
+ if(this.getClass().getSimpleName().startsWith("base64")) { // don't expose randomization
+ os.write(bytes);
+ time = 0L;
+ } else {
+ int start=0;
+ for(int i=0;i<3;++i) {
+ start+=Math.abs(dis.readByte());
+ }
+ start%=0x7;
+ for(int i=0;i<start;++i) {
+ dis.readByte();
+ }
+ time = (dis.readInt() & 0xFFFF)|(System.currentTimeMillis()&0xFFFF0000);
+ int minlength = dis.readByte();
+ if(minlength<0x9){
+ DataOutputStream dos = new DataOutputStream(os);
+ for(int i=0;i<minlength;++i) {
+ dis.readByte();
+ dos.writeByte(dis.readByte());
+ }
+ } else {
+ int pre =((Byte.SIZE*3+Integer.SIZE+Byte.SIZE)/Byte.SIZE)+start;
+ os.write(bytes, pre, bytes.length-pre);
+ }
+ }
+ return time;
+ }
+
+ public static String randomGen(int numBytes) {
+ return randomGen(passChars,numBytes);
+ }
+
+ public static String randomGen(char[] chars ,int numBytes) {
+ int rint;
+ StringBuilder sb = new StringBuilder(numBytes);
+ for(int i=0;i<numBytes;++i) {
+ rint = random.nextInt(chars.length);
+ sb.append(chars[rint]);
+ }
+ return sb.toString();
+ }
+ // Internal mechanism for helping to randomize placement of characters within a Symm codeset
+ // Based on an incoming data stream (originally created randomly, but can be recreated within
+ // 2048 key), go after a particular place in the new codeset. If that codeset spot is used, then move
+ // right or left (depending on iteration) to find the next available slot. In this way, key generation
+ // is speeded up by only enacting N iterations, but adds a spreading effect of the random number stream, so that keyset is also
+ // shuffled for a good spread. It is, however, repeatable, given the same number set, allowing for
+ // quick recreation when the official stream is actually obtained.
+ public Symm obtain(byte[] key) throws IOException {
+ try {
+ byte[] bytes = new byte[AES.AES_KEY_SIZE/8];
+ int offset = (Math.abs(key[(47%key.length)])+137)%(key.length-bytes.length);
+ for(int i=0;i<bytes.length;++i) {
+ bytes[i] = key[i+offset];
+ }
+
+ aes = new AES(bytes,0,bytes.length);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ int filled = codeset.length;
+ char[] seq = new char[filled];
+ int end = filled--;
+
+ boolean right = true;
+ int index;
+ Obtain o = new Obtain(this,key);
+
+ while(filled>=0) {
+ index = o.next();
+ if(index<0 || index>=codeset.length) {
+ System.out.println("uh, oh");
+ }
+ if(right) { // alternate going left or right to find the next open slot (keeps it from taking too long to hit something)
+ for(int j=index;j<end;++j) {
+ if(seq[j]==0) {
+ seq[j]=codeset[filled];
+ --filled;
+ break;
+ }
+ }
+ right = false;
+ } else {
+ for(int j=index;j>=0;--j) {
+ if(seq[j]==0) {
+ seq[j]=codeset[filled];
+ --filled;
+ break;
+ }
+ }
+ right = true;
+ }
+ }
+ return new Symm(seq,this);
+ }
+}
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
index 0000000..7ba6fb4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Taf.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import com.att.cadi.taf.TafResp;
+
+
+/**
+ * TAF - Transmutative Assertion Framework.
+ *
+ * This main Interface embodies the essential of the assertion, where a number of different TAFs might be used to authenticate
+ * and that authentication to be recognized through other elements.
+ *
+ * Concept by Robert Garskof. Implemented by Jonathan Gathman
+ *
+ *
+ */
+public interface Taf {
+ enum LifeForm {CBLF, SBLF, LFN};
+ /**
+ * The lifeForm param is a humorous way of describing whether the interaction is proceeding from direct Human Interaction via a browser
+ * or App which can directly query a memorized password, key sequence, bio-feedback, from that user, or a machine mechanism for which identity
+ * can more easily be determined by Certificate, Mechanical ID/Password etc. Popularized in modern culture and Science Fiction (especially
+ * 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
+ * "Silicon Based Life Forms" (SBLF) to indicate machine only interactions. I have added "LFN" for (Life-Form Neutral) to aid identifying
+ * processes for which it doesn't matter whether there is a human at the immediate end of the chain, or cannot be determined mechanically.
+ *
+ * The variable parameter is not necessarily ideal, but with too many unknown Tafs to be created, flexibility,
+ * is unfortunately required at this point. Future versions could lock this down more. JG 10/18/2012
+ *
+ * @param lifeForm
+ * @param info
+ * @return
+ */
+ public TafResp validate(LifeForm reading, String ... info);
+
+}
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
index 0000000..e392e86
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/Transmutate.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+
+/**
+ * The unique element of TAF is that we establish the relationship/mechanism to mutate the Principal derived from
+ * one Authentication mechanism into a trustable Principal of another. The mechanism needs to be decided by system
+ * trusting.
+ *
+ * The Generic "T" is used so that the code used will be very specific for the implementation, enforced by Compiler
+ *
+ * This interface will allow differences of trusting Transmutation of Authentication
+ *
+ */
+public interface Transmutate<T> {
+ /**
+ * Mutate the (assumed validated) Principal into the expected Principal name to be used to construct
+ *
+ * @param p
+ * @return
+ */
+ public T mutate(Principal p);
+}
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
index 0000000..2cf2203
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/TrustChecker.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.att.cadi.taf.TafResp;
+
+/**
+ * Change to another Principal based on Trust of caller and User Chain (if desired)
+ *
+ *
+ */
+public interface TrustChecker {
+ public TafResp mayTrust(TafResp tresp, HttpServletRequest req);
+
+ /**
+ * A class that trusts no-one else, so just return same TResp
+ */
+ public static TrustChecker NOTRUST = new TrustChecker() {
+ @Override
+ public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {
+ return tresp;
+ }
+
+ @Override
+ public void setLur(Lur lur) {
+ }
+ };
+
+ public void setLur(Lur lur);
+}
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
index 0000000..6903cb3
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/User.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.att.cadi.lur.LocalPermission;
+
+/**
+ * Class to hold info from the User Perspective.
+ *
+ *
+ */
+public final class User<PERM extends Permission> {
+ private static Map<String,Permission> NULL_MAP = new HashMap<String,Permission>();
+ public Principal principal;
+ Map<String, Permission> perms ;
+ long permExpires;
+ private final long interval;
+ int count;
+
+ // Note: This should only be used for Local RBAC (in memory)
+ public User(Principal principal) {
+ this.principal = principal;
+ perms = NULL_MAP;
+ permExpires = Long.MAX_VALUE; // Never. Well, until 64 bits of millis since 1970 expires...
+ interval = 0L;
+ count = 0;
+ }
+
+ public User(Principal principal, long expireInterval) {
+ this.principal = principal;
+ perms = NULL_MAP;
+ expireInterval = Math.max(expireInterval, 0); // avoid < 1
+ interval = Math.max(AbsUserCache.MIN_INTERVAL,Math.min(expireInterval,AbsUserCache.MAX_INTERVAL));
+ permExpires = 0;
+ count = 0;
+ }
+
+ public void renewPerm() {
+ permExpires = System.currentTimeMillis()+interval;
+ }
+
+ public long permExpires() {
+ return permExpires;
+ }
+
+ public boolean permExpired() {
+ return System.currentTimeMillis() > permExpires;
+ }
+
+ public boolean noPerms() {
+ return perms==null || perms.values().size()==0;
+ }
+
+ public void setNoPerms() {
+ perms=NULL_MAP;
+ permExpires = System.currentTimeMillis() + interval;
+ }
+
+ public boolean permsUnloaded() {
+ return perms==null;
+ }
+
+ public synchronized void incCount() {
+ ++count;
+ }
+
+ public synchronized void resetCount() {
+ count=0;
+ }
+
+ public Map<String,Permission> newMap() {
+ return new ConcurrentHashMap<String,Permission>();
+ }
+
+ public void add(LocalPermission permission) {
+ if(perms==NULL_MAP)perms=newMap();
+ perms.put(permission.getKey(),permission);
+ }
+
+ public void add(Map<String, Permission> newMap, PERM permission) {
+ newMap.put(permission.getKey(),permission);
+ }
+
+ public void setMap(Map<String, Permission> newMap) {
+ perms = newMap;
+ }
+
+ public boolean contains(Permission perm) {
+ for (Permission p : perms.values()) {
+ if (p.match(perm)) return true;
+ }
+ return false;
+ }
+
+ public void copyPermsTo(List<Permission> sink) {
+ sink.addAll(perms.values());
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(principal.getName());
+ sb.append('|');
+ boolean first = true;
+ synchronized(perms) {
+ for(Permission gp : perms.values()) {
+ if(first) {
+ first = false;
+ sb.append(':');
+ } else {
+ sb.append(',');
+ }
+ sb.append(gp.getKey());
+ }
+ }
+ return sb.toString();
+ }
+
+}
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
index 0000000..90c47c1
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/UserChain.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+/**
+ * Interface to add a User Chain String to Principal
+ *
+ *
+ *
+ * Where
+ * APP is name suitable for Logging (i.e. official App Acronym)
+ * ID is official User or MechID, best if includes Identity Source (i.e. ab1234@csp.att.com)
+ * Protocol is the Security protocol,
+ *
+ * Format:<ID>:<APP>:<protocol>[:AS][,<ID>:<APP>:<protocol>]*
+ *
+ *
+ *
+ */
+public interface UserChain {
+ public enum Protocol {BasicAuth,Cookie,Cert,OAuth};
+ public String userChain();
+}
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
index 0000000..dd8e56d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/Config.java
@@ -0,0 +1,815 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.TimerTask;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachingLur;
+import com.att.cadi.CadiException;
+import com.att.cadi.CredVal;
+import com.att.cadi.Locator;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.lur.LocalLur;
+import com.att.cadi.lur.NullLur;
+import com.att.cadi.taf.HttpEpiTaf;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.basic.BasicHttpTaf;
+import com.att.cadi.taf.cert.X509Taf;
+import com.att.cadi.taf.dos.DenialOfServiceTaf;
+
+/**
+ * Create a Consistent Configuration mechanism, even when configuration styles are as vastly different as
+ * Properties vs JavaBeans vs FilterConfigs...
+ *
+ *
+ */
+public class Config {
+
+ private static final String HIDE_PASS = "***************";
+
+ public static final String UTF_8 = "UTF-8";
+
+ // Property Names associated with configurations.
+ // As of 1.0.2, these have had the dots removed so as to be compatible with JavaBean style
+ // configurations as well as property list style.
+ public static final String HOSTNAME = "hostname";
+ public static final String CADI_PROP_FILES = "cadi_prop_files"; // Additional Properties files (separate with ;)
+ public static final String CADI_LOGLEVEL = "cadi_loglevel";
+ public static final String CADI_LOGNAME = "cadi_logname";
+ public static final String CADI_KEYFILE = "cadi_keyfile";
+ public static final String CADI_KEYSTORE = "cadi_keystore";
+ public static final String CADI_KEYSTORE_PASSWORD = "cadi_keystore_password";
+ public static final String CADI_ALIAS = "cadi_alias";
+ public static final String CADI_LOGINPAGE_URL = "cadi_loginpage_url";
+
+ public static final String CADI_KEY_PASSWORD = "cadi_key_password";
+ public static final String CADI_TRUSTSTORE = "cadi_truststore";
+ public static final String CADI_TRUSTSTORE_PASSWORD = "cadi_truststore_password";
+ public static final String CADI_X509_ISSUERS = "cadi_x509_issuers";
+ public static final String CADI_TRUST_MASKS="cadi_trust_masks";
+ public static final String CADI_TRUST_PERM="cadi_trust_perm"; // IDs with this perm can utilize the "AS " user concept
+ public static final String CADI_PROTOCOLS = "cadi_protocols";
+ public static final String CADI_NOAUTHN = "cadi_noauthn";
+ public static final String CADI_LOC_LIST = "cadi_loc_list";
+
+ public static final String CADI_USER_CHAIN_TAG = "cadi_user_chain";
+ public static final String CADI_USER_CHAIN = "USER_CHAIN";
+
+
+
+ public static final String CSP_DOMAIN = "csp_domain";
+ public static final String CSP_HOSTNAME = "csp_hostname";
+ public static final String CSP_DEVL_LOCALHOST = "csp_devl_localhost";
+ public static final String CSP_USER_HEADER = "CSP_USER";
+ public static final String CSP_SYSTEMS_CONF = "CSPSystems.conf";
+ public static final String CSP_SYSTEMS_CONF_FILE = "csp_systems_conf_file";
+
+
+ public static final String TGUARD_ENV="tguard_env";
+ public static final String TGUARD_DOMAIN = "tguard_domain";
+ public static final String TGUARD_TIMEOUT = "tguard_timeout";
+ public static final String TGUARD_TIMEOUT_DEF = "5000";
+ public static final String TGUARD_CERTS = "tguard_certs"; // comma delimited SHA-256 finger prints
+// public static final String TGUARD_DEVL_LOCALHOST = "tguard_devl_localhost";
+// public static final String TGUARD_USER_HEADER = "TGUARD_USER";
+
+ public static final String LOCALHOST_ALLOW = "localhost_allow";
+ public static final String LOCALHOST_DENY = "localhost_deny";
+
+ public static final String BASIC_REALM = "basic_realm"; // what is sent to the client
+ public static final String BASIC_WARN = "basic_warn"; // Warning of insecure channel
+ public static final String USERS = "local_users";
+ public static final String GROUPS = "local_groups";
+ public static final String WRITE_TO = "local_writeto"; // dump RBAC to local file in Tomcat Style (some apps use)
+
+ public static final String AAF_ENV = "aaf_env";
+ public static final String AAF_ROOT_NS = "aaf_root_ns";
+ public static final String AAF_ROOT_COMPANY = "aaf_root_company";
+ public static final String AAF_URL = "aaf_url"; //URL for AAF... Use to trigger AAF configuration
+ public static final String AAF_MECHID = "aaf_id";
+ public static final String AAF_MECHPASS = "aaf_password";
+ public static final String AAF_LUR_CLASS = "aaf_lur_class";
+ public static final String AAF_TAF_CLASS = "aaf_taf_class";
+ public static final String AAF_CONNECTOR_CLASS = "aaf_connector_class";
+ public static final String AAF_LOCATOR_CLASS = "aaf_locator_class";
+ public static final String AAF_CONN_TIMEOUT = "aaf_conn_timeout";
+ public static final String AAF_CONN_TIMEOUT_DEF = "3000";
+ public static final String AAF_READ_TIMEOUT = "aaf_timeout";
+ public static final String AAF_READ_TIMEOUT_DEF = "5000";
+ public static final String AAF_USER_EXPIRES = "aaf_user_expires";
+ public static final String AAF_USER_EXPIRES_DEF = "600000"; // Default is 10 mins
+ public static final String AAF_CLEAN_INTERVAL = "aaf_clean_interval";
+ public static final String AAF_CLEAN_INTERVAL_DEF = "30000"; // Default is 30 seconds
+ public static final String AAF_REFRESH_TRIGGER_COUNT = "aaf_refresh_trigger_count";
+ public static final String AAF_REFRESH_TRIGGER_COUNT_DEF = "3"; // Default is 10 mins
+
+ public static final String AAF_HIGH_COUNT = "aaf_high_count";
+ public static final String AAF_HIGH_COUNT_DEF = "1000"; // Default is 1000 entries
+ public static final String AAF_PERM_MAP = "aaf_perm_map";
+ public static final String AAF_DEPLOYED_VERSION = "DEPLOYED_VERSION";
+ public static final String AAF_CERT_IDS = "aaf_cert_ids";
+ public static final String AAF_DEBUG_IDS = "aaf_debug_ids"; // comma delimited
+
+ public static final String GW_URL = "gw_url";
+ public static final String CM_URL = "cm_url";
+ public static final String CM_TRUSTED_CAS = "cm_trusted_cas";
+
+ public static final String PATHFILTER_URLPATTERN = "pathfilter_urlpattern";
+ public static final String PATHFILTER_STACK = "pathfilter_stack";
+ public static final String PATHFILTER_NS = "pathfilter_ns";
+ public static final String PATHFILTER_NOT_AUTHORIZED_MSG = "pathfilter_not_authorized_msg";
+
+ public static final String AFT_DME2_TRUSTSTORE_PASSWORD = "AFT_DME2_TRUSTSTORE_PASSWORD";
+ public static final String AFT_DME2_TRUSTSTORE = "AFT_DME2_TRUSTSTORE";
+ public static final String AFT_DME2_KEYSTORE_PASSWORD = "AFT_DME2_KEYSTORE_PASSWORD";
+ public static final String AFT_DME2_KEY_PASSWORD = "AFT_DME2_KEY_PASSWORD";
+ public static final String AFT_DME2_KEYSTORE = "AFT_DME2_KEYSTORE";
+ public static final String AFT_DME2_SSL_TRUST_ALL = "AFT_DME2_SSL_TRUST_ALL";
+ public static final String AFT_DME2_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_SSL_INCLUDE_PROTOCOLS";
+
+
+ // DME2 Client. First property must be set to "false", and the others set in order to use SSL Client
+ public static final String AFT_DME2_CLIENT_IGNORE_SSL_CONFIG="AFT_DME2_CLIENT_IGNORE_SSL_CONFIG";
+ public static final String AFT_DME2_CLIENT_KEYSTORE = "AFT_DME2_CLIENT_KEYSTORE";
+ public static final String AFT_DME2_CLIENT_KEYSTORE_PASSWORD = "AFT_DME2_CLIENT_KEYSTORE_PASSWORD";
+ public static final String AFT_DME2_CLIENT_TRUSTSTORE = "AFT_DME2_CLIENT_TRUSTSTORE";
+ public static final String AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD = "AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD";
+ public static final String AFT_DME2_CLIENT_SSL_CERT_ALIAS = "AFT_DME2_CLIENT_SSL_CERT_ALIAS";
+ public static final String AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS";
+
+
+ // This one should go unpublic
+ public static final String AAF_DEFAULT_REALM = "aaf_default_realm";
+ private static String defaultRealm="none";
+
+ public static final String AAF_DOMAIN_SUPPORT = "aaf_domain_support";
+ //public static final String AAF_DOMAIN_SUPPORT_DEF = ".com";
+ public static final String AAF_DOMAIN_SUPPORT_DEF = ".org";
+
+
+ public static void setDefaultRealm(Access access) throws CadiException {
+ try {
+ boolean hasCSP;
+ try {
+ Class.forName("com.att.cadi.taf.csp.CSPTaf");
+ hasCSP=true;
+ } catch(ClassNotFoundException e) {
+ hasCSP = logProp(access,Config.CSP_DOMAIN, null)!=null;
+ }
+ defaultRealm = logProp(access,Config.AAF_DEFAULT_REALM,
+ hasCSP?"csp.att.com":
+ logProp(access,Config.BASIC_REALM,
+ logProp(access,HOSTNAME,InetAddress.getLocalHost().getHostName())
+ )
+ );
+ } catch (UnknownHostException e) {
+ //defaultRealm="none";
+ }
+ }
+
+
+ public static HttpTaf configHttpTaf(Access access, TrustChecker tc, CredVal up, Lur lur, Object ... additionalTafLurs) throws CadiException {
+ /////////////////////////////////////////////////////
+ // Setup AAFCon for any following
+ /////////////////////////////////////////////////////
+ Object aafcon = null;
+ if(lur != null) {
+ Field f = null;
+ try {
+ f = lur.getClass().getField("aaf");
+ aafcon = f.get(lur);
+ } catch (Exception nsfe) {
+ }
+ }
+ // IMPORTANT! Don't attempt to load AAF Connector if there is no AAF URL
+ String aafURL = access.getProperty(AAF_URL,null);
+ if(aafcon==null && aafURL!=null) {
+ aafcon = loadAAFConnector(access, aafURL);
+ }
+
+ HttpTaf taf;
+ // Setup Host, in case Network reports an unusable Hostname (i.e. VTiers, VPNs, etc)
+ String hostname = logProp(access, HOSTNAME,null);
+ if(hostname==null) {
+ try {
+ hostname = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e1) {
+ throw new CadiException("Unable to determine Hostname",e1);
+ }
+ }
+
+ access.log(Level.INIT, "Hostname set to",hostname);
+ // Get appropriate TAFs
+ ArrayList<HttpTaf> htlist = new ArrayList<HttpTaf>();
+
+ /////////////////////////////////////////////////////
+ // Add a Denial of Service TAF
+ // Note: how IPs and IDs are added are up to service type.
+ // They call "DenialOfServiceTaf.denyIP(String) or denyID(String)
+ /////////////////////////////////////////////////////
+ htlist.add(new DenialOfServiceTaf(access));
+
+ /////////////////////////////////////////////////////
+ // Configure LocalHost
+ /////////////////////////////////////////////////////
+
+ String truststore = logProp(access, CADI_TRUSTSTORE, access.getProperty("AFT_DME2_TRUSTSTORE", null));
+ if(truststore!=null) {
+ String truststore_pwd = access.getProperty(CADI_TRUSTSTORE_PASSWORD, access.getProperty("AFT_DME2_TRUSTSTORE_PASSWORD",null));
+ if(truststore_pwd!=null) {
+ if(truststore_pwd.startsWith(Symm.ENC)) {
+ try {
+ truststore_pwd = access.decrypt(truststore_pwd,false);
+ } catch (IOException e) {
+ throw new CadiException(CADI_TRUSTSTORE_PASSWORD + " cannot be decrypted",e);
+ }
+ }
+ try {
+ htlist.add(new X509Taf(access,lur));
+ access.log(Level.INIT,"Certificate Authorization enabled");
+ } catch (SecurityException e) {
+ access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);
+ } catch (IllegalArgumentException e) {
+ access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);
+ } catch (CertificateException e) {
+ access.log(Level.INIT,"Certificate Authorization failed, it is disabled",e);
+ } catch (NoSuchAlgorithmException e) {
+ access.log(Level.INIT,"Certificate Authorization failed, wrong Security Algorithm",e);
+ }
+ }
+ } else {
+ access.log(Level.INIT,"Certificate Authorization not enabled");
+ }
+
+ /////////////////////////////////////////////////////
+ // Configure Basic Auth (local content)
+ /////////////////////////////////////////////////////
+ String basic_realm = logProp(access, BASIC_REALM,null);
+ boolean basic_warn = "TRUE".equals(access.getProperty(BASIC_WARN,"FALSE"));
+ if(basic_realm!=null && up!=null) {
+ access.log(Level.INIT,"Basic Authorization is enabled using realm",basic_realm);
+ // Allow warning about insecure channel to be turned off
+ if(!basic_warn)access.log(Level.INIT,"WARNING! The basic_warn property has been set to false.",
+ " There will be no additional warning if Basic Auth is used on an insecure channel"
+ );
+ String aafCleanup = logProp(access, AAF_USER_EXPIRES,AAF_USER_EXPIRES_DEF); // Default is 10 mins
+ long userExp = Long.parseLong(aafCleanup);
+
+ htlist.add(new BasicHttpTaf(access, up, basic_realm, userExp, basic_warn));
+ } else {
+ access.log(Level.INIT,"Local Basic Authorization is disabled. Enable by setting basic_realm=<appropriate realm, i.e. my.att.com>");
+ }
+
+ /////////////////////////////////////////////////////
+ // Configure AAF Driven Basic Auth
+ /////////////////////////////////////////////////////
+ boolean getRemoteAAF = true;
+ if(additionalTafLurs!=null) {
+ for(Object o : additionalTafLurs) {
+ if(o.getClass().getSimpleName().equals("DirectAAFLur")) {
+ getRemoteAAF = false;
+ break;
+ }
+ }
+ }
+ HttpTaf aaftaf=null;
+ if(getRemoteAAF) {
+ if(aafcon==null) {
+ access.log(Level.INIT,"AAF Connection (AAFcon) is null. Cannot create an AAF TAF");
+ } else if(aafURL==null) {
+ access.log(Level.INIT,"No AAF URL in properties, Cannot create an AAF TAF");
+ } else {// There's an AAF_URL... try to configure an AAF
+ String defName = aafURL.contains("version=2.0")?"com.att.cadi.aaf.v2_0.AAFTaf":"";
+ String aafTafClassName = logProp(access, AAF_TAF_CLASS,defName);
+ // Only 2.0 available at this time
+ if("com.att.cadi.aaf.v2_0.AAFTaf".equals(aafTafClassName)) {
+ try {
+ Class<?> aafTafClass = loadClass(access,aafTafClassName);
+ Class<?> aafConClass = loadClass(access,"com.att.cadi.aaf.v2_0.AAFCon");
+
+ Constructor<?> cstr = aafTafClass.getConstructor(aafConClass,boolean.class,AbsUserCache.class);
+ if(cstr!=null) {
+ aaftaf = (HttpTaf)cstr.newInstance(aafcon,basic_warn,lur);
+ if(aaftaf==null) {
+ access.log(Level.INIT,"ERROR! AAF TAF Failed construction. NOT Configured");
+ } else {
+ access.log(Level.INIT,"AAF TAF Configured to ",aafURL);
+ // Note: will add later, after all others configured
+ }
+ }
+ } catch(Exception e) {
+ access.log(Level.INIT,"ERROR! AAF TAF Failed construction. NOT Configured");
+ }
+ }
+ }
+ }
+
+
+ String alias = logProp(access, CADI_ALIAS,null);
+
+ /////////////////////////////////////////////////////
+ // Configure tGuard... (AT&T Client Repo)
+ /////////////////////////////////////////////////////
+ // TGUARD Environment, translated to any other remote Environment validation mechanism...
+ String tGuard_domain = logProp(access, TGUARD_DOMAIN,null);
+ String tGuard_env = logProp(access, TGUARD_ENV, null);
+
+ if(!("PROD".equals(tGuard_env) || "STAGE".equals(tGuard_env))) {
+ access.log(Level.INIT, "tGuard Authorization is disabled. Enable by setting", TGUARD_ENV, "to \"PROD\" or \"STAGE\"");
+ } else if(tGuard_domain==null) {
+ access.log(Level.INIT,TGUARD_DOMAIN + " must be set: tGuard Authorization is disabled.");
+ } else if(alias == null) {
+ access.log(Level.INIT,CADI_ALIAS + " must be set: tGuard Authorization is disabled.");
+ } else {
+ try {
+ Class<?> tGuardClass = loadClass(access,"com.att.cadi.tguard.TGuardHttpTaf");
+ if(aaftaf!=null) {
+ Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, AbsUserCache.class});
+ htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {access,aaftaf}));
+ access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");
+ } else {
+ Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, int.class, int.class, int.class});
+ htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {
+ access,
+ Integer.parseInt(logProp(access, AAF_CLEAN_INTERVAL,AAF_CLEAN_INTERVAL_DEF)),
+ Integer.parseInt(logProp(access, AAF_HIGH_COUNT, AAF_HIGH_COUNT_DEF)),
+ Integer.parseInt(logProp(access, AAF_REFRESH_TRIGGER_COUNT, AAF_REFRESH_TRIGGER_COUNT_DEF))
+ }));
+ access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");
+ }
+ } catch(Exception e) {
+ access.log(e, Level.INIT,"tGuard Class cannot be loaded: tGuard Authorization is disabled.");
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Adding BasicAuth (AAF) last, after other primary Cookie Based
+ // Needs to be before Cert... see below
+ /////////////////////////////////////////////////////
+ if(aaftaf!=null) {
+ htlist.add(aaftaf);
+ }
+
+
+ /////////////////////////////////////////////////////
+ // Any Additional Lurs passed in Constructor
+ /////////////////////////////////////////////////////
+ if(additionalTafLurs!=null) {
+ for(Object additional : additionalTafLurs) {
+ if(additional instanceof HttpTaf) {
+ htlist.add((HttpTaf)additional);
+ access.log(Level.INIT,additional);
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Create EpiTaf from configured TAFs
+ /////////////////////////////////////////////////////
+ if(htlist.size()==1) {
+ // just return the one
+ taf = htlist.get(0);
+ } else {
+ HttpTaf[] htarray = new HttpTaf[htlist.size()];
+ htlist.toArray(htarray);
+ Locator<URI> locator = loadLocator(access, logProp(access, CADI_LOGINPAGE_URL, null));
+
+ taf = new HttpEpiTaf(access,locator, tc, htarray); // ok to pass locator == null
+ String level = logProp(access, CADI_LOGLEVEL, null);
+ if(level!=null) {
+ access.setLogLevel(Level.valueOf(level));
+ }
+ }
+
+ return taf;
+ }
+
+ public static String logProp(Access access,String tag, String def) {
+ String rv = access.getProperty(tag, def);
+ if(rv == null) {
+ access.log(Level.INIT,tag,"is not set");
+ } else {
+ access.log(Level.INIT,tag,"is set to",rv);
+ }
+ return rv;
+ }
+
+ public static Lur configLur(Access access, Object ... additionalTafLurs) throws CadiException {
+ List<Lur> lurs = new ArrayList<Lur>();
+
+ /////////////////////////////////////////////////////
+ // Configure a Local Property Based RBAC/LUR
+ /////////////////////////////////////////////////////
+ try {
+ String users = access.getProperty(USERS,null);
+ String groups = access.getProperty(GROUPS,null);
+
+ if(groups!=null || users!=null) {
+ LocalLur ll;
+ lurs.add(ll = new LocalLur(access, users, groups)); // note b64==null is ok.. just means no encryption.
+
+ String writeto = access.getProperty(WRITE_TO,null);
+ if(writeto!=null) {
+ String msg = UsersDump.updateUsers(writeto, ll);
+ if(msg!=null) access.log(Level.INIT,"ERROR! Error Updating ",writeto,"with roles and users:",msg);
+ }
+ }
+ } catch (IOException e) {
+ throw new CadiException(e);
+ }
+
+ /////////////////////////////////////////////////////
+ // Configure the AAF Lur (if any)
+ /////////////////////////////////////////////////////
+ String aafURL = logProp(access,AAF_URL,null); // Trigger Property
+ String aaf_env = access.getProperty(AAF_ENV,null);
+ if(aaf_env == null && aafURL!=null && access instanceof PropAccess) { // set AAF_ENV from AAF_URL
+ int ec = aafURL.indexOf("envContext=");
+ if(ec>0) {
+ ec += 11; // length of envContext=
+ int slash = aafURL.indexOf('/', ec);
+ if(slash>0) {
+ aaf_env = aafURL.substring(ec, slash);
+ ((PropAccess)access).setProperty(AAF_ENV, aaf_env);
+ access.printf(Level.INIT, "Setting aaf_env to %s from aaf_url value",aaf_env);
+ }
+ }
+ }
+
+ if(aafURL==null) {
+ access.log(Level.INIT,"No AAF LUR properties, AAF will not be loaded");
+ } else {// There's an AAF_URL... try to configure an AAF
+ String aafLurClassStr = logProp(access,AAF_LUR_CLASS,"com.att.cadi.aaf.v2_0.AAFLurPerm");
+ ////////////AAF Lur 2.0 /////////////
+ if(aafLurClassStr.startsWith("com.att.cadi.aaf.v2_0")) {
+ try {
+ Object aafcon = loadAAFConnector(access, aafURL);
+ if(aafcon==null) {
+ access.log(Level.INIT,"AAF LUR class,",aafLurClassStr,"cannot be constructed without valid AAFCon object.");
+ } else {
+ Class<?> aafAbsAAFCon = loadClass(access, "com.att.cadi.aaf.v2_0.AAFCon");
+ Method mNewLur = aafAbsAAFCon.getMethod("newLur");
+ Object aaflur = mNewLur.invoke(aafcon);
+
+ if(aaflur==null) {
+ access.log(Level.INIT,"ERROR! AAF LUR Failed construction. NOT Configured");
+ } else {
+ access.log(Level.INIT,"AAF LUR Configured to ",aafURL);
+ lurs.add((Lur)aaflur);
+ String debugIDs = logProp(access,Config.AAF_DEBUG_IDS, null);
+ if(debugIDs !=null && aaflur instanceof CachingLur) {
+ ((CachingLur<?>)aaflur).setDebug(debugIDs);
+ }
+ }
+ }
+ } catch (Exception e) {
+ access.log(e,"AAF LUR class,",aafLurClassStr,"could not be constructed with given Constructors.");
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Any Additional passed in Constructor
+ /////////////////////////////////////////////////////
+ if(additionalTafLurs!=null) {
+ for(Object additional : additionalTafLurs) {
+ if(additional instanceof Lur) {
+ lurs.add((Lur)additional);
+ access.log(Level.INIT, additional);
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Return a Lur based on how many there are...
+ /////////////////////////////////////////////////////
+ switch(lurs.size()) {
+ case 0:
+ access.log(Level.INIT,"WARNING! No CADI LURs configured");
+ // Return a NULL Lur that does nothing.
+ return new NullLur();
+ case 1:
+ return lurs.get(0); // Only one, just return it, save processing
+ default:
+ // Multiple Lurs, use EpiLUR to handle
+ Lur[] la = new Lur[lurs.size()];
+ lurs.toArray(la);
+ return new EpiLur(la);
+ }
+ }
+
+ private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2 = "com.att.cadi.aaf.v2_0.AAFConDME2";
+ private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP = "com.att.cadi.aaf.v2_0.AAFConHttp";
+ public static Object loadAAFConnector(Access access, String aafURL) {
+ Object aafcon = null;
+ Class<?> aafConClass = null;
+
+ try {
+ if(aafURL!=null) {
+ String aafConnector = access.getProperty(AAF_CONNECTOR_CLASS, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);
+ if(COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2.equals(aafConnector) || aafURL.contains("/service=")) {
+ aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2);
+ if(aafConClass!=null) {
+ Constructor<?> cons = aafConClass.getConstructor(PropAccess.class);
+ aafcon = cons.newInstance(access);
+ } else {
+ access.log(Level.ERROR, "URL contains '/service=', which requires DME2");
+ }
+ } else if(COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP.equals(aafConnector)) {
+ aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);
+ for(Constructor<?> c : aafConClass.getConstructors()) {
+ List<Object> lo = new ArrayList<Object>();
+ for(Class<?> pc : c.getParameterTypes()) {
+ if(pc.equals(PropAccess.class)) {
+ lo.add(access);
+ } else if(pc.equals(Locator.class)) {
+ lo.add(loadLocator(access, aafURL));
+ } else {
+ continue;
+ }
+ }
+ if(c.getParameterTypes().length!=lo.size()) {
+ continue; // back to another Constructor
+ } else {
+ aafcon = c.newInstance(lo.toArray());
+ }
+ break;
+ }
+ }
+ if(aafcon!=null) {
+ String mechid = logProp(access,Config.AAF_MECHID, null);
+ String pass = access.getProperty(Config.AAF_MECHPASS, null);
+ if(mechid!=null && pass!=null) {
+ try {
+ Method basicAuth = aafConClass.getMethod("basicAuth", String.class, String.class);
+ basicAuth.invoke(aafcon, mechid,pass);
+ } catch (NoSuchMethodException nsme) {
+ // it's ok, don't use
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ access.log(e,"AAF Connector could not be constructed with given Constructors.");
+ }
+
+ return aafcon;
+ }
+
+ public static Class<?> loadClass(Access access, String className) {
+ Class<?> cls=null;
+ try {
+ cls = access.classLoader().loadClass(className);
+ } catch (ClassNotFoundException cnfe) {
+ try {
+ cls = access.getClass().getClassLoader().loadClass(className);
+ } catch (ClassNotFoundException cnfe2) {
+ // just return null
+ }
+ }
+ return cls;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Locator<URI> loadLocator(Access access, String url) {
+ Locator<URI> locator = null;
+ if(url==null) {
+ access.log(Level.INIT,"No URL for AAF Login Page. Disabled");
+ } else {
+ if(url.contains("DME2RESOLVE")) {
+ try {
+ Class<?> lcls = loadClass(access,"com.att.cadi.locator.DME2Locator");
+ Class<?> dmcls = loadClass(access,"com.att.aft.dme2.api.DME2Manager");
+ Constructor<?> cnst = lcls.getConstructor(new Class[] {Access.class,dmcls,String.class});
+ locator = (Locator<URI>)cnst.newInstance(new Object[] {access,null,url});
+ access.log(Level.INFO, "DME2Locator enabled with " + url);
+ } catch (Exception e) {
+ access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires DME2. It is now disabled",e);
+ }
+ } else {
+ try {
+ Class<?> cls = loadClass(access,"com.att.cadi.locator.PropertyLocator");
+ Constructor<?> cnst = cls.getConstructor(new Class[] {String.class});
+ locator = (Locator<URI>)cnst.newInstance(new Object[] {url});
+ access.log(Level.INFO, "PropertyLocator enabled with " + url);
+ } catch (Exception e) {
+ access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires PropertyLocator. It is now disabled",e);
+ }
+ }
+ }
+ return locator;
+ }
+
+ /*
+ * DME2 can only read Passwords as clear text properties. Leaving in "System Properties" un-encrypted exposes these passwords
+ */
+ public static class PasswordRemoval extends TimerTask {
+ private Access access;
+
+ private final List<String> pws;
+
+ public PasswordRemoval(Access access) {
+ this.access = access;
+ pws = new ArrayList<String>();
+ }
+
+ @Override
+ public void run() {
+ for(String key:pws) {
+ access.log(Level.INIT, "Scrubbing " + key);
+ System.clearProperty(key);
+ }
+ }
+ public void add(String key) {
+ pws.add(key);
+ }
+ }
+
+ private static final String Y = "Y";
+
+ private static String[][] CONVERTER_STRINGS=new String[][] {
+ {AFT_DME2_KEYSTORE,CADI_KEYSTORE,null},
+ {AFT_DME2_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},
+ {AFT_DME2_KEY_PASSWORD,CADI_KEY_PASSWORD,null},
+ {AFT_DME2_TRUSTSTORE,CADI_TRUSTSTORE,null},
+ {AFT_DME2_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},
+ {AFT_DME2_CLIENT_KEYSTORE,CADI_KEYSTORE,null},
+ {AFT_DME2_CLIENT_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},
+ {AFT_DME2_CLIENT_TRUSTSTORE,CADI_TRUSTSTORE,null},
+ {AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},
+ {AFT_DME2_CLIENT_SSL_CERT_ALIAS,CADI_ALIAS,null},
+ {AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},
+ {"AFT_DME2_HOSTNAME",HOSTNAME,null},
+ {"AFT_LATITUDE",null,Y},
+ {"AFT_LONGITUDE",null,Y},
+ {"AFT_ENVIRONMENT",null,Y},
+ {"SCLD_PLATFORM",null,Y},
+ {"DME2_EP_REGISTRY_CLASS",null,Y},// for Developer local access
+ {"AFT_DME2_EP_REGISTRY_FS_DIR",null,Y},
+ {"DME2.DEBUG",null,null},
+ {"AFT_DME2_HTTP_EXCHANGE_TRACE_ON",null,null},
+ {"AFT_DME2_SSL_ENABLE",null,null},
+ {"AFT_DME2_SSL_WANT_CLIENT_AUTH",null,null},
+ {AFT_DME2_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},
+ {"AFT_DME2_SSL_VALIDATE_CERTS",null,null},
+ {AFT_DME2_CLIENT_IGNORE_SSL_CONFIG,null,null},
+ {"https.protocols",CADI_PROTOCOLS,Y},
+ };
+
+
+
+ public static Properties getDME2Props(PropAccess access) {
+ Properties dprops = new Properties();
+ String value = null;
+ boolean reqClientConfig = false;
+ for(String[] row : CONVERTER_STRINGS) {
+ value = access.getProperty(row[0],null);
+ if(value==null) {
+ value = System.getProperty(row[0]);
+ if(value==null && row[1]!=null) {
+ value = access.getProperty(row[1],null);
+ if(value == null) {
+ value = System.getProperty(row[1]);
+ }
+ }
+ }
+ if(value!=null) {
+ if(row[0].contains("_SSL_")) {
+ reqClientConfig = true;
+ }
+ if(row[0].startsWith("AFT") || row[0].startsWith("SCLD") || row[0].contains("DME2")) {
+ if(value.startsWith("enc:")) {
+ try {
+ value = access.decrypt(value, true);
+ } catch (IOException e) {
+ access.log(Level.ERROR, e);
+ }
+ System.setProperty(row[0], value);
+ } else if(Y.equals(row[2])) {
+ System.setProperty(row[0], value);
+ dprops.setProperty(row[0], value);
+ } else if(row[0].contains("PASSWORD") || row[0].contains("STORE")) {
+ System.setProperty(row[0], value);
+ } else {
+ dprops.setProperty(row[0], value);
+ }
+ }
+
+ }
+
+ }
+
+ Properties sprops = System.getProperties();
+ if(reqClientConfig && sprops.getProperty(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {
+ sprops.put(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG, "false");
+ replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE,AFT_DME2_TRUSTSTORE);
+ replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE_PASSWORD,AFT_DME2_TRUSTSTORE_PASSWORD);
+ replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE,AFT_DME2_CLIENT_TRUSTSTORE);
+ replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE_PASSWORD,AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD);
+ }
+
+ if(sprops.getProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS)==null) {
+ sprops.setProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));
+ }
+
+ if(sprops.getProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS)==null) {
+ sprops.setProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));
+ }
+
+ if(access.willLog(Level.DEBUG)) {
+ if(access instanceof PropAccess) {
+ access.log(Level.DEBUG,"Access Properties");
+ for(Entry<Object, Object> es : ((PropAccess)access).getProperties().entrySet()) {
+ access.printf(Level.DEBUG," %s=%s",es.getKey().toString(),es.getValue().toString());
+ }
+ }
+ access.log(Level.DEBUG,"DME2 Properties()");
+ for(Entry<Object, Object> es : dprops.entrySet()) {
+ value = es.getValue().toString();
+ if(es.getKey().toString().contains("PASS")) {
+ if(value==null || !value.contains("enc:")) {
+ value = HIDE_PASS;
+ }
+ }
+ access.printf(Level.DEBUG," %s=%s",es.getKey().toString(),value);
+ }
+
+ access.log(Level.DEBUG,"System (AFT) Properties");
+ for(Entry<Object, Object> es : System.getProperties().entrySet()) {
+ if(es.getKey().toString().startsWith("AFT")) {
+ value = es.getValue().toString();
+ if(es.getKey().toString().contains("PASS")) {
+ if(value==null || !value.contains("enc:")) {
+ value = HIDE_PASS;
+ }
+ }
+ access.printf(Level.DEBUG," %s=%s",es.getKey().toString(),value);
+ }
+ }
+ }
+ // Cover any not specific AFT props
+ String key;
+ for(Entry<Object, Object> es : access.getProperties().entrySet()) {
+ if((key=es.getKey().toString()).startsWith("AFT_") &&
+ !key.contains("PASSWORD") &&
+ dprops.get(key)==null) {
+ dprops.put(key, es.getValue());
+ }
+ }
+ return dprops;
+ }
+
+ private static void replaceKeyWithTrust(Properties props, String ks, String ts) {
+ String value;
+ if(props.get(ks)==null && (value=props.getProperty(ts))!=null) {
+ props.put(ks,value);
+ props.remove(ts);
+ }
+ }
+ // Set by CSP, or is hostname.
+ public static String getDefaultRealm() {
+ return defaultRealm;
+ }
+
+}
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
index 0000000..d6bb35b
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/Get.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import java.lang.reflect.Method;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+
+public interface Get {
+ public String get(String name, String def, boolean print);
+
+
+ /**
+ * A class for Getting info out of "JavaBean" format
+ *
+ */
+ public static class Bean implements Get {
+ private Object bean;
+ private Class<?> bc;
+ private Class<?>[] params;
+ private Object[] args;
+
+ public Bean(Object bean) {
+ this.bean = bean;
+ bc = bean.getClass();
+ params = new Class<?>[0]; // note, this will allow to go out of scope after config
+ args = new Object[0];
+ }
+
+ public String get(String name, String def, boolean print) {
+ String str = null;
+ String gname = "get"+Character.toUpperCase(name.charAt(0))+name.substring(1);
+ try {
+ Method meth = bc.getMethod(gname, params);
+ Object obj = meth.invoke(bean, args);
+ str = obj==null?null:obj.toString(); // easy string convert...
+ } catch (Exception e) {
+ }
+
+ // Take def if nothing else
+ if(str==null) {
+ str = def;
+ // don't log defaults
+ } else {
+ str = str.trim(); // this is vital in Property File based values, as spaces can hide easily
+ }
+ // Note: Can't log during configuration
+ return str;
+ }
+ }
+
+ public static Get NULL = new Get() {
+ public String get(String name, String def, boolean print) {
+ return def;
+ }
+ };
+
+ public static class AccessGet implements Get {
+ private Access access;
+ public AccessGet(Access access) {
+ this.access = access;
+ }
+ public String get(String name, String def, boolean print) {
+ String gotten = access.getProperty(name, def);
+ if(print) {
+ if(gotten == null) {
+ access.log(Level.INIT,name, "is not set");
+ } else {
+ access.log(Level.INIT,name, "is set to", gotten);
+ }
+ }
+ return gotten;
+ }
+ }
+
+}
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
index 0000000..bdd6afd
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/GetAccess.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import com.att.cadi.PropAccess;
+
+public class GetAccess extends PropAccess {
+ private final Get getter;
+
+ public GetAccess(Get getter) {
+ super(new String[]{"cadi_prop_files="+getter.get("cadi_prop_files", null, true)});
+ this.getter = getter;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.PropAccess#getProperty(java.lang.String, java.lang.String)
+ */
+ @Override
+ public String getProperty(String tag, String def) {
+ String rv;
+ rv = super.getProperty(tag, null);
+ if(rv==null && getter!=null) {
+ rv = getter.get(tag, null, true);
+ }
+ return rv==null?def:rv;
+ }
+ /* (non-Javadoc)
+ * @see com.att.cadi.PropAccess#getProperty(java.lang.String)
+ */
+ @Override
+ public String getProperty(String tag) {
+ String rv;
+ rv = super.getProperty(tag, null);
+ if(rv==null && getter!=null) {
+ rv = getter.get(tag, null, true);
+ }
+ return rv;
+ }
+
+ public Get get() {
+ return getter;
+ }
+}
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
index 0000000..a304319
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/MultiGet.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+public class MultiGet implements Get {
+ private Get[] getters;
+
+ public MultiGet(Get ... getters) {
+ this.getters = getters;
+ }
+
+ @Override
+ public String get(String name, String def, boolean print) {
+ String str;
+ for(Get getter : getters) {
+ str = getter.get(name, null, print);
+ if(str!=null)
+ return str;
+ }
+ return def;
+ }
+
+}
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
index 0000000..a1ef35b
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/SecurityInfo.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.rmi.AccessException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.util.MaskFormatException;
+import com.att.cadi.util.NetMask;
+
+public class SecurityInfo {
+ private static final String SECURITY_ALGO = "RSA";
+ private static final String HTTPS_PROTOCOLS = "https.protocols";
+ private static final String JDK_TLS_CLIENT_PROTOCOLS = "jdk.tls.client.protocols";
+
+ public static final String HTTPS_PROTOCOLS_DEFAULT = "TLSv1.1,TLSv1.2";
+ public static final String REGEX_COMMA = "\\s*,\\s*";
+ public static final String SslKeyManagerFactoryAlgorithm;
+
+ private SSLSocketFactory scf;
+ private X509KeyManager[] km;
+ private X509TrustManager[] tm;
+ public final String default_alias;
+ private NetMask[] trustMasks;
+ private SSLContext ctx;
+ private HostnameVerifier maskHV;
+
+ // Change Key Algorithms for IBM's VM. Could put in others, if needed.
+ static {
+ if(System.getProperty("java.vm.vendor").equalsIgnoreCase("IBM Corporation")) {
+ SslKeyManagerFactoryAlgorithm = "IbmX509";
+ } else {
+ SslKeyManagerFactoryAlgorithm = "SunX509";
+ }
+ }
+
+
+ public SecurityInfo(final Access access) throws GeneralSecurityException, IOException {
+ // reuse DME2 Properties for convenience if specific Properties don't exist
+ String keyStore = access.getProperty(Config.CADI_KEYSTORE,
+ access.getProperty(Config.AFT_DME2_KEYSTORE,null));
+ String keyStorePasswd = access.getProperty(Config.CADI_KEYSTORE_PASSWORD,
+ access.getProperty(Config.AFT_DME2_KEYSTORE_PASSWORD, null));
+ keyStorePasswd = keyStorePasswd==null?null:access.decrypt(keyStorePasswd,false);
+ String trustStore = access.getProperty(Config.CADI_TRUSTSTORE,
+ access.getProperty(Config.AFT_DME2_TRUSTSTORE, null));
+ String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD,
+ access.getProperty(Config.AFT_DME2_TRUSTSTORE_PASSWORD,null));
+ trustStorePasswd = trustStorePasswd==null?null:access.decrypt(trustStorePasswd,false);
+ default_alias = access.getProperty(Config.CADI_ALIAS,
+ access.getProperty(Config.AFT_DME2_CLIENT_SSL_CERT_ALIAS,null));
+
+ String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD,null);
+ keyPasswd = keyPasswd==null?keyStorePasswd:access.decrypt(keyPasswd,false);
+ String tips=access.getProperty(Config.CADI_TRUST_MASKS, null);
+ if(tips!=null) {
+ access.log(Level.INIT,"Explicitly accepting valid X509s from",tips);
+ String[] ipsplit = tips.split(REGEX_COMMA);
+ trustMasks = new NetMask[ipsplit.length];
+ for(int i=0;i<ipsplit.length;++i) {
+ try {
+ trustMasks[i]=new NetMask(ipsplit[i]);
+ } catch (MaskFormatException e) {
+ throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS,e);
+ }
+ }
+ }
+ String https_protocols = Config.logProp(access,Config.CADI_PROTOCOLS,
+ access.getProperty(Config.AFT_DME2_SSL_INCLUDE_PROTOCOLS,
+ access.getProperty(HTTPS_PROTOCOLS,HTTPS_PROTOCOLS_DEFAULT)
+ ));
+ System.setProperty(HTTPS_PROTOCOLS,https_protocols);
+ System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, https_protocols);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);
+ File file;
+
+
+ if(keyStore==null || keyStorePasswd == null) {
+ km = new X509KeyManager[0];
+ } else {
+ ArrayList<X509KeyManager> kmal = new ArrayList<X509KeyManager>();
+ for(String ksname : keyStore.split(REGEX_COMMA)) {
+ file = new File(ksname);
+ String keystoreFormat;
+ if(ksname.endsWith("pkcs12")) {
+ keystoreFormat = "PKCS12";
+ } else {
+ keystoreFormat = "JKS";
+ }
+ if(file.exists()) {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ KeyStore ks = KeyStore.getInstance(keystoreFormat);
+ ks.load(fis, keyStorePasswd.toCharArray());
+ kmf.init(ks, keyPasswd.toCharArray());
+ } finally {
+ fis.close();
+ }
+ }
+ }
+ for(KeyManager km : kmf.getKeyManagers()) {
+ if(km instanceof X509KeyManager) {
+ kmal.add((X509KeyManager)km);
+ }
+ }
+ km = new X509KeyManager[kmal.size()];
+ kmal.toArray(km);
+ }
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);
+ if(trustStore!=null) {
+ for(String tsname : trustStore.split(REGEX_COMMA)) {
+ file = new File(tsname);
+ if(file.exists()) {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ KeyStore ts = KeyStore.getInstance("JKS");
+ ts.load(fis, trustStorePasswd.toCharArray());
+ tmf.init(ts);
+ } finally {
+ fis.close();
+ }
+ }
+ }
+ TrustManager tms[] = tmf.getTrustManagers();
+ tm = new X509TrustManager[tms==null?0:tms.length];
+ for(int i=0;i<tms.length;++i) {
+ try {
+ tm[i]=(X509TrustManager)tms[i];
+ } catch (ClassCastException e) {
+ access.log(Level.WARN, "Non X509 TrustManager", tm[i].getClass().getName(),"skipped in SecurityInfo");
+ }
+ }
+ }
+
+ if(trustMasks!=null) {
+ final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection.setDefaultHostnameVerifier(maskHV = new HostnameVerifier() {
+ @Override
+ public boolean verify(final String urlHostName, final SSLSession session) {
+ try {
+ // This will pick up /etc/host entries as well as DNS
+ InetAddress ia = InetAddress.getByName(session.getPeerHost());
+ for(NetMask tmask : trustMasks) {
+ if(tmask.isInNet(ia.getHostAddress())) {
+ return true;
+ }
+ }
+ } catch (UnknownHostException e) {
+ // It's ok. do normal Verify
+ }
+ return origHV.verify(urlHostName,session);
+ };
+ });
+ }
+ ctx = SSLContext.getInstance("TLS");
+ ctx.init(km, tm, null);
+ SSLContext.setDefault(ctx);
+ scf = ctx.getSocketFactory();
+ }
+
+ /**
+ * @return the scf
+ */
+ public SSLSocketFactory getSSLSocketFactory() {
+ return scf;
+ }
+
+ public SSLContext getSSLContext() {
+ return ctx;
+ }
+
+ /**
+ * @return the km
+ */
+ public X509KeyManager[] getKeyManagers() {
+ return km;
+ }
+
+ public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {
+ for(X509TrustManager xtm : tm) {
+ xtm.checkClientTrusted(certarr, SECURITY_ALGO);
+ }
+ }
+
+ public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {
+ for(X509TrustManager xtm : tm) {
+ xtm.checkServerTrusted(certarr, SECURITY_ALGO);
+ }
+ }
+
+ public void setSocketFactoryOn(HttpsURLConnection hsuc) {
+ hsuc.setSSLSocketFactory(scf);
+ if(maskHV!=null && !maskHV.equals(hsuc.getHostnameVerifier())) {
+ hsuc.setHostnameVerifier(maskHV);
+ }
+ }
+
+}
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
index 0000000..5e2fd54
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/SecurityInfoC.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import com.att.cadi.Access;
+import com.att.cadi.SecuritySetter;
+
+
+public class SecurityInfoC<CLIENT> extends SecurityInfo {
+ public SecuritySetter<CLIENT> defSS;
+
+ public SecurityInfoC(Access access) throws GeneralSecurityException, IOException {
+ super(access);
+ }
+
+ public SecurityInfoC<CLIENT> set(SecuritySetter<CLIENT> defSS) {
+ this.defSS = defSS;
+ return this;
+ }
+
+}
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
index 0000000..7d47b7e
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/config/UsersDump.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.config;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Date;
+import java.util.HashSet;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.lur.LocalLur;
+
+public class UsersDump {
+
+ /**
+ * @param args
+ */
+ public static boolean write(OutputStream os, AbsUserCache<?> lur) {
+ PrintStream ps;
+ if(os instanceof PrintStream) {
+ ps = (PrintStream)os;
+ } else {
+ ps = new PrintStream(os);
+ }
+ try {
+ ps.println("<?xml version='1.0' encoding='utf-8'?>");
+ ps.println("<!--");
+ ps.print( " Code Generated Tomcat Users and Roles from AT&T LUR on ");
+ ps.println(new Date());
+ ps.println( "-->");
+ ps.println("<tomcat-users>");
+
+ // We loop through Users, but want to write Groups first... therefore, save off print
+ StringBuilder sb = new StringBuilder();
+
+ // Obtain all unique role names
+ HashSet<String> groups = new HashSet<String>();
+ for(AbsUserCache<?>.DumpInfo di : lur.dumpInfo()) {
+ sb.append("\n <user username=\"");
+ sb.append(di.user);
+ sb.append("\" roles=\"");
+ boolean first = true;
+ for(String role : di.perms) {
+ groups.add(role);
+ if(first)first = false;
+ else sb.append(',');
+ sb.append(role);
+ }
+ sb.append("\"/>");
+
+ }
+
+ // Print roles
+ for(String group : groups) {
+ ps.print(" <role rolename=\"");
+ ps.print(group);
+ ps.println("\"/>");
+ }
+
+ ps.println(sb);
+
+ ps.println("</tomcat-users>");
+ ps.flush();
+ } catch (Throwable t) {
+ t.printStackTrace(ps);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Note: This method returns a String if there's an error, or null if ok.
+ * This unusual style is necessitated by the fact that any Exceptions thrown are likely to
+ * be unlogged and hidden from view, making debugging almost impossible.
+ *
+ * @param writeto
+ * @param up
+ * @return
+ */
+ public static String updateUsers(String writeto, LocalLur up) {
+ // Dump a Tomcat-user.xml lookalike (anywhere)
+ if(writeto!=null) {
+ // First read content
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if(UsersDump.write(baos, up)) {
+ byte[] postulate = baos.toByteArray();
+ // now get contents of file
+ File file = new File(writeto);
+ boolean writeIt;
+ if(file.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ byte[] orig = new byte[(int)file.length()];
+ try {
+ fis.read(orig);
+ } finally {
+ fis.close();
+ }
+ // Starting at third "<" (<tomcat-users> line)
+ int startA=0, startB=0;
+ for(int i=0;startA<orig.length && i<3;++startA) if(orig[startA]=='<')++i;
+ for(int i=0;startB<orig.length && i<3;++startB) if(postulate[startB]=='<')++i;
+
+ writeIt=orig.length-startA!=postulate.length-startB; // first, check if remaining length is the same
+ while(!writeIt && startA<orig.length && startB<postulate.length) {
+ if(orig[startA++]!=postulate[startB++])writeIt = true;
+ }
+ } catch (Exception e) {
+ writeIt = true;
+ }
+ } else {
+ writeIt = true;
+ }
+
+ if(writeIt) {
+ try {
+ FileOutputStream fos = new FileOutputStream(file);
+ try {
+ fos.write(postulate);
+ } finally {
+ fos.close();
+ }
+ } catch (IOException e) {
+ return e.getMessage();
+ }
+ }
+ }
+ }
+ return null; // no message means ok.
+ }
+
+}
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
index 0000000..8f33105
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/AUTHZ.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.servlet.Servlet;
+
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface AUTHZ {
+ Class<? extends Servlet> value();
+}
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
index 0000000..dab6b47
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/AUTHZServlet.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ *
+ */
+public class AUTHZServlet<S extends Servlet> implements Servlet {
+ private String[] roles;
+ private Servlet delegate;
+
+ protected AUTHZServlet(Class<S> cls) {
+ try {
+ delegate = cls.newInstance();
+ } catch (Exception e) {
+ delegate = null;
+ }
+ RolesAllowed rolesAllowed = cls.getAnnotation(RolesAllowed.class);
+ if(rolesAllowed == null) {
+ roles = null;
+ } else {
+ roles = rolesAllowed.value();
+ }
+ }
+
+ public void init(ServletConfig sc) throws ServletException {
+ if(delegate == null) throw new ServletException("Invalid Servlet Delegate");
+ delegate.init(sc);
+ }
+
+ public ServletConfig getServletConfig() {
+ return delegate.getServletConfig();
+ }
+
+ public String getServletInfo() {
+ return delegate.getServletInfo();
+ }
+
+ public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
+ if(roles==null) {
+ delegate.service(req,resp);
+ } else { // Validate
+ try {
+ HttpServletRequest hreq = (HttpServletRequest)req;
+ boolean proceed = false;
+ for(String role : roles) {
+ if(hreq.isUserInRole(role)) {
+ proceed = true;
+ break;
+ }
+ }
+ if(proceed) {
+ delegate.service(req,resp);
+ } else {
+ //baseRequest.getServletContext().log(hreq.getUserPrincipal().getName()+" Refused " + roles);
+ ((HttpServletResponse)resp).sendError(403); // forbidden
+ }
+ } catch(ClassCastException e) {
+ throw new ServletException("JASPIServlet only supports HTTPServletRequest/HttpServletResponse");
+ }
+ }
+ }
+
+ public void destroy() {
+ delegate.destroy();
+ }
+
+
+}
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
index 0000000..a36b7c7
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/AccessGetter.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import com.att.cadi.Access;
+import com.att.cadi.config.Get;
+
+public class AccessGetter implements Get {
+ private final Access access;
+ public AccessGetter(Access access) {
+ this.access = access;
+ }
+ public String get(String name, String def, boolean print) {
+ return access.getProperty(name, def);
+ }
+
+}
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
index 0000000..c7a9250
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/CadiAccess.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.Get;
+
+public class CadiAccess implements Access {
+ // constants for a couple of very commonly used strings.
+ protected static final String FROM = "from";
+ protected static final String FOR = "for";
+
+ // Properties derived from <pass> sources (could be property files, Valve Configurations, Filter
+ // configs, etc.
+ protected Properties props;
+
+ // Will we write Logs?
+ protected Level willWrite = Level.INFO;
+
+ protected ServletContext context;
+ protected Get getter = Get.NULL; // replace with Derived Class getter
+ private Symm symm;
+
+ public CadiAccess(Map<String, Object> map) {
+ if(map!=null && !map.isEmpty()) {
+ props = new Properties();
+ for(Entry<String, Object> es : map.entrySet()) {
+ Object v = es.getValue();
+ if(v!=null) {
+ props.put(es.getKey(), v.toString());
+ }
+ }
+ Object keyfile = props.get(Config.CADI_KEYFILE);
+ if(keyfile!=null) {
+ try {
+ FileInputStream fis = new FileInputStream(keyfile.toString());
+ symm = Symm.obtain(fis);
+ } catch (Exception e) {
+ }
+ }
+
+ }
+ }
+
+ public Level willWrite() {
+ return willWrite;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Access#willLog(com.att.cadi.Access.Level)
+ */
+ @Override
+ public boolean willLog(Level level) {
+ return willWrite.compareTo(level)<=0;
+ }
+
+ /**
+ * Add the "Level" to the Buildline for Logging types that don't specify, or straight Streams, etc. Then buildline
+ *
+ * Build a line of code onto a StringBuilder based on Objects. Analyze whether
+ * spaces need including.
+ *
+ * @param level
+ * @param sb
+ * @param elements
+ * @return
+ */
+ public final static StringBuilder buildLine(Level level, StringBuilder sb, Object[] elements) {
+ sb.append(level.name());
+ return buildLine(sb,elements);
+ }
+
+ /*
+ * Build a line of code onto a StringBuilder based on Objects. Analyze whether
+ * spaces need including.
+ *
+ * @param sb
+ * @param elements
+ * @return
+ */
+ public final static StringBuilder buildLine(StringBuilder sb, Object[] elements) {
+ sb.append(' ');
+ String str;
+ boolean notFirst = false;
+ for(Object o : elements) {
+ if(o!=null) {
+ str = o.toString();
+
+ if(str.length()>0) {
+ if(notFirst && shouldAddSpace(str,true) && shouldAddSpace(sb,false)) {
+ sb.append(' ');
+ } else {
+ notFirst=true;
+ }
+ sb.append(str);
+ }
+ }
+ }
+ return sb;
+ }
+
+ private static boolean shouldAddSpace(CharSequence c,boolean start) {
+ if(c.length()>0)
+ switch(c.charAt(start?0:c.length()-1)) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\'':
+ case '"':
+ case '|':
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Standard mechanism for logging, given being within a Servlet Context
+ *
+ * Here, we treat
+ *
+ * if context exists, log to it, otherwise log to Std Out (The latter is usually for startup
+ * scenarios)
+ *
+ */
+ public void log(Level level, Object... elements) {
+ if(willWrite.compareTo(level)<=0) {
+ StringBuilder sb = buildLine(level, new StringBuilder(),elements);
+ if(context==null) {
+ System.out.println(sb.toString());
+ } else {
+ context.log(sb.toString());
+ }
+ }
+ }
+
+ /**
+ * Standard mechanism for logging an Exception, given being within a Servlet Context, etc
+ *
+ * if context exists, log to it, otherwise log to Std Out (The latter is usually for startup
+ * scenarios)
+ *
+ */
+ public void log(Exception e, Object... elements) {
+ if(willWrite.compareTo(Level.ERROR)<=0) {
+ StringBuilder sb = buildLine(Level.ERROR, new StringBuilder(),elements);
+
+ if(context==null) {
+ sb.append(e.toString());
+ System.out.println(sb.toString());
+ } else {
+ context.log(sb.toString(),e);
+ }
+ }
+ }
+
+ public void setLogLevel(Level level) {
+ willWrite = level;
+ }
+
+ /**
+ * Pass back the classloader of the Servlet Context, if it exists. Otherwise, get the classloader
+ * of this object.
+ */
+ public ClassLoader classLoader() { // Use the Classloader that Context was created with
+ return (context==null?this:context).getClass().getClassLoader();
+ }
+
+ /**
+ * Get the Property from Context
+ */
+ public String getProperty(String string, String def) {
+ String rv = null;
+
+ if ( props != null )
+ rv = props.getProperty( string, def );
+
+ if(rv==null) {
+ rv = context.getInitParameter(string);
+ }
+ return rv==null?def:rv;
+
+ }
+
+ public void load(InputStream is) throws IOException {
+ if(this.props==null) {
+ this.props = new Properties();
+ }
+ this.props.load(is);
+ symm = Symm.obtain(this);
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ if(symm==null) {
+ String keyfile = getter.get(Config.CADI_KEYFILE, null, true);
+ if(keyfile!=null) {
+ FileInputStream fis = new FileInputStream(keyfile);
+ symm=Symm.obtain(fis);
+ fis.close();
+ }
+ }
+ return (symm!=null && encrypted!=null && (anytext || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object[] elements) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..578cbba
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/CadiFilter.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CadiException;
+import com.att.cadi.CadiWrap;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.ServletContextAccess;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.Get;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+
+/**
+ * CadiFilter
+ *
+ * This class implements Servlet Filter, and ties together CADI implementations
+ *
+ * This class can be used in a standard J2EE Servlet manner. Optimal usage is for POJO operations, where
+ * one can enforce this Filter being first and primary. Depending on the Container, it
+ * may be more effective, in some cases, to utilize features that allow earlier determination of
+ * AUTHN (Authorization). An example would be "Tomcat Valve". These implementations, however, should
+ * be modeled after the "init" and "doFilter" functions, and be kept up to date as this class changes.
+ *
+ *
+ *
+ */
+public class CadiFilter implements Filter {
+ private static CadiHTTPManip httpChecker;
+ private static String[] pathExceptions;
+ private static List<Pair> mapPairs;
+ private Access access;
+ private Object[] additionalTafLurs;
+ private static int count=0;
+
+ public Lur getLur() {
+ return httpChecker.getLur();
+ }
+
+ /**
+ * Construct a viable Filter
+ *
+ * Due to the vagaries of many containers, there is a tendency to create Objects and call "Init" on
+ * them at a later time. Therefore, this object creates with an object that denies all access
+ * until appropriate Init happens, just in case the container lets something slip by in the meantime.
+ *
+ */
+ public CadiFilter() {
+ additionalTafLurs = CadiHTTPManip.noAdditional;
+ }
+
+ /**
+ * This constructor to be used when directly constructing and placing in HTTP Engine
+ *
+ * @param access
+ * @param moreTafLurs
+ * @throws ServletException
+ */
+ public CadiFilter(Access access, Object ... moreTafLurs) throws ServletException {
+ additionalTafLurs = moreTafLurs;
+ init(new AccessGetter(this.access = access));
+ }
+
+
+ /**
+ * Use this to pass in a PreContructed CADI Filter, but with initializing... let Servlet do it
+ * @param init
+ * @param access
+ * @param moreTafLurs
+ * @throws ServletException
+ */
+ public CadiFilter(boolean init, PropAccess access, Object ... moreTafLurs) throws ServletException {
+ this.access = access;
+ if(init) {
+ init(new AccessGetter(access));
+ }
+ additionalTafLurs = moreTafLurs;
+ }
+
+ /**
+ * Init
+ *
+ * Standard Filter "init" call with FilterConfig to obtain properties. POJOs can construct a
+ * FilterConfig with the mechanism of their choice, and standard J2EE Servlet engines utilize this
+ * mechanism already.
+ */
+ //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM Init functions
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // need the Context for Logging, instantiating ClassLoader, etc
+ ServletContextAccess sca=new ServletContextAccess(filterConfig);
+ if(access==null) {
+ access = sca;
+ }
+
+ // Set Protected getter with base Access, for internal class instantiations
+ init(new FCGet(access, sca.context(), filterConfig));
+ }
+
+
+ private void init(Get getter) throws ServletException {
+ // Start with the assumption of "Don't trust anyone".
+ TrustChecker tc = TrustChecker.NOTRUST; // default position
+ try {
+ @SuppressWarnings("unchecked")
+ Class<TrustChecker> ctc = (Class<TrustChecker>) Class.forName("com.att.cadi.aaf.v2_0.AAFTrustChecker");
+ if(ctc!=null) {
+ Constructor<TrustChecker> contc = ctc.getConstructor(Access.class);
+ if(contc!=null) {
+ tc = contc.newInstance(access);
+ }
+ }
+ } catch (Exception e) {
+ access.log(Level.INIT, "AAFTrustChecker cannot be loaded",e.getMessage());
+ }
+
+
+ // Synchronize, because some instantiations call init several times on the same object
+ // In this case, the epiTaf will be changed to a non-NullTaf, and thus not instantiate twice.
+ synchronized(CadiHTTPManip.noAdditional /*will always remain same Object*/) {
+ ++count;
+ if(httpChecker == null) {
+ if(access==null) {
+ access = new PropAccess();
+ }
+ try {
+ httpChecker = new CadiHTTPManip(access,null /*reuseable Con*/,tc, additionalTafLurs);
+ } catch (CadiException e1) {
+ throw new ServletException(e1);
+ }
+ } else if(access==null) {
+ access= httpChecker.getAccess();
+ }
+
+ /*
+ * Setup Authn Path Exceptions
+ */
+ if(pathExceptions==null) {
+ String str = getter.get(Config.CADI_NOAUTHN, null, true);
+ if(str!=null) {
+ pathExceptions = str.split("\\s*:\\s*");
+ }
+ }
+
+ /*
+ * SETUP Permission Converters... those that can take Strings from a Vendor Product, and convert to appropriate AAF Permissions
+ */
+ if(mapPairs==null) {
+ String str = getter.get(Config.AAF_PERM_MAP, null, true);
+ if(str!=null) {
+ String mstr = getter.get(Config.AAF_PERM_MAP, null, true);
+ if(mstr!=null) {
+ String map[] = mstr.split("\\s*:\\s*");
+ if(map.length>0) {
+ MapPermConverter mpc=null;
+ int idx;
+ mapPairs = new ArrayList<Pair>();
+ for(String entry : map) {
+ if((idx=entry.indexOf('='))<0) { // it's a Path, so create a new converter
+ access.log(Level.INIT,"Loading Perm Conversions for:",entry);
+ mapPairs.add(new Pair(entry,mpc=new MapPermConverter()));
+ } else {
+ if(mpc!=null) {
+ mpc.map().put(entry.substring(0,idx),entry.substring(idx+1));
+ } else {
+ access.log(Level.ERROR,"cadi_perm_map is malformed; ",entry, "is skipped");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Remove Getter
+ getter = Get.NULL;
+ }
+
+ /**
+ * Containers call "destroy" when time to cleanup
+ */
+ public void destroy() {
+ // Synchronize, in case multiCadiFilters are used.
+ synchronized(CadiHTTPManip.noAdditional) {
+ if(--count<=0 && httpChecker!=null) {
+ httpChecker.destroy();
+ httpChecker=null;
+ access=null;
+ pathExceptions=null;
+ }
+ }
+ }
+
+ /**
+ * doFilter
+ *
+ * This is the standard J2EE invocation. Analyze the request, modify response as necessary, and
+ * only call the next item in the filterChain if request is suitably Authenticated.
+ */
+ //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM functions
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ try {
+ HttpServletRequest hreq = (HttpServletRequest)request;
+ if(noAuthn(hreq)) {
+ chain.doFilter(request, response);
+ } else {
+ HttpServletResponse hresp = (HttpServletResponse)response;
+ TafResp tresp = httpChecker.validate(hreq, hresp);
+ if(tresp.isAuthenticated()==RESP.IS_AUTHENTICATED) {
+ CadiWrap cw = new CadiWrap(hreq, tresp, httpChecker.getLur(),getConverter(hreq));
+ if(httpChecker.notCadi(cw, hresp)) {
+ chain.doFilter(cw,response);
+ }
+ }
+ }
+ } catch (ClassCastException e) {
+ throw new ServletException("CadiFilter expects Servlet to be an HTTP Servlet",e);
+ }
+ }
+
+
+ /**
+ * If PathExceptions exist, report if these should not have Authn applied.
+ * @param hreq
+ * @return
+ */
+ private boolean noAuthn(HttpServletRequest hreq) {
+ if(pathExceptions!=null) {
+ String pi = hreq.getPathInfo();
+ if(pi==null) return false; // JBoss sometimes leaves null
+ for(String pe : pathExceptions) {
+ if(pi.startsWith(pe))return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get Converter by Path
+ */
+ private PermConverter getConverter(HttpServletRequest hreq) {
+ if(mapPairs!=null) {
+ String pi = hreq.getPathInfo();
+ if(pi!=null) {
+ for(Pair p: mapPairs) {
+ if(pi.startsWith(p.name))return p.pc;
+ }
+ }
+ }
+ return NullPermConverter.singleton();
+ }
+
+ /**
+ * store PermConverters by Path prefix
+ *
+ */
+ private class Pair {
+ public Pair(String key, PermConverter pc) {
+ name = key;
+ this.pc = pc;
+ }
+ public String name;
+ public PermConverter pc;
+ }
+
+}
+
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
index 0000000..821dae9
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/CadiHTTPManip.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CadiException;
+import com.att.cadi.CadiWrap;
+import com.att.cadi.Connector;
+import com.att.cadi.CredVal;
+import com.att.cadi.Lur;
+import com.att.cadi.Taf;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.config.Config;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.util.UserChainManip;
+
+/**
+ * Encapsulate common HTTP Manipulation Behavior. It will appropriately set
+ * HTTPServletResponse for Redirect or Forbidden, as needed.
+ *
+ * Further, this is useful, because it avoids multiple creates of Connections, where some Filters
+ * are created and destroyed regularly.
+ *
+ *
+ *
+ */
+public class CadiHTTPManip {
+ private static final String ACCESS_CADI_CONTROL = ".access|cadi|control";
+ private static final String METH = "OPTIONS";
+ private static final String CADI = "/cadi/";
+ private static final String CADI_CACHE_PRINT = "/cadi/cache/print";
+ private static final String CADI_CACHE_CLEAR = "/cadi/cache/clear";
+ private static final String CADI_LOG_SET = "/cadi/log/set/";
+ private Access access;
+ private HttpTaf taf;
+ private CredVal up;
+ private Lur lur;
+ private String thisPerm,companyPerm,aaf_id;
+
+ public static final Object[] noAdditional = new Object[0]; // CadiFilter can be created each call in some systems
+
+
+ public CadiHTTPManip(Access access, Connector con, TrustChecker tc, Object ... additionalTafLurs) throws CadiException {
+ synchronized(CADI) {
+ this.access = access;
+// Get getter = new AccessGetter(access);
+ Config.setDefaultRealm(access);
+
+ aaf_id = access.getProperty(Config.CADI_ALIAS,access.getProperty(Config.AAF_MECHID, null));
+ if(aaf_id==null) {
+ access.printf(Level.INIT, "%s is not set. %s can be used instead",Config.AAF_MECHID,Config.CADI_ALIAS);
+ } else {
+ access.printf(Level.INIT, "%s is set to %s",Config.AAF_MECHID,aaf_id);
+ }
+ String ns = aaf_id==null?null:UserChainManip.idToNS(aaf_id);
+ if(ns!=null) {
+ thisPerm = ns+ACCESS_CADI_CONTROL;
+ int dot = ns.indexOf('.');
+ if(dot>=0) {
+ int dot2=ns.indexOf('.',dot+1);
+ if(dot2<0) {
+ dot2=dot;
+ }
+ companyPerm = ns.substring(0, dot2)+ACCESS_CADI_CONTROL;
+ } else {
+ companyPerm = "com"+ACCESS_CADI_CONTROL;
+ }
+ } else {
+ thisPerm = companyPerm = "com"+ACCESS_CADI_CONTROL;
+ }
+
+ if(con!=null) { // try to reutilize connector
+ List<Lur> ll = null;
+ for(Object tl : additionalTafLurs) {
+ if(tl instanceof Lur) {
+ if(ll==null) {
+ ll = new ArrayList<Lur>();
+ ll.add(con.newLur());
+ }
+ ll.add((Lur)tl);
+ }
+ }
+ if(ll==null) {
+ lur = con.newLur();
+ } else {
+ lur = new EpiLur((Lur[])ll.toArray());
+ }
+ } else {
+ lur = Config.configLur(access, additionalTafLurs);
+ }
+ tc.setLur(lur);
+ if(lur instanceof EpiLur) {
+ up = ((EpiLur)lur).getUserPassImpl();
+ } else if(lur instanceof CredVal) {
+ up = (CredVal)lur;
+ } else {
+ up = null;
+ }
+ taf = Config.configHttpTaf(access, tc, up, lur, additionalTafLurs);
+ }
+ }
+
+ public TafResp validate(HttpServletRequest hreq, HttpServletResponse hresp) throws IOException {
+ TafResp tresp = taf.validate(Taf.LifeForm.LFN, hreq, hresp);
+ switch(tresp.isAuthenticated()) {
+ case IS_AUTHENTICATED:
+ access.printf(Level.INFO,"Authenticated: %s from %s:%d"
+ , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+ break;
+ case TRY_AUTHENTICATING:
+ switch (tresp.authenticate()) {
+ case IS_AUTHENTICATED:
+ access.printf(Level.INFO,"Authenticated: %s from %s:%d"
+ , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+ break;
+ case HTTP_REDIRECT_INVOKED:
+ access.log(Level.INFO,"Authenticating via redirection: ", tresp.desc());
+ break;
+ case NO_FURTHER_PROCESSING:
+ access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d"
+ , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+ hresp.sendError(403, tresp.desc()); // Forbidden
+ break;
+
+ default:
+ access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"
+ , hreq.getRemoteAddr(), hreq.getRemotePort());
+ hresp.sendError(403, tresp.desc()); // Forbidden
+ }
+ break;
+ case NO_FURTHER_PROCESSING:
+ access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d",
+ tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+ hresp.sendError(403, "Access Denied"); // FORBIDDEN
+ break;
+ default:
+ access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"
+ , hreq.getRemoteAddr(), hreq.getRemotePort());
+ hresp.sendError(403, "Access Denied"); // FORBIDDEN
+ }
+ return tresp;
+ }
+
+ public boolean notCadi(CadiWrap req, HttpServletResponse resp) {
+
+ String pathInfo = req.getPathInfo();
+ if(METH.equalsIgnoreCase(req.getMethod()) && pathInfo!=null && pathInfo.contains(CADI)) {
+ if(req.getUser().equals(aaf_id) || req.isUserInRole(thisPerm) || req.isUserInRole(companyPerm)) {
+ try {
+ if(pathInfo.contains(CADI_CACHE_PRINT)) {
+ resp.getOutputStream().println(lur.toString());
+ resp.setStatus(200);
+ return false;
+ } else if(pathInfo.contains(CADI_CACHE_CLEAR)) {
+ StringBuilder report = new StringBuilder();
+ lur.clear(req.getUserPrincipal(), report);
+ resp.getOutputStream().println(report.toString());
+ resp.setStatus(200);
+ return false;
+ } else if(pathInfo.contains(CADI_LOG_SET)) {
+ Level l;
+ int slash = pathInfo.lastIndexOf('/');
+ String level = pathInfo.substring(slash+1);
+ try {
+ l = Level.valueOf(level);
+ access.printf(Level.AUDIT, "%s has set CADI Log Level to '%s'",req.getUser(),l.name());
+ access.setLogLevel(l);
+ } catch (IllegalArgumentException e) {
+ access.printf(Level.AUDIT, "'%s' is not a valid CADI Log Level",level);
+ }
+ return false;
+ }
+ } catch (IOException e) {
+ access.log(e);
+ }
+ }
+ }
+ return true;
+ }
+
+ public Lur getLur() {
+ return lur;
+ }
+
+ public void destroy() {
+ access.log(Level.INFO,"CadiHttpChecker destroyed.");
+ if(lur!=null) {
+ lur.destroy();
+ lur=null;
+ }
+ }
+
+ public Access getAccess() {
+ return access;
+ }
+
+}
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
index 0000000..97840d4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/FCGet.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.config.Get;
+
+/*
+ * A private method to query the Filter config and if not exists, return the default. This
+ * cleans up the initialization code.
+ */
+class FCGet implements Get {
+ /**
+ *
+ */
+ private final Access access;
+ private FilterConfig filterConfig;
+ private ServletContext context;
+
+ public FCGet(Access access, ServletContext context, FilterConfig filterConfig) {
+ this.access = access;
+ this.context = context;
+ this.filterConfig = filterConfig;
+ }
+
+ public String get(String name, String def, boolean print) {
+ String str = null;
+ // Try Server Context First
+ if(context!=null) {
+ str = context.getInitParameter(name);
+ }
+
+ // Try Filter Context next
+ if(str==null && filterConfig != null) {
+ str = filterConfig.getInitParameter(name);
+ }
+
+ if(str==null) {
+ str = access.getProperty(name, def);
+ }
+ // Take def if nothing else
+ if(str==null) {
+ str = def;
+ // don't log defaults
+ } else {
+ str = str.trim(); // this is vital in Property File based values, as spaces can hide easily
+ if(print) {
+ access.log(Level.INFO,"Setting", name, "to", str);
+ }
+ }
+ return str;
+ }
+}
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
index 0000000..19aeb18
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/MapPermConverter.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapPermConverter implements PermConverter {
+ private HashMap<String,String> map;
+
+ /**
+ * Create with colon separated name value pairs
+ * i.e. teAdmin=com.att.myNS.myPerm|*|*:teUser=...
+ *
+ * @param value
+ */
+ public MapPermConverter() {
+ map = new HashMap<String,String>();
+ }
+
+ /**
+ * use to instantiate entries
+ *
+ * @return
+ */
+ public Map<String,String> map() {
+ return map;
+ }
+
+ public String convert(String minimal) {
+ String rv = map.get(minimal);
+ return rv==null?minimal:rv;
+ }
+
+}
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
index 0000000..07c565d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/NullPermConverter.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+
+/**
+ * A NullPermConverter
+ *
+ * Obey the PermConverter Interface, but passed in "minimal" String is not converted.
+ *
+ *
+ */
+public class NullPermConverter implements PermConverter {
+
+ private NullPermConverter() {}
+ private static final NullPermConverter singleton = new NullPermConverter();
+ public static NullPermConverter singleton() {return singleton;}
+
+ public String convert(String minimal) {
+ return minimal;
+ }
+
+}
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
index 0000000..3ea6536
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/PathFilter.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.config.Config;
+
+/**
+ * PathFilter
+ *
+ * This class implements Servlet Filter, and uses AAF to validate access to a Path.
+ *
+ * This class can be used in a standard J2EE Servlet manner.
+ *
+ *
+ */
+public class PathFilter implements Filter {
+ private ServletContext context;
+ private String aaf_type;
+ private String not_authorized_msg;
+ private final Log log;
+
+ /**
+ * Construct a viable Filter for installing in Container WEB.XML, etc.
+ *
+ */
+ public PathFilter() {
+ log = new Log() {
+ public void info(String ... msg) {
+ context.log(build("INFO:",msg));
+ }
+ public void audit(String ... msg) {
+ context.log(build("AUDIT:",msg));
+ }
+ private String build(String type, String []msg) {
+ StringBuilder sb = new StringBuilder(type);
+ for(String s : msg) {
+ sb.append(' ');
+ sb.append(s);
+ }
+ return sb.toString();
+ }
+
+ };
+ }
+
+ /**
+ * Filter that can be constructed within Java
+ * @param access
+ */
+ public PathFilter(final Access access) {
+ log = new Log() {
+ public void info(String ... msg) {
+ access.log(Level.INFO, (Object[])msg);
+ }
+ public void audit(String ... msg) {
+ access.log(Level.AUDIT, (Object[])msg);
+ }
+ };
+ }
+
+ /**
+ * Init
+ *
+ * Standard Filter "init" call with FilterConfig to obtain properties. POJOs can construct a
+ * FilterConfig with the mechanism of their choice, and standard J2EE Servlet engines utilize this
+ * mechanism already.
+ */
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // need the Context for Logging, instantiating ClassLoader, etc
+ context = filterConfig.getServletContext();
+ StringBuilder sb = new StringBuilder();
+ StringBuilder err = new StringBuilder();
+ Object attr = context.getAttribute(Config.PATHFILTER_NS);
+ if(attr==null) {
+ err.append("PathFilter - pathfilter_ns is not set");
+ } else {
+ sb.append(attr.toString());
+ }
+
+ attr = context.getAttribute(Config.PATHFILTER_STACK);
+ if(attr==null) {
+ log.info("PathFilter - No pathfilter_stack set, ignoring");
+ } else {
+ sb.append('.');
+ sb.append(attr.toString());
+ }
+
+ attr = context.getAttribute(Config.PATHFILTER_URLPATTERN);
+ if(attr==null) {
+ log.info("PathFilter - No pathfilter_urlpattern set, defaulting to 'urlpattern'");
+ sb.append(".urlpattern");
+ } else {
+ sb.append('.');
+ sb.append(attr.toString());
+ }
+
+ log.info("PathFilter - AAF Permission Type is",sb.toString());
+
+ sb.append('|');
+
+ aaf_type = sb.toString();
+
+ attr = context.getAttribute(Config.PATHFILTER_NOT_AUTHORIZED_MSG);
+ if(attr==null) {
+ not_authorized_msg = "Forbidden - Not Authorized to access this Path";
+ } else {
+ not_authorized_msg = attr.toString();
+ }
+
+ if(err.length()>0) {
+ throw new ServletException(err.toString());
+ }
+ }
+
+ private interface Log {
+ public void info(String ... msg);
+ public void audit(String ... msg);
+ }
+
+ /**
+ * doFilter
+ *
+ * This is the standard J2EE invocation. Analyze the request, modify response as necessary, and
+ * only call the next item in the filterChain if request is suitably Authenticated.
+ */
+ //TODO Always validate changes against Tomcat AbsCadiValve and Jaspi CadiSAM functions
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest hreq = (HttpServletRequest)request;
+ HttpServletResponse hresp = (HttpServletResponse)response;
+ String perm = aaf_type+hreq.getPathInfo()+'|'+hreq.getMethod();
+ if(hreq.isUserInRole(perm)) {
+ chain.doFilter(request, response);
+ } else {
+ log.audit("PathFilter has denied",hreq.getUserPrincipal().getName(),"access to",perm);
+ hresp.sendError(403,not_authorized_msg);
+ }
+ }
+
+ /**
+ * Containers call "destroy" when time to cleanup
+ */
+ public void destroy() {
+ log.info("PathFilter destroyed.");
+ }
+
+
+
+}
+
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
index 0000000..e5bfcb7
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/PermConverter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.filter;
+
+/**
+ * Convert a simplistic, single string Permission into an Enterprise Scoped Perm
+ *
+ *
+ */
+public interface PermConverter {
+ public String convert(String minimal);
+}
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
index 0000000..ec350fd
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/RolesAllowed.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+/**
+ * RolesAllowed
+ *
+ *
+ * Similar to Java EE's Spec from Annotations 1.1, 2.8
+ *
+ * That Spec, however, was geared towards being able to route calls to Methods on Objects, and thus needed a more refined
+ * sense of permissions hierarchy. The same mechanism, however, can easily be achieved on single Servlet/Handlers in
+ * POJOs like Jetty by simply adding the Roles Allowed in a similar Annotation
+ *
+ */
+package com.att.cadi.filter;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * JASPI Style Annotation of RolesAllowed when the coding style is desired but actually including all
+ * JEE jars is not. If using actual JASPI, use official @interface classes, not this one...
+ *
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface RolesAllowed {
+ /**
+ * Security role of the implementation, which doesn't have to be an EJB or CORBA like object. Can be just a
+ * Handler
+ * @return
+ */
+ String[] value();
+}
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
index 0000000..3db6d4e
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/filter/ServletImpl.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+/**
+ * RolesAllowed
+ *
+ *
+ * Similar to Java EE's Spec from Annotations 1.1, 2.8
+ *
+ * That Spec, however, was geared towards being able to route calls to Methods on Objects, and thus needed a more refined
+ * sense of permissions hierarchy. The same mechanism, however, can easily be achieved on single Servlet/Handlers in
+ * POJOs like Jetty by simply adding the Roles Allowed in a similar Annotation
+ *
+ */
+package com.att.cadi.filter;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.servlet.Servlet;
+
+/**
+ *
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface ServletImpl {
+ /**
+ * Security role of the implementation, which doesn't have to be an EJB or CORBA like object. Can be just a
+ * Handler
+ * @return
+ */
+ Class<? extends Servlet> value();
+}
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
index 0000000..03a7961
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/lur/ConfigPrincipal.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.GetCred;
+import com.att.cadi.Symm;
+
+public class ConfigPrincipal implements Principal, GetCred {
+ private String name;
+ private byte[] cred;
+ private String content;
+
+ public ConfigPrincipal(String name, String passwd) {
+ this.name = name;
+ this.cred = passwd.getBytes();
+ content = null;
+ }
+
+ public ConfigPrincipal(String name, byte[] cred) {
+ this.name = name;
+ this.cred = cred;
+ content = null;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public byte[] getCred() {
+ return cred;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public String getAsBasicAuthHeader() throws IOException {
+ if(content ==null) {
+ String s = name + ':' + new String(cred);
+ content = "Basic " + Symm.base64.encode(s);
+ } else if(!content.startsWith("Basic ")) { // content is the saved password from construction
+ String s = name + ':' + content;
+ content = "Basic " + Symm.base64.encode(s);
+ }
+ return content;
+ }
+}
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
index 0000000..de6c057
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/lur/EpiLur.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur;
+
+import java.security.Principal;
+import java.util.List;
+
+import com.att.cadi.CachingLur;
+import com.att.cadi.CadiException;
+import com.att.cadi.CredVal;
+import com.att.cadi.Lur;
+import com.att.cadi.Permission;
+
+/**
+ * EpiLUR
+ *
+ * Short for "Epic LUR". Be able to run through a series of LURs to obtain the validation needed.
+ *
+ * The pun is better for the other pattern... "TAF" (aka EpiTaf), but it's still the larger picture of
+ * LURs that will be accomplished.
+ *
+ * FYI, the reason we separate LURs, rather than combine, is that Various User Repository Resources have
+ * different Caching requirements. For instance, the Local User Repo (with stand alone names), never expire, but might be
+ * refreshed with a change in Configuration File, while the Remote Service based LURs will need to expire at prescribed intervals
+ *
+ *
+ */
+public final class EpiLur implements Lur {
+ private final Lur[] lurs;
+
+ /**
+ * EpiLur constructor
+ *
+ * Construct the EpiLur from variable TAF parameters
+ * @param lurs
+ * @throws CadiException
+ */
+ public EpiLur(Lur ... lurs) throws CadiException{
+ this.lurs = lurs;
+ if(lurs.length==0) throw new CadiException("Need at least one Lur implementation in constructor");
+ }
+
+ public boolean fish(Principal bait, Permission pond) {
+ if(pond==null) {
+ return false;
+ }
+ boolean rv = false;
+ Lur lur;
+ for(int i=0;!rv && i<lurs.length;++i) {
+ rv = (lur = lurs[i]).fish(bait, pond);
+ if(!rv && lur.handlesExclusively(pond)) break;
+ }
+ return rv;
+ }
+
+ public void fishAll(Principal bait, List<Permission> permissions) {
+ for(Lur lur : lurs) {
+ lur.fishAll(bait, permissions);
+ }
+ }
+
+ public void destroy() {
+ for(Lur lur : lurs) {
+ lur.destroy();
+ }
+ }
+
+ /**
+ * Return the first Lur (if any) which also implements UserPass
+ * @return
+ */
+ public CredVal getUserPassImpl() {
+ for(Lur lur : lurs) {
+ if(lur instanceof CredVal) {
+ return (CredVal)lur;
+ }
+ }
+ return null;
+ }
+
+ // Never needed... Only EpiLur uses...
+ public boolean handlesExclusively(Permission pond) {
+ return false;
+ }
+
+ /**
+ * Get Lur for index. Returns null if out of range
+ * @param idx
+ * @return
+ */
+ public Lur get(int idx) {
+ if(idx>=0 && idx<lurs.length) {
+ return lurs[idx];
+ }
+ return null;
+ }
+
+ public boolean supports(String userName) {
+ for(Lur l : lurs) {
+ if(l.supports(userName))return true;
+ }
+ return false;
+ }
+
+ public void remove(String id) {
+ for(Lur l : lurs) {
+ if(l instanceof CachingLur) {
+ ((CachingLur<?>)l).remove(id);
+ }
+ }
+ }
+
+ public Lur subLur(Class<? extends Lur> cls ) {
+ for(Lur l : lurs) {
+ if(l.getClass().isAssignableFrom(cls)) {
+ return l;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Permission createPerm(String p) {
+ return new LocalPermission(p);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#clear(java.security.Principal, java.lang.StringBuilder)
+ */
+ @Override
+ public void clear(Principal p, StringBuilder report) {
+ for(Lur lur : lurs) {
+ lur.clear(p, report);
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for(Lur lur : lurs) {
+ sb.append(lur.getClass().getSimpleName());
+ sb.append(": Report\n");
+ sb.append(lur.toString());
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+}
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
index 0000000..80b302a
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/lur/LocalLur.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CredVal;
+import com.att.cadi.Hash;
+import com.att.cadi.Permission;
+import com.att.cadi.StrLur;
+import com.att.cadi.User;
+import com.att.cadi.config.Config;
+
+
+/**
+ * An in-memory Lur that can be configured locally with User info via properties, similar to Tomcat-users.xml mechanisms.
+ *
+ *
+ */
+public final class LocalLur extends AbsUserCache<LocalPermission> implements StrLur, CredVal {
+ public static final String SEMI = "\\s*;\\s*";
+ public static final String COLON = "\\s*:\\s*";
+ public static final String COMMA = "\\s*,\\s*";
+ public static final String PERCENT = "\\s*%\\s*";
+
+ // Use to quickly determine whether any given group is supported by this LUR
+ private final Set<String> supportingGroups;
+ private String supportedRealm;
+
+ /**
+ * Construct by building structure, see "build"
+ *
+ * Reconstruct with "build"
+ *
+ * @param userProperty
+ * @param groupProperty
+ * @param decryptor
+ * @throws IOException
+ */
+ public LocalLur(Access access, String userProperty, String groupProperty) throws IOException {
+ super(access, 0, 0, Integer.MAX_VALUE); // data doesn't expire
+ supportedRealm = access.getProperty(Config.BASIC_REALM, "localized");
+ supportingGroups = new TreeSet<String>();
+
+ if(userProperty!=null) {
+ // For each User name...
+ for(String user : userProperty.trim().split(SEMI)) {
+ String[] us = user.split(COLON,2);
+ String[] userpass = us[0].split(PERCENT,2);
+ String u;
+ User<LocalPermission> usr;
+ if(userpass.length>1) {
+ if(userpass.length>0 && userpass[0].indexOf('@')<0) {
+ userpass[0]=userpass[0] + '@' + access.getProperty(Config.AAF_DEFAULT_REALM,Config.getDefaultRealm());
+ }
+
+ u = userpass[0];
+ byte[] pass = access.decrypt(userpass[1], true).getBytes();
+ usr = new User<LocalPermission>(new ConfigPrincipal(u, pass));
+ } else {
+ u = us[0];
+ usr = new User<LocalPermission>(new ConfigPrincipal(u, (byte[])null));
+ }
+ addUser(usr);
+ access.log(Level.INIT, "Local User:",usr.principal);
+
+ if(us.length>1) {
+ Map<String, Permission> newMap = usr.newMap();
+ for(String group : us[1].split(COMMA)) {
+ supportingGroups.add(group);
+ usr.add(newMap,new LocalPermission(group));
+ }
+ usr.setMap(newMap);
+ }
+ }
+ }
+ if(groupProperty!=null) {
+ // For each Group name...
+ for(String group : groupProperty.trim().split(SEMI)) {
+ String[] gs = group.split(COLON,2);
+ if(gs.length>1) {
+ supportingGroups.add(gs[0]);
+ LocalPermission p = new LocalPermission(gs[0]);
+ // Add all users (known by comma separators)
+
+ for(String grpMem : gs[1].split(COMMA)) {
+ // look for password, if so, put in passMap
+ String[] userpass = grpMem.split(PERCENT,2);
+ if(userpass.length>0 && userpass[0].indexOf('@')<0) {
+ userpass[0]=userpass[0] + '@' + access.getProperty(Config.AAF_DEFAULT_REALM,Config.getDefaultRealm());
+ }
+ User<LocalPermission> usr = getUser(userpass[0]);
+ if(userpass.length>1) {
+ byte[] pass = access.decrypt(userpass[1], true).getBytes();
+ if(usr==null)addUser(usr=new User<LocalPermission>(new ConfigPrincipal(userpass[0],pass)));
+ else usr.principal=new ConfigPrincipal(userpass[0],pass);
+ } else {
+ if(usr==null)addUser(usr=new User<LocalPermission>(new ConfigPrincipal(userpass[0],(byte[])null)));
+ }
+ usr.add(p);
+ access.log(Level.INIT, "Local User:",usr.principal);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean validate(String user, CredVal.Type type, byte[] cred) {
+ User<LocalPermission> usr = getUser(user);
+ switch(type) {
+ case PASSWORD:
+ // covers null as well as bad pass
+ if(usr!=null && cred!=null && usr.principal instanceof ConfigPrincipal) {
+ return Hash.isEqual(cred,((ConfigPrincipal)usr.principal).getCred());
+ }
+ break;
+ }
+ return false;
+ }
+
+ // @Override
+ public boolean fish(Principal bait, Permission pond) {
+ if(supports(bait.getName()) && pond instanceof LocalPermission) { // local Users only have LocalPermissions
+ User<LocalPermission> user = getUser(bait);
+ return user==null?false:user.contains((LocalPermission)pond);
+ }
+ return false;
+ }
+
+ public boolean fish(String bait, Permission pond) {
+ if(supports(bait) && pond instanceof LocalPermission) { // local Users only have LocalPermissions
+ User<LocalPermission> user = getUser(bait);
+ return user==null?false:user.contains((LocalPermission)pond);
+ }
+ return false;
+ }
+
+ // We do not want to expose the actual Group, so make a copy.
+ public void fishAll(Principal bait, List<Permission> perms) {
+ if(supports(bait.getName())) {
+ User<LocalPermission> user = getUser(bait);
+ if(user!=null) {
+ user.copyPermsTo(perms);
+ }
+ }
+ }
+
+ public void fishAll(String bait, List<Permission> perms) {
+ if(supports(bait)) {
+ User<LocalPermission> user = getUser(bait);
+ if(user!=null) {
+ user.copyPermsTo(perms);
+ }
+ }
+ }
+
+ public boolean supports(String userName) {
+ return userName!=null && userName.endsWith(supportedRealm);
+ }
+
+ public boolean handlesExclusively(Permission pond) {
+ return supportingGroups.contains(pond.getKey());
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#createPerm(java.lang.String)
+ */
+ @Override
+ public Permission createPerm(String p) {
+ return new LocalPermission(p);
+ }
+
+}
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
index 0000000..8fdaec2
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/lur/LocalPermission.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur;
+
+import com.att.cadi.Permission;
+
+public class LocalPermission implements Permission {
+ private String key;
+
+ public LocalPermission(String role) {
+ this.key = role;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String toString() {
+ return key;
+ }
+
+ public boolean match(Permission p) {
+ return key.equals(p.getKey());
+ }
+
+ public String permType() {
+ return "LOCAL";
+ }
+
+
+}
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
index 0000000..91fb7bb
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/lur/NullLur.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur;
+
+import java.security.Principal;
+import java.util.List;
+
+import com.att.cadi.Lur;
+import com.att.cadi.Permission;
+
+public class NullLur implements Lur {
+ private static final Permission NULL = new Permission() {
+ @Override
+ public String permType() {
+ return "";
+ }
+
+ @Override
+ public String getKey() {
+ return "";
+ }
+
+ @Override
+ public boolean match(Permission p) {
+ return false;
+ }};
+
+ public boolean fish(Principal bait, Permission pond) {
+ // Well, for Jenkins, this is ok... It finds out it can't do J2EE Security, and then looks at it's own
+// System.err.println("CADI's LUR has not been configured, but is still being called. Access is being denied");
+ return false;
+ }
+
+ public void fishAll(Principal bait, List<Permission> permissions) {
+ }
+
+ public void destroy() {
+ }
+
+ public boolean handlesExclusively(Permission pond) {
+ return false;
+ }
+
+ public boolean supports(String userName) {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#createPerm(java.lang.String)
+ */
+ @Override
+ public Permission createPerm(String p) {
+ return NULL;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#clear(java.security.Principal, java.lang.StringBuilder)
+ */
+ @Override
+ public void clear(Principal p, StringBuilder report) {
+ report.append(NullLur.class.getSimpleName());
+ report.append('\n');
+ }
+
+ public String toString() {
+ return NullLur.class.getSimpleName() + '\n';
+ }
+}
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
index 0000000..58f7d71
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/BasicPrincipal.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import com.att.cadi.BasicCred;
+import com.att.cadi.GetCred;
+import com.att.cadi.Symm;
+
+public class BasicPrincipal extends BearerPrincipal implements GetCred {
+ private static byte[] basic = "Basic ".getBytes();
+
+ private String name = null;
+ private String shortName = null;
+ private byte[] cred = null;
+
+ private long created;
+
+ public BasicPrincipal(String content,String domain) throws IOException {
+ created = System.currentTimeMillis();
+ ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());
+ // Read past "Basic ", ensuring it starts with it.
+ for(int i=0;i<basic.length;++i) {
+ if(bis.read()!=basic[i]) {
+ name=content;
+ cred = null;
+ return;
+ }
+ }
+ BasicOS bos = new BasicOS(content.length());
+ Symm.base64.decode(bis,bos); // note: writes directly to name until ':'
+ if(name==null) throw new IOException("Invalid Coding");
+ else cred = bos.toCred();
+ int at;
+ if((at=name.indexOf('@'))>0) {
+ domain=name.substring(at+1);
+ shortName=name.substring(0, at);
+ } else {
+ shortName = name;
+ name = name + '@' + domain;
+ }
+ }
+
+ public BasicPrincipal(BasicCred bc, String domain) {
+ name = bc.getUser();
+ cred = bc.getCred();
+ }
+
+ private class BasicOS extends OutputStream {
+ private boolean first = true;
+ private ByteArrayOutputStream baos;
+
+ public BasicOS(int size) {
+ baos = new ByteArrayOutputStream(size);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if(b==':' && first) {
+ first = false;
+ name = new String(baos.toByteArray());
+ baos.reset(); //
+ } else {
+ baos.write(b);
+ }
+ }
+
+ private byte[] toCred() {
+ return baos.toByteArray();
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getShortName() {
+ return shortName;
+ }
+
+ public byte[] getCred() {
+ return cred;
+ }
+
+ public long created() {
+ return created;
+ }
+
+ public String toString() {
+ return "Basic Authorization for " + name + " evaluated on " + new Date(created).toString();
+ }
+}
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
index 0000000..11bc22a
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/BearerPrincipal.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.security.Principal;
+
+public abstract class BearerPrincipal implements Principal {
+ private String bearer = null;
+ public BearerPrincipal setBearer(String bearer) {
+ this.bearer = bearer;
+ return this;
+ }
+ public String getBearer() {
+ return bearer;
+ }
+}
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
index 0000000..36c75b8
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/CSPPrincipal_T.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.security.Principal;
+
+/**
+ * Indicate a CSP Principal that is trusted as a CSPPrincipal.
+ *
+ */
+public interface CSPPrincipal_T extends Principal {
+
+}
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
index 0000000..37c6a83
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/CachedBasicPrincipal.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.io.IOException;
+
+import com.att.cadi.BasicCred;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.taf.HttpTaf;
+
+/**
+ * Cached Principals need to be able to revalidate in the Background
+ *
+ *
+ */
+public class CachedBasicPrincipal extends BasicPrincipal implements CachedPrincipal {
+ private final HttpTaf creator;
+ private long timeToLive;
+ private long expires;
+
+ public CachedBasicPrincipal(HttpTaf creator, BasicCred bc, String domain, long timeToLive) {
+ super(bc, domain);
+ this.creator = creator;
+ this.timeToLive = timeToLive;
+ expires = System.currentTimeMillis()+timeToLive;
+ }
+
+ public CachedBasicPrincipal(HttpTaf creator, String content, String domain, long timeToLive) throws IOException {
+ super(content, domain);
+ this.creator = creator;
+ this.timeToLive = timeToLive;
+ expires = System.currentTimeMillis()+timeToLive;
+ }
+
+ public CachedPrincipal.Resp revalidate() {
+ Resp resp = creator.revalidate(this);
+ if(resp.equals(Resp.REVALIDATED))expires = System.currentTimeMillis()+timeToLive;
+ return resp;
+ }
+
+ public long expires() {
+ return expires;
+ }
+
+}
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
index 0000000..aa610d3
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/TGuardPrincipal.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+public class TGuardPrincipal extends BearerPrincipal {
+
+ private String name, tresp;
+
+ public TGuardPrincipal(String tresp) {
+ this.tresp=tresp;
+ }
+
+ /**
+ * TODO Need to figure out what Organizations TGuard entities should be part of.
+ *
+ */
+ public String getName() {
+ if(name==null) {
+ String temp = get("iv-user");
+ if(temp==null)return null;
+ StringBuilder sb = new StringBuilder();
+ int at = temp.indexOf('@');
+ if(at<0) {
+ sb.append(temp);
+ } else {
+ sb.append(temp.substring(0, at));
+ }
+ if(temp.endsWith("@uverse.com"))sb.append("@uverse.tguard.att.com");
+ else if(temp.endsWith("@att.com"))sb.append("@com.tguard.att.com");
+ else if(temp.endsWith("@att.net"))sb.append("@net.tguard.att.com");
+ else sb.append("@tguard.att.com");
+ name = sb.toString();
+ }
+ return name;
+ }
+
+ /**
+ * Get a value from a named TGuard Property
+ *
+ * TGuard response info is very dynamic. They can add new properties at any time, so we dare not code field names for these values.
+ * @param key
+ * @return
+ */
+ public String get(String key) {
+ if(key==null)return null;
+ int idx=0,equal=0,amp=0;
+ while(idx>=0 && (equal = tresp.indexOf('=',idx))>=0) {
+ amp = tresp.indexOf('&',equal);
+ if(key.regionMatches(0, tresp, idx, equal-idx)) {
+ return amp>=0?tresp.substring(equal+1, amp):tresp.substring(equal+1);
+ }
+ idx=amp+(amp>0?1:0);
+ }
+ return null;
+ }
+
+ public String info() {
+ return tresp;
+ }
+}
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
index 0000000..97907ac
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/TGuardPrincipal_T.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.security.Principal;
+
+/**
+ * Indicate a TGuard Principal that is trusted as a TGuardPrincipal.
+ *
+ */
+public interface TGuardPrincipal_T extends Principal {
+
+}
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
index 0000000..67b76c6
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/TrustPrincipal.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.security.Principal;
+
+import com.att.cadi.UserChain;
+
+public class TrustPrincipal extends BearerPrincipal implements UserChain {
+ private final String name;
+ private final Principal original;
+ private String userChain;
+
+ public TrustPrincipal(final Principal actual, final String asName) {
+ this.original = actual;
+ name = asName.trim();
+ if(actual instanceof UserChain) {
+ UserChain uc = (UserChain)actual;
+ userChain = uc.userChain();
+ } else if(actual instanceof X509Principal) {
+ userChain="x509";
+ } else if(actual instanceof BasicPrincipal) {
+ userChain="BAth";
+ } else {
+ userChain = actual.getClass().getSimpleName();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public String getOrigName() {
+ return original.getName() + '[' + userChain + ']';
+ }
+
+ @Override
+ public String userChain() {
+ return userChain;
+ }
+
+ public Principal original() {
+ return original;
+ }
+
+}
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
index 0000000..8e17033
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/principal/X509Principal.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.principal;
+
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.regex.Pattern;
+
+import com.att.cadi.GetCred;
+
+public class X509Principal extends BearerPrincipal implements GetCred {
+ private static final Pattern pattern = Pattern.compile("[a-zA-Z0-9]*\\@[a-zA-Z0-9.]*");
+ private byte[] content;
+ private X509Certificate cert;
+ private String name;
+
+ public X509Principal(String identity, X509Certificate cert, byte[] content) {
+ name = identity;
+ this.content = content;
+ this.cert = cert;
+ }
+
+ public X509Principal(X509Certificate cert, byte[] content) throws IOException {
+ this.content=content;
+ this.cert = cert;
+ String subj = cert.getSubjectDN().getName();
+ int cn = subj.indexOf("OU=");
+ if(cn>=0) {
+ cn+=3;
+ int space = subj.indexOf(',',cn);
+ if(space>=0) {
+ String id = subj.substring(cn, space);
+ if(pattern.matcher(id).matches()) {
+ name = id;
+ }
+ }
+ }
+ if(name==null)
+ throw new IOException("X509 does not have Identity as CN");
+
+ }
+
+
+ public String getAsHeader() throws IOException {
+ try {
+ if(content==null)
+ content=cert.getEncoded();
+ } catch (CertificateEncodingException e) {
+ throw new IOException(e);
+ }
+ return "X509 " + content;
+ }
+
+ public String toString() {
+ return "X509 Authentication for " + name;
+ }
+
+
+ public byte[] getCred() {
+ try {
+ return content==null?(content=cert.getEncoded()):content;
+ } catch (CertificateEncodingException e) {
+ return null;
+ }
+ }
+
+
+ public String getName() {
+ return name;
+ }
+}
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
index 0000000..94d2e5d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/AbsTafResp.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.security.Principal;
+
+import com.att.cadi.Access;
+
+/**
+ * AbsTafResp
+ *
+ * Base class for TafResp (TAF Response Objects)
+ *
+ */
+public abstract class AbsTafResp implements TafResp {
+
+ protected final String desc;
+ protected final Principal principal;
+ protected final Access access;
+
+ /**
+ * AbsTafResp
+ *
+ * Set and hold
+ * Description (for logging)
+ * Principal (as created by derived class)
+ * Access (for access to underlying container, i.e. for Logging, auditing, ClassLoaders, etc)
+ *
+ * @param access
+ * @param principal
+ * @param description
+ */
+ public AbsTafResp(Access access, Principal principal, String description) {
+ this.access = access;
+ this.principal = principal;
+ this.desc = description;
+ }
+
+ /**
+ * isValid()
+ *
+ * Respond in the affirmative if the TAF was able to Authenticate
+ */
+ public boolean isValid() {
+ return principal!=null;
+ }
+
+ /**
+ * desc()
+ *
+ * Respond with description of response as given by the TAF
+ */
+ public String desc() {
+ return desc;
+ }
+
+ /**
+ * isAuthenticated()
+ *
+ * Respond with the TAF's code of whether Authenticated, or suggested next steps
+ * default is either IS_AUTHENTICATED, or TRY_ANOTHER_TAF. The TAF can overload
+ * and suggest others, such as "NO_FURTHER_PROCESSING", if it can detect that this
+ * is some sort of security breach (i.e. Denial of Service)
+ */
+ public RESP isAuthenticated() {
+ return principal==null?RESP.TRY_ANOTHER_TAF:RESP.IS_AUTHENTICATED;
+ }
+
+ /**
+ * getPrincipal()
+ *
+ * Return the principal created by the TAF based on Authentication.
+ *
+ * Returns "null" if Authentication failed (no principal)
+ */
+ public Principal getPrincipal() {
+ return principal;
+ }
+
+ /**
+ * getAccess()
+ *
+ * Get the Access object from the TAF, so that appropriate Logging, etc can be coordinated.
+ */
+ public Access getAccess() {
+ return access;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.taf.TafResp#isFailedAttempt()
+ */
+ public boolean isFailedAttempt() {
+ return false;
+ }
+
+}
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
index 0000000..d3f5493
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/EpiTaf.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Taf;
+
+/**
+ * EpiTAF
+ *
+ * Short for "Epic TAF". Be able to run through a series of TAFs to obtain the validation needed.
+ *
+ * OK, the name could probably be better as "Tafs", like it was originally, but the pun was too
+ * irresistible for this author to pass up.
+ *
+ *
+ */
+public class EpiTaf implements Taf {
+ private Taf[] tafs;
+
+ /**
+ * EpiTaf constructor
+ *
+ * Construct the EpiTaf from variable TAF parameters
+ * @param tafs
+ * @throws CadiException
+ */
+ public EpiTaf(Taf ... tafs) throws CadiException{
+ this.tafs = tafs;
+ if(tafs.length==0) throw new CadiException("Need at least one Taf implementation in constructor");
+ }
+
+ /**
+ * validate
+ *
+ * Respond with the first TAF to authenticate user based on variable info and "LifeForm" (is it
+ * a human behind an interface, or a server behind a protocol).
+ *
+ * If there is no TAF that can authenticate, respond with the first TAF that suggests it can
+ * establish an Authentication conversation (TRY_AUTHENTICATING).
+ *
+ * If no TAF declares either, respond with NullTafResp (which denies all questions)
+ */
+ public TafResp validate(LifeForm reading, String... info) {
+ TafResp tresp,firstTryAuth=null;
+ for(Taf taf : tafs) {
+ tresp = taf.validate(reading, info);
+ switch(tresp.isAuthenticated()) {
+ case TRY_ANOTHER_TAF:
+ break;
+ case TRY_AUTHENTICATING:
+ if(firstTryAuth==null)firstTryAuth=tresp;
+ break;
+ default:
+ return tresp;
+ }
+ }
+
+ // No TAFs configured, at this point. It is safer at this point to be "not validated",
+ // rather than "let it go"
+ return firstTryAuth == null?NullTafResp.singleton():firstTryAuth;
+ }
+
+}
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
index 0000000..7f6d9af
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/HttpEpiTaf.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.net.URI;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.TrustChecker;
+
+/**
+ * HttpEpiTaf
+ *
+ * An extension of the basic "EpiTAF" concept, check known HTTP Related TAFs for valid credentials
+ *
+ *
+ */
+public class HttpEpiTaf implements HttpTaf {
+ private HttpTaf[] tafs;
+ private Access access;
+ private Locator<URI> locator;
+ private TrustChecker trustChecker;
+
+ /**
+ * HttpEpiTaf constructor
+ *
+ * Construct the HttpEpiTaf from variable Http specific TAF parameters
+
+ * @param tafs
+ * @throws CadiException
+ */
+ public HttpEpiTaf(Access access, Locator<URI> locator, TrustChecker tc, HttpTaf ... tafs) throws CadiException{
+ this.tafs = tafs;
+ this.access = access;
+ this.locator = locator;
+ this.trustChecker = tc;
+ // Establish what Header Property to look for UserChain/Trust Props
+// trustChainProp = access.getProperty(Config.CADI_TRUST_PROP, Config.CADI_TRUST_PROP_DEFAULT);
+
+ if(tafs.length==0) throw new CadiException("Need at least one HttpTaf implementation in constructor");
+ }
+
+ /**
+ * validate
+ *
+ * Respond with the first Http specific TAF to authenticate user based on variable info
+ * and "LifeForm" (is it a human behind a browser, or a server utilizing HTTP Protocol).
+ *
+ * If there is no HttpTAF that can authenticate, respond with the first TAF that suggests it can
+ * establish an Authentication conversation (TRY_AUTHENTICATING) (Examples include a redirect to CSP
+ * Servers for CSP Cookie, or BasicAuth 401 response, suggesting User/Password for given Realm
+ * submission
+ *
+ * If no TAF declares either, respond with NullTafResp (which denies all questions)
+ */
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ // Given a LifeForm Neutral, for HTTP, we need to discover true Life-Form Readings
+ if(reading==LifeForm.LFN) {
+ reading = tricorderScan(req);
+ }
+ TafResp tresp=null, firstTry = null;
+ List<Redirectable> redirectables = null;
+
+ for(HttpTaf taf : tafs) {
+ tresp = taf.validate(reading, req, resp);
+ switch(tresp.isAuthenticated()) {
+ case TRY_ANOTHER_TAF:
+ break; // and loop
+ case TRY_AUTHENTICATING:
+ if(tresp instanceof Redirectable) {
+ if(redirectables==null) {
+ redirectables = new ArrayList<Redirectable>();
+ }
+ redirectables.add((Redirectable)tresp);
+ } else if(firstTry==null) {
+ firstTry = tresp;
+ }
+ break;
+ case IS_AUTHENTICATED:
+ tresp = trustChecker.mayTrust(tresp, req);
+ return tresp;
+ default:
+ return tresp;
+ }
+ }
+
+ // If No TAFs configured, at this point. It is safer at this point to be "not validated",
+ // rather than "let it go"
+ // Note: if exists, there will always be more than 0 entries, according to above code
+ if(redirectables==null) {
+ return firstTry!=null?firstTry:NullTafResp.singleton();
+ }
+
+ // If there is one Tryable entry then return it
+ if(redirectables.size()>1) {
+ return LoginPageTafResp.create(access,locator,resp,redirectables);
+ } else {
+ return redirectables.get(0);
+ }
+ }
+
+ public boolean revalidate(Principal prin) throws Exception {
+ return false;
+ }
+
+ /*
+ * 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
+ * of "LifeForm" reading we can determine, i.e. is there a Human (CarbonBasedLifeForm) behind a browser, or is it mechanical
+ * id (SiliconBasedLifeForm)? This makes a difference in some Authentication, i.e CSP, which doesn't work well for SBLFs
+ */
+ private LifeForm tricorderScan(HttpServletRequest req) {
+ // For simplicity's sake, we'll say Humans use FQDNs, not IPs.
+
+ String auth = req.getParameter("Authentication");
+ if(auth!=null) {
+ if("BasicAuth".equals(auth)) {
+ return LifeForm.SBLF;
+ }
+ }
+ // Current guess that only Browsers bother to set "Agent" codes that identify the kind of browser they are.
+ // If mechanical frameworks are found that populate this, then more advanced analysis may be required
+ // 1/22/2013
+ String agent = req.getHeader("User-Agent");
+ if(agent!=null && agent.startsWith("Mozilla")) // covers I.E./Firefox/Safari/probably any other "advanced" Browser see http://en.wikipedia.org/wiki/User_agent
+ return LifeForm.CBLF;
+ return LifeForm.SBLF; // notably skips "curl","wget", (which is desired behavior. We don't want to try CSP, etc on these)
+ }
+
+ public Resp revalidate(CachedPrincipal prin) {
+ Resp resp;
+ for(HttpTaf taf : tafs) {
+ resp = taf.revalidate(prin);
+ switch(resp) {
+ case NOT_MINE:
+ break;
+ default:
+ return resp;
+ }
+ }
+ return Resp.NOT_MINE;
+ }
+
+ /**
+ * List HttpTafs with their "toString" representations... primarily useful for Debugging in an IDE
+ * like Eclipse.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for(HttpTaf ht : tafs) {
+ sb.append(ht.toString());
+ sb.append(". ");
+ }
+ return sb.toString();
+ }
+}
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
index 0000000..4270a81
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/HttpTaf.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.Taf.LifeForm;
+
+/**
+ * A TAF which is in a specific HTTP environment in which the engine implements
+ * javax Servlet.
+ *
+ * Using the Http Request and Response interfaces takes the effort out of implementing in almost any kind of
+ * HTTP Container or Engine.
+ *
+ *
+ */
+public interface HttpTaf {
+ /**
+ * validate
+ *
+ * Validate the Request, and respond with created TafResp object.
+ *
+ * @param reading
+ * @param req
+ * @param resp
+ * @return
+ */
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp);
+
+ /**
+ * Re-Validate Credential
+ *
+ * @param prin
+ * @return
+ */
+ public CachedPrincipal.Resp revalidate(CachedPrincipal prin);
+}
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
index 0000000..d9da3fa
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/LoginPageTafResp.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+
+public class LoginPageTafResp extends AbsTafResp {
+ private final HttpServletResponse httpResp;
+ private final String loginPageURL;
+
+ private LoginPageTafResp(Access access, final HttpServletResponse resp, String loginPageURL) {
+ super(access, null, "Multiple Possible HTTP Logins available. Redirecting to Login Choice Page");
+ httpResp = resp;
+ this.loginPageURL = loginPageURL;
+ }
+
+ @Override
+ public RESP authenticate() throws IOException {
+ httpResp.sendRedirect(loginPageURL);
+ return RESP.HTTP_REDIRECT_INVOKED;
+ }
+
+ @Override
+ public RESP isAuthenticated() {
+ return RESP.TRY_AUTHENTICATING;
+ }
+
+ public static TafResp create(Access access, Locator<URI> locator, final HttpServletResponse resp, List<Redirectable> redir) {
+ if(locator!=null) {
+ try {
+ Item item = locator.best();
+ URI uri = locator.get(item);
+ if(uri!=null) {
+ StringBuilder sb = new StringBuilder(uri.toString());
+ String query = uri.getQuery();
+ boolean first = query==null || query.length()==0;
+ int count=0;
+ for(Redirectable t : redir) {
+ if(first) {
+ sb.append('?');
+ first=false;
+ }
+ else sb.append('&');
+ sb.append(t.get());
+ ++count;
+ }
+ if(count>0)return new LoginPageTafResp(access, resp, sb.toString());
+ }
+ } catch (Exception e) {
+ access.log(e, "Error deriving Login Page location");
+ }
+ } else if(!redir.isEmpty()) {
+ access.log(Level.DEBUG,"LoginPage Locator is not configured. Taking first Redirectable Taf");
+ return redir.get(0);
+ }
+ return NullTafResp.singleton();
+ }
+}
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
index 0000000..ec4a15b
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/NullTaf.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.Taf;
+
+
+/**
+ * This TAF is set at the very beginning of Filters and Valves so that if any configuration issues hit while
+ * starting, the default behavior is to shut down traffic rather than leaving an open hole
+ *
+ *
+ */
+public class NullTaf implements Taf, HttpTaf {
+ // Singleton Pattern
+ public NullTaf() {}
+
+ /**
+ * validate
+ *
+ * Always Respond with a NullTafResp, which declares it is unauthenticated, and unauthorized
+ */
+ public TafResp validate(LifeForm reading, String... info) {
+ return NullTafResp.singleton();
+ }
+
+ /**
+ * validate
+ *
+ * Always Respond with a NullTafResp, which declares it is unauthenticated, and unauthorized
+ */
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ return NullTafResp.singleton();
+ }
+
+ public Resp revalidate(CachedPrincipal prin) {
+ return Resp.NOT_MINE;
+ }
+}
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
index 0000000..c95b195
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/NullTafResp.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+
+/**
+ * A Null Pattern for setting responses to "Deny" before configuration is setup.
+ *
+ */
+class NullTafResp implements TafResp {
+ private NullTafResp(){}
+
+ private static TafResp singleton = new NullTafResp();
+
+ public static TafResp singleton() {
+ return singleton;
+ }
+
+ public boolean isValid() {
+ return false;
+ }
+
+ public RESP isAuthenticated() {
+ return RESP.NO_FURTHER_PROCESSING;
+ }
+
+ public String desc() {
+ return "All Authentication denied";
+ }
+
+ public RESP authenticate() throws IOException {
+ return RESP.NO_FURTHER_PROCESSING;
+ }
+
+ public Principal getPrincipal() {
+ return null;
+ }
+
+ public Access getAccess() {
+ return Access.NULL;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.taf.TafResp#isFailedAttempt()
+ */
+ public boolean isFailedAttempt() {
+ return true;
+ }
+}
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
index 0000000..d9f9b67
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/PuntTafResp.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+
+/**
+ * A Punt Resp to make it fast and easy for a Taf to respond that it cannot handle a particular kind of
+ * request. It is always the same object, so there is no cost for memory, etc.
+ *
+ */
+public class PuntTafResp implements TafResp {
+ private PuntTafResp(){}
+
+ private static TafResp singleton = new PuntTafResp();
+
+ public static TafResp singleton() {
+ return singleton;
+ }
+
+ public boolean isValid() {
+ return false;
+ }
+
+ public RESP isAuthenticated() {
+ return RESP.TRY_ANOTHER_TAF;
+ }
+
+ public String desc() {
+ return "This Taf can or will not handle this authentication";
+ }
+
+ public RESP authenticate() throws IOException {
+ return RESP.TRY_ANOTHER_TAF;
+ }
+
+ public Principal getPrincipal() {
+ return null;
+ }
+
+ public Access getAccess() {
+ return NullTafResp.singleton().getAccess();
+ }
+
+ public boolean isFailedAttempt() {
+ return false;
+ }
+}
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
index 0000000..e83e7ce
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/Redirectable.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+public interface Redirectable extends TafResp {
+ /**
+ * Create a Redirectable URL entry prefaced by a URLEncoder.String for a Menu
+ * example:
+ * "Global Login=https://xxxx....."
+ */
+ public String get();
+}
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
index 0000000..3a1a6f4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/TafResp.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+
+/**
+ * Response from Taf objects, which inform users what has happened and/or what should be done
+ *
+ *
+ */
+public interface TafResp {
+ public static enum RESP {
+ IS_AUTHENTICATED,
+ NO_FURTHER_PROCESSING,
+ TRY_AUTHENTICATING,
+ TRY_ANOTHER_TAF,
+ FAIL,
+ // A note was made to avoid the response REDIRECT. However, I have deemed that it is
+ // unavoidable when the underlying TAF did do a REDIRECT, because it requires a HTTP
+ // Service code to exit without modifying the Response any further.
+ // Therefore, I have changed this to indicate what HAS happened, with should accommodate
+ // both positions. JG 10/18/2012
+// public static final int HTTP_REDIRECT_INVOKED = 11;
+ HTTP_REDIRECT_INVOKED,
+ HAS_PROCESSED};
+
+ /**
+ * Basic success check
+ * @return
+ */
+ public boolean isValid();
+
+ /**
+ * String description of what has occurred (for logging/exceptions)
+ * @return
+ */
+ public String desc();
+
+ /**
+ * Check Response
+ * @return
+ */
+ public RESP isAuthenticated();
+
+ /**
+ * Authenticate, returning FAIL or Other Valid indication
+ *
+ * HTTP implementations should watch for "HTTP_REDIRECT_INVOKED", and end the HTTP call appropriately.
+ * @return
+ * @throws CadiException
+ */
+ public RESP authenticate() throws IOException;
+
+ /**
+ * Once authenticated, this object should hold a Principal created from the authorization
+ * @return
+ */
+ public Principal getPrincipal();
+
+ /**
+ * get the Access object which created this object, allowing the responder to appropriate Log, etc
+ */
+ public Access getAccess();
+
+ /**
+ * Be able to check if part of a Failed attempt
+ */
+ public boolean isFailedAttempt();
+}
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
index 0000000..127450c
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/TrustNotTafResp.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+
+public class TrustNotTafResp implements TafResp {
+ private final TafResp delegate;
+ private final String desc;
+
+ public TrustNotTafResp(final TafResp delegate, final String desc) {
+ this.delegate = delegate;
+ this.desc = desc;
+ }
+
+ @Override
+ public boolean isValid() {
+ return false;
+ }
+
+ @Override
+ public String desc() {
+ return desc;
+ }
+
+ @Override
+ public RESP isAuthenticated() {
+ return RESP.NO_FURTHER_PROCESSING;
+ }
+
+ @Override
+ public RESP authenticate() throws IOException {
+ return RESP.NO_FURTHER_PROCESSING;
+ }
+
+ @Override
+ public Principal getPrincipal() {
+ return delegate.getPrincipal();
+ }
+
+ @Override
+ public Access getAccess() {
+ return delegate.getAccess();
+ }
+
+ @Override
+ public boolean isFailedAttempt() {
+ return true;
+ }
+
+ public String toString() {
+ return desc();
+ }
+}
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
index 0000000..27c6034
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/TrustTafResp.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+
+public class TrustTafResp implements TafResp {
+ private final TafResp delegate;
+ private final Principal principal;
+ private final String desc;
+
+ public TrustTafResp(final TafResp delegate, final Principal principal, final String desc) {
+ this.delegate = delegate;
+ this.principal = principal;
+ this.desc = desc + ' ' + delegate.desc();
+ }
+
+ @Override
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ @Override
+ public String desc() {
+ return desc;
+ }
+
+ @Override
+ public RESP isAuthenticated() {
+ return delegate.isAuthenticated();
+ }
+
+ @Override
+ public RESP authenticate() throws IOException {
+ return delegate.authenticate();
+ }
+
+ @Override
+ public Principal getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public Access getAccess() {
+ return delegate.getAccess();
+ }
+
+ @Override
+ public boolean isFailedAttempt() {
+ return delegate.isFailedAttempt();
+ }
+
+ public String toString() {
+ return principal.getName() + " by trust of " + desc();
+ }
+}
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
index 0000000..672c463
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTaf.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.basic;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.BasicCred;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CredVal;
+import com.att.cadi.CredVal.Type;
+import com.att.cadi.Taf;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CachedBasicPrincipal;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+import com.att.cadi.taf.dos.DenialOfServiceTaf;
+
+/**
+ * BasicHttpTaf
+ *
+ * This TAF implements the "Basic Auth" protocol.
+ *
+ * WARNING! It is true for any implementation of "Basic Auth" that the password is passed unencrypted.
+ * This is because the expectation, when designed years ago, was that it would only be used in
+ * conjunction with SSL (https). It is common, however, for users to ignore this on the assumption that
+ * their internal network is secure, or just ignorance. Therefore, a WARNING will be printed
+ * when the HTTP Channel is not encrypted (unless explicitly turned off).
+ *
+ *
+ */
+public class BasicHttpTaf implements HttpTaf {
+ private Access access;
+ private String realm;
+ private CredVal rbac;
+ private boolean warn;
+ private long timeToLive;
+
+ public BasicHttpTaf(Access access, CredVal rbac, String realm, long timeToLive, boolean turnOnWarning) {
+ this.access = access;
+ this.realm = realm;
+ this.rbac = rbac;
+ this.warn = turnOnWarning;
+ this.timeToLive = timeToLive;
+ }
+
+ /**
+ * Note: BasicHttp works for either Carbon Based (Humans) or Silicon Based (machine) Lifeforms.
+ * @see Taf
+ */
+ public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ // See if Request implements BasicCred (aka CadiWrap or other), and if User/Pass has already been set separately
+ if(req instanceof BasicCred) {
+ BasicCred bc = (BasicCred)req;
+ if(bc.getUser()!=null) { // CadiWrap, if set, makes sure User & Password are both valid, or both null
+ if(DenialOfServiceTaf.isDeniedID(bc.getUser())!=null) {
+ return DenialOfServiceTaf.respDenyID(access,bc.getUser());
+ }
+ CachedBasicPrincipal bp = new CachedBasicPrincipal(this,bc,realm,timeToLive);
+ // ONLY FOR Last Ditch DEBUGGING...
+ // access.log(Level.WARN,bp.getName() + ":" + new String(bp.getCred()));
+ if(rbac.validate(bp.getName(),Type.PASSWORD,bp.getCred())) {
+ return new BasicHttpTafResp(access,bp,bp.getName()+" authenticated by password",RESP.IS_AUTHENTICATED,resp,realm,false);
+ } else {
+ //TODO may need timed retries in a given time period
+ return new BasicHttpTafResp(access,null,buildMsg(bp,req,"User/Pass combo invalid for ",bc.getUser()),
+ RESP.TRY_AUTHENTICATING,resp,realm,true);
+ }
+ }
+ }
+ // Get User/Password from Authorization Header value
+ String authz = req.getHeader("Authorization");
+ if(authz != null && authz.startsWith("Basic ")) {
+ if(warn&&!req.isSecure()) {
+ access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
+ }
+ try {
+ CachedBasicPrincipal ba = new CachedBasicPrincipal(this,authz,realm,timeToLive);
+ if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
+ return DenialOfServiceTaf.respDenyID(access,ba.getName());
+ }
+
+ // ONLY FOR Last Ditch DEBUGGING...
+ // access.log(Level.WARN,ba.getName() + ":" + new String(ba.getCred()));
+ if(rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())) {
+ return new BasicHttpTafResp(access,ba, ba.getName()+" authenticated by BasicAuth password",RESP.IS_AUTHENTICATED,resp,realm,false);
+ } else {
+ //TODO may need timed retries in a given time period
+ return new BasicHttpTafResp(access,null,buildMsg(ba,req,"User/Pass combo invalid"),
+ RESP.TRY_AUTHENTICATING,resp,realm,true);
+ }
+ } catch (IOException e) {
+ String msg = buildMsg(null,req,"Failed HTTP Basic Authorization (", e.getMessage(), ')');
+ access.log(Level.INFO,msg);
+ return new BasicHttpTafResp(access,null,msg, RESP.TRY_AUTHENTICATING, resp, realm,true);
+ }
+ }
+ return new BasicHttpTafResp(access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,realm,false);
+ }
+
+ protected String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
+ StringBuilder sb = new StringBuilder();
+ for(Object s : msg) {
+ sb.append(s.toString());
+ }
+ if(pr!=null) {
+ sb.append(" for ");
+ sb.append(pr.getName());
+ }
+ sb.append(" from ");
+ sb.append(req.getRemoteAddr());
+ sb.append(':');
+ sb.append(req.getRemotePort());
+ return sb.toString();
+ }
+
+ @Override
+ public Resp revalidate(CachedPrincipal prin) {
+ if(prin instanceof BasicPrincipal) {
+ BasicPrincipal ba = (BasicPrincipal)prin;
+ if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
+ return Resp.UNVALIDATED;
+ }
+ return rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())?Resp.REVALIDATED:Resp.UNVALIDATED;
+ }
+ return Resp.NOT_MINE;
+ }
+
+ public String toString() {
+ return "Basic Auth enabled on realm: " + realm;
+ }
+}
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
index 0000000..c768587
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/basic/BasicHttpTafResp.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.basic;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.taf.AbsTafResp;
+import com.att.cadi.taf.TafResp;
+
+public class BasicHttpTafResp extends AbsTafResp implements TafResp {
+ private HttpServletResponse httpResp;
+ private String realm;
+ private RESP status;
+ private final boolean wasFailed;
+
+ public BasicHttpTafResp(Access access, Principal principal, String description, RESP status, HttpServletResponse resp, String realm, boolean wasFailed) {
+ super(access,principal, description);
+ httpResp = resp;
+ this.realm = realm;
+ this.status = status;
+ this.wasFailed = wasFailed;
+ }
+
+ public RESP authenticate() throws IOException {
+ httpResp.setStatus(401); // Unauthorized
+ httpResp.setHeader("WWW-Authenticate", "Basic realm=\""+realm+'"');
+ return RESP.HTTP_REDIRECT_INVOKED;
+ }
+
+ public RESP isAuthenticated() {
+ return status;
+ }
+
+ public boolean isFailedAttempt() {
+ return wasFailed;
+ }
+
+
+}
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
index 0000000..6e46481
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/cert/CertIdentity.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.cert;
+
+import java.security.Principal;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface CertIdentity {
+ /**
+ * identity from X509Certificate Object and/or certBytes
+ *
+ * If you have both, include them. If you only have one, leave the other null, and it will be generated if needed
+ *
+ * The Request is there to obtain Header or Attribute info of ultimate user
+ *
+ * @param req
+ * @param cert
+ * @param certBytes
+ * @return
+ * @throws CertificateException
+ */
+ public Principal identity(HttpServletRequest req, X509Certificate cert, byte[] certBytes) throws CertificateException;
+}
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
index 0000000..3435d52
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/cert/X509HttpTafResp.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.cert;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.cadi.Access;
+import com.att.cadi.taf.AbsTafResp;
+import com.att.cadi.taf.TafResp;
+
+public class X509HttpTafResp extends AbsTafResp implements TafResp {
+ private RESP status;
+
+ public X509HttpTafResp(Access access, Principal principal, String description, RESP status) {
+ super(access, principal, description);
+ this.status = status;
+ }
+
+ public RESP authenticate() throws IOException {
+ return RESP.TRY_ANOTHER_TAF;
+ }
+
+ public RESP isAuthenticated() {
+ return status;
+ }
+
+ public String toString() {
+ return status.name();
+ }
+
+}
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
index 0000000..cb93046
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/cert/X509Taf.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+
+import javax.net.ssl.TrustManagerFactory;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Lur;
+import com.att.cadi.Symm;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.config.SecurityInfo;
+import com.att.cadi.lur.LocalPermission;
+import com.att.cadi.principal.TGuardPrincipal;
+import com.att.cadi.principal.X509Principal;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+import com.att.cadi.util.Split;
+
+public class X509Taf implements HttpTaf {
+
+ public static final CertificateFactory certFactory;
+ public static final MessageDigest messageDigest;
+ public static final TrustManagerFactory tmf;
+ private Access access;
+ private CertIdentity[] certIdents;
+ private Lur lur;
+ private ArrayList<String> cadiIssuers;
+ private String env;
+ private SecurityInfo si;
+
+ static {
+ try {
+ certFactory = CertificateFactory.getInstance("X.509");
+ messageDigest = MessageDigest.getInstance("SHA-256"); // use this to clone
+ tmf = TrustManagerFactory.getInstance(SecurityInfoC.SslKeyManagerFactoryAlgorithm);
+ } catch (Exception e) {
+ throw new RuntimeException("X.509 and SHA-256 are required for X509Taf",e);
+ }
+ }
+
+ public X509Taf(Access access, Lur lur, CertIdentity ... cis) throws CertificateException, NoSuchAlgorithmException, CadiException {
+ this.access = access;
+ env = access.getProperty(Config.AAF_ENV,null);
+ if(env==null) {
+ throw new CadiException("X509Taf requires Environment ("+Config.AAF_ENV+") to be set.");
+ }
+ this.lur = lur;
+ this.cadiIssuers = new ArrayList<String>();
+ 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(":")) {
+ cadiIssuers.add(ci);
+ }
+ try {
+ Class<?> dci = access.classLoader().loadClass("com.att.authz.cadi.DirectCertIdentity");
+ CertIdentity temp[] = new CertIdentity[cis.length+1];
+ System.arraycopy(cis, 0, temp, 1, cis.length);
+ temp[0] = (CertIdentity) dci.newInstance();
+ certIdents=temp;
+ } catch (Exception e) {
+ certIdents = cis;
+ }
+
+ try {
+ si = new SecurityInfo(access);
+ } catch (GeneralSecurityException | IOException e1) {
+ throw new CadiException(e1);
+ }
+ }
+
+ public static final X509Certificate getCert(byte[] certBytes) throws CertificateException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);
+ return (X509Certificate)certFactory.generateCertificate(bais);
+ }
+
+ public static final byte[] getFingerPrint(byte[] ba) {
+ MessageDigest md;
+ try {
+ md = (MessageDigest)messageDigest.clone();
+ } catch (CloneNotSupportedException e) {
+ // should never get here
+ return new byte[0];
+ }
+ md.update(ba);
+ return md.digest();
+ }
+
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ // Check for Mutual SSL
+ try {
+ X509Certificate[] certarr = (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");
+ if(certarr!=null && certarr.length>0) {
+ si.checkClientTrusted(certarr);
+ // Note: If the Issuer is not in the TrustStore, it's not added to the Cert list
+ if(cadiIssuers.contains(certarr[0].getIssuerDN().toString())) {
+ String x500 = certarr[0].getSubjectDN().getName();
+ int ou=x500.indexOf("OU=");
+ if(ou>0) {
+ ou+=3;
+ int comma = x500.indexOf(',',ou);
+ if(comma>0) {
+ String id= x500.substring(ou,comma);
+ String idenv[] = id.split(":");
+ if(idenv.length==1 || (idenv.length>1 && env.equals(idenv[1]))) {
+ return new X509HttpTafResp(access,
+ new X509Principal(idenv[0], certarr[0],null),
+ id + " validated by CADI x509", RESP.IS_AUTHENTICATED);
+ }
+ }
+ }
+ }
+ }
+
+ byte[] array = null;
+ byte[] certBytes = null;
+ X509Certificate cert=null;
+ String responseText=null;
+ String authHeader = req.getHeader("Authorization");
+
+ if(certarr!=null) { // If cert !=null, Cert is Tested by Mutual Protocol.
+ if(authHeader!=null) { // This is only intended to be a Secure Connection, not an Identity
+ return new X509HttpTafResp(access, null, "Certificate verified, but another Identity is presented", RESP.TRY_ANOTHER_TAF);
+ }
+ cert = certarr[0];
+ responseText = ", validated by Mutual SSL Protocol";
+ } else { // If cert == null, Get Declared Cert (in header), but validate by having them sign something
+ if(authHeader != null && authHeader.startsWith("x509 ")) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(authHeader.length());
+ try {
+ array = authHeader.getBytes();
+ ByteArrayInputStream bais = new ByteArrayInputStream(array);
+ Symm.base64noSplit.decode(bais, baos, 5);
+ certBytes = baos.toByteArray();
+ cert = getCert(certBytes);
+
+ /**
+ * Identity from CERT if well know CA and specific encoded information
+ */
+ // If found Identity doesn't work, try SignedStuff Protocol
+// cert.checkValidity();
+// cert.--- GET FINGERPRINT?
+ String stuff = req.getHeader("Signature");
+ if(stuff==null)
+ return new X509HttpTafResp(access, null, "Header entry 'Signature' required to validate One way X509 Certificate", RESP.TRY_ANOTHER_TAF);
+ String data = req.getHeader("Data");
+// if(data==null)
+// return new X509HttpTafResp(access, null, "No signed Data to validate with X509 Certificate", RESP.TRY_ANOTHER_TAF);
+
+ // Note: Data Pos shows is "<signatureType> <data>"
+// int dataPos = (stuff.indexOf(' ')); // determine what is Algorithm
+ // Get Signature
+ bais = new ByteArrayInputStream(stuff.getBytes());
+ baos = new ByteArrayOutputStream(stuff.length());
+ Symm.base64noSplit.decode(bais, baos);
+ array = baos.toByteArray();
+// Signature sig = Signature.getInstance(stuff.substring(0, dataPos)); // get Algorithm from first part of Signature
+
+ Signature sig = Signature.getInstance(cert.getSigAlgName());
+ sig.initVerify(cert.getPublicKey());
+ sig.update(data.getBytes());
+ if(!sig.verify(array)) {
+ access.log(Level.ERROR, "Signature doesn't Match");
+ return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);
+ }
+ responseText = ", validated by Signed Data";
+ } catch (Exception e) {
+ access.log(e, "Exception while validating Cert");
+ return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);
+ }
+
+ } else {
+ return new X509HttpTafResp(access, null, "No Certificate Info on Transaction", RESP.TRY_ANOTHER_TAF);
+ }
+ }
+
+ // A cert has been found, match Identify
+ Principal prin=null;
+
+ for(int i=0;prin==null && i<certIdents.length;++i) {
+ if((prin=certIdents[i].identity(req, cert, certBytes))!=null) {
+ responseText = prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText;
+// xresp = new X509HttpTafResp(
+// access,
+// prin,
+// prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText,
+// RESP.IS_AUTHENTICATED);
+
+ }
+ }
+
+ // if Principal is found, check for "AS_USER" and whether this entity is trusted to declare
+ if(prin!=null) {
+ String as_user=req.getHeader(Config.CADI_USER_CHAIN);
+ if(as_user!=null) {
+ if(as_user.startsWith("TGUARD ") && lur.fish(prin, new LocalPermission("com.att.aaf.trust|"+prin.getName()+"|tguard"))) {
+ prin = new TGuardPrincipal(as_user.substring(7));
+ responseText=prin.getName() + " set via trust of " + responseText;
+ }
+ }
+ return new X509HttpTafResp(
+ access,
+ prin,
+ responseText,
+ RESP.IS_AUTHENTICATED);
+ }
+ } catch(Exception e) {
+ return new X509HttpTafResp(access, null, e.getMessage(), RESP.TRY_ANOTHER_TAF);
+ }
+
+ return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);
+ }
+
+ public Resp revalidate(CachedPrincipal prin) {
+ return null;
+ }
+
+}
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
index 0000000..88a6721
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTaf.java
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.dos;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.PuntTafResp;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+
+public class DenialOfServiceTaf implements HttpTaf {
+ private static Map<String, Counter> deniedIP=null, deniedID=null;
+ private Access access;
+ private static File dosIP, dosID;
+
+ /**
+ *
+ * @param hostname
+ * @param prod
+ * @throws CadiException
+ */
+ public DenialOfServiceTaf(Access access) throws CadiException {
+ this.access = access;
+ if(dosIP==null || dosID == null) {
+ String dirStr;
+ if((dirStr = access.getProperty("aaf_data_dir", null))!=null) {
+ dosIP = new File(dirStr+"/dosIP");
+ readIP();
+ dosID = new File(dirStr+"/dosID");
+ readID();
+ }
+ }
+ }
+
+ public TafResp validate(LifeForm reading, HttpServletRequest req, final HttpServletResponse resp) {
+ // Performance, when not needed
+ if(deniedIP != null) {
+ String ip;
+ Counter c = deniedIP.get(ip=req.getRemoteAddr());
+ if(c!=null) {
+ c.inc();
+ return respDenyIP(access,ip);
+ }
+ }
+
+ // Note: Can't process Principal, because this is the first TAF, and no Principal is created.
+ // Other TAFs use "isDenied()" on this Object to validate.
+ return PuntTafResp.singleton();
+ }
+
+ public Resp revalidate(CachedPrincipal prin) {
+ // We always return NOT MINE, because DOS Taf does not ever validate
+ return Resp.NOT_MINE;
+ }
+
+ /*
+ * for use in Other TAFs, before they attempt backend validation of
+ */
+ public static Counter isDeniedID(String identity) {
+ if(deniedID!=null) {
+ return deniedID.get(identity);
+ }
+ return null;
+ }
+
+ /**
+ *
+ */
+ public static Counter isDeniedIP(String ipvX) {
+ if(deniedID!=null) {
+ return deniedID.get(ipvX);
+ }
+ return null;
+ }
+
+ /**
+ * Return of "True" means IP has been added.
+ * Return of "False" means IP already added.
+ *
+ * @param ip
+ * @return
+ */
+ public static synchronized boolean denyIP(String ip) {
+ boolean rv = false;
+ if(deniedIP==null) {
+ deniedIP = new HashMap<String,Counter>();
+ deniedIP.put(ip, new Counter(ip)); // Noted duplicated for minimum time spent
+ rv= true;
+ } else if(deniedIP.get(ip)==null) {
+ deniedIP.put(ip, new Counter(ip));
+ rv = true;
+ }
+ if(rv) {
+ writeIP();
+ }
+ return rv;
+ }
+
+ private static void writeIP() {
+ if(dosIP!=null && deniedIP!=null) {
+ if(deniedIP.isEmpty()) {
+ if(dosIP.exists()) {
+ dosIP.delete();
+ }
+ } else {
+ PrintStream fos;
+ try {
+ fos = new PrintStream(new FileOutputStream(dosIP,false));
+ try {
+ for(String ip: deniedIP.keySet()) {
+ fos.println(ip);
+ }
+ } finally {
+ fos.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+ private static void readIP() {
+ if(dosIP!=null && dosIP.exists()) {
+ BufferedReader br;
+ try {
+ br = new BufferedReader(new FileReader(dosIP));
+ if(deniedIP==null) {
+ deniedIP=new HashMap<String,Counter>();
+ }
+
+ try {
+ String line;
+ while((line=br.readLine())!=null) {
+ deniedIP.put(line, new Counter(line));
+ }
+ } finally {
+ br.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+
+ /**
+ * Return of "True" means IP has was removed.
+ * Return of "False" means IP wasn't being denied.
+ *
+ * @param ip
+ * @return
+ */
+ public static synchronized boolean removeDenyIP(String ip) {
+ if(deniedIP!=null && deniedIP.remove(ip)!=null) {
+ writeIP();
+ if(deniedIP.isEmpty()) {
+ deniedIP=null;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return of "True" means ID has been added.
+ * Return of "False" means ID already added.
+ *
+ * @param ip
+ * @return
+ */
+ public static synchronized boolean denyID(String id) {
+ boolean rv = false;
+ if(deniedID==null) {
+ deniedID = new HashMap<String,Counter>();
+ deniedID.put(id, new Counter(id)); // Noted duplicated for minimum time spent
+ rv = true;
+ } else if(deniedID.get(id)==null) {
+ deniedID.put(id, new Counter(id));
+ rv = true;
+ }
+ if(rv) {
+ writeID();
+ }
+ return rv;
+
+ }
+
+ private static void writeID() {
+ if(dosID!=null && deniedID!=null) {
+ if(deniedID.isEmpty()) {
+ if(dosID.exists()) {
+ dosID.delete();
+ }
+ } else {
+ PrintStream fos;
+ try {
+ fos = new PrintStream(new FileOutputStream(dosID,false));
+ try {
+ for(String ip: deniedID.keySet()) {
+ fos.println(ip);
+ }
+ } finally {
+ fos.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+ private static void readID() {
+ if(dosID!=null && dosID.exists()) {
+ BufferedReader br;
+ try {
+ br = new BufferedReader(new FileReader(dosID));
+ if(deniedID==null) {
+ deniedID=new HashMap<String,Counter>();
+ }
+ try {
+ String line;
+ while((line=br.readLine())!=null) {
+ deniedID.put(line, new Counter(line));
+ }
+ } finally {
+ br.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+ /**
+ * Return of "True" means ID has was removed.
+ * Return of "False" means ID wasn't being denied.
+ *
+ * @param ip
+ * @return
+ */
+ public static synchronized boolean removeDenyID(String id) {
+ if(deniedID!=null && deniedID.remove(id)!=null) {
+ writeID();
+ if(deniedID.isEmpty()) {
+ deniedID=null;
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ public List<String> report() {
+ int initSize = 0;
+ if(deniedIP!=null)initSize+=deniedIP.size();
+ if(deniedID!=null)initSize+=deniedID.size();
+ ArrayList<String> al = new ArrayList<String>(initSize);
+ if(deniedID!=null) {
+ for(Counter c : deniedID.values()) {
+ al.add(c.toString());
+ }
+ }
+ if(deniedIP!=null) {
+ for(Counter c : deniedIP.values()) {
+ al.add(c.toString());
+ }
+ }
+ return al;
+ }
+
+ public static class Counter {
+ private final String name;
+ private int count = 0;
+ private Date first;
+ private long last; // note, we use "last" as long, to avoid popping useless dates on Heap.
+
+ public Counter(String name) {
+ this.name = name;
+ first = null;
+ last = 0L;
+ count = 0;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public long getLast() {
+ return last;
+ }
+
+ /*
+ * Only allow Denial of ServiceTaf to increment
+ */
+ private synchronized void inc() {
+ ++count;
+ last = System.currentTimeMillis();
+ if(first==null) {
+ first = new Date(last);
+ }
+ }
+
+ public String toString() {
+ if(count==0)
+ return name + " is on the denied list, but has not attempted Access";
+ else
+ return
+ name +
+ " has been denied " +
+ count +
+ " times since " +
+ first +
+ ". Last denial was " +
+ new Date(last);
+ }
+ }
+
+ public static TafResp respDenyID(Access access, String identity) {
+ return new DenialOfServiceTafResp(access, RESP.NO_FURTHER_PROCESSING, identity + " is on the Identity Denial list");
+ }
+
+ public static TafResp respDenyIP(Access access, String ip) {
+ return new DenialOfServiceTafResp(access, RESP.NO_FURTHER_PROCESSING, ip + " is on the IP Denial list");
+ }
+
+}
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
index 0000000..7cbbf73
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/dos/DenialOfServiceTafResp.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.dos;
+
+import java.io.IOException;
+
+import com.att.cadi.Access;
+import com.att.cadi.taf.AbsTafResp;
+
+public class DenialOfServiceTafResp extends AbsTafResp {
+ private RESP ect; // Homage to Arethra Franklin
+
+ public DenialOfServiceTafResp(Access access, RESP resp, String description ) {
+ super(access, null, description);
+ ect = resp;
+ }
+
+ // Override base behavior of checking Principal and trying another TAF
+ @Override
+ public RESP isAuthenticated() {
+ return ect;
+ }
+
+
+ public RESP authenticate() throws IOException {
+ return ect;
+ }
+}
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
index 0000000..89500a6
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTaf.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.localhost;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.Taf;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+
+/**
+ * Implement the ability to utilize LocalHost as a TAF.
+ *
+ * Configure with two properties,
+ * localhost.deny
+ * localhost.accept
+ *
+ * 1) If localhost.deny==true, then no localhost requests are allowed
+ * 2) If localhost.deny==false, but accept==false, return "Try Another TAF" (i.e. allow further checking of the
+ * chain, but don't treat localhost as an acceptable credential)
+ * 3) If localhost.deny=false and accept=true, then the processes coming from the same machine, given logins are needed,
+ * to run, are treated as validated. This is primarily for Developer purposes.
+ *
+ *
+ *
+ */
+public class LocalhostTaf implements HttpTaf {
+ private TafResp isLocalHost,isNotLocalHost;
+ private static final TreeSet<String> addrSet;
+
+ static {
+ addrSet = new TreeSet<String>();
+ try {
+ for(Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();en.hasMoreElements();) {
+ NetworkInterface ni = en.nextElement();
+ for(Enumeration<InetAddress> eia = ni.getInetAddresses();eia.hasMoreElements();) {
+ InetAddress ia = eia.nextElement();
+ addrSet.add(ia.getHostAddress());
+ }
+ }
+ } catch (SocketException e) {
+ }
+
+ }
+
+ public LocalhostTaf(Access access, boolean accept, boolean isDenied) {
+ String hostname = access.getProperty("hostname",null);
+ if(hostname !=null) {
+ try {
+ addrSet.add(InetAddress.getByName(hostname).getHostAddress());
+ } catch (UnknownHostException e) {
+ access.log(e,"Unknown Host");
+ }
+ }
+
+ if(isDenied) {
+ access.log(Level.INFO,"LocalhostTaf will deny all localhost traffic");
+ } else {
+ access.log(Level.INFO,"LocalhostTaf will not deny localhost requests, ",
+ (accept?"and will treat them as authenticated":"but will require other authentication"));
+ }
+ // Set the appropriate behavior for when ID coming in is from localhost
+ isLocalHost = isDenied?
+ new LocalhostTafResp(access, RESP.NO_FURTHER_PROCESSING,"Localhost is denied"):
+ accept?
+ new LocalhostTafResp(access, RESP.IS_AUTHENTICATED,"Localhost is allowed"):
+ new LocalhostTafResp(access, RESP.TRY_ANOTHER_TAF,"Localhost is allowed");
+ isNotLocalHost = new LocalhostTafResp(access, RESP.TRY_ANOTHER_TAF,"Address is not Localhost");
+ }
+
+// @Override
+ public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ String remote = req.getRemoteAddr();
+ return addrSet.contains(remote)
+ ?isLocalHost
+ :isNotLocalHost;
+ }
+
+ /**
+ * This function used for other TAFs (i.e. CSP, which can't work on localhost address)
+ *
+ * @param address
+ * @return
+ */
+ public static boolean isLocalAddress(String address) {
+ return addrSet.contains(address);
+ }
+
+ public String toString() {
+ return "Localhost TAF activated: " + isLocalHost.desc();
+ }
+
+ public Resp revalidate(CachedPrincipal prin) {
+ // shouldn't get here, since there's no need to Cache, but if so, LocalHost is always valid...
+ return Resp.REVALIDATED;
+ }
+}
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
index 0000000..29ddf92
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/taf/localhost/LocalhostTafResp.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.taf.localhost;
+
+import java.security.Principal;
+
+import com.att.cadi.Access;
+import com.att.cadi.taf.TafResp;
+
+public class LocalhostTafResp implements TafResp {
+ private RESP action;
+ private String description;
+ private final static Principal principal = new Principal() {
+ private String name = System.getProperty("user.name")+"@localhost";
+// @Override
+ public String getName() {
+ return name;
+ }
+ };
+
+ private Access access;
+
+ public LocalhostTafResp(Access access, RESP state, String desc) {
+ action = state;
+ description = desc;
+ this.access = access;
+ }
+
+// @Override
+ public boolean isValid() {
+ return action == RESP.IS_AUTHENTICATED;
+ }
+
+// @Override
+ public String desc() {
+ return description;
+ }
+
+// @Override
+ public RESP authenticate() {
+ return action;
+ }
+
+ public RESP isAuthenticated() {
+ return action;
+ }
+
+// @Override
+ public Principal getPrincipal() {
+ return principal;
+ }
+
+ public Access getAccess() {
+ return access;
+ }
+
+ public boolean isFailedAttempt() {
+ return false;
+ }
+
+}
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
index 0000000..9991616
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/Chmod.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface Chmod {
+ public void chmod(File f) throws IOException;
+
+ public static final Chmod to755 = new Chmod() {
+ public void chmod(File f) throws IOException {
+ f.setExecutable(true, false);
+ f.setExecutable(true, true);
+ f.setReadable(true, false);
+ f.setReadable(true, true);
+ f.setWritable(false, false);
+ f.setWritable(true, true);
+ }
+ };
+
+ public static final Chmod to644 = new Chmod() {
+ public void chmod(File f) throws IOException {
+ f.setExecutable(false, false);
+ f.setExecutable(false, true);
+ f.setReadable(true, false);
+ f.setReadable(true, true);
+ f.setWritable(false, false);
+ f.setWritable(true, true);
+ }
+ };
+
+ public static final Chmod to400 = new Chmod() {
+ public void chmod(File f) throws IOException {
+ f.setExecutable(false, false);
+ f.setExecutable(false, true);
+ f.setReadable(false, false);
+ f.setReadable(true, true);
+ f.setWritable(false, false);
+ f.setWritable(false, true);
+ }
+ };
+}
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
index 0000000..f85efa4
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/JsonOutputStream.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class JsonOutputStream extends OutputStream {
+ private static final byte[] TWO_SPACE = " ".getBytes();
+ private OutputStream os;
+ private boolean closeable;
+ private int indent = 0;
+ private int prev,ret=0;
+
+ public JsonOutputStream(OutputStream os) {
+ // Don't close these, or dire consequences.
+ closeable = !os.equals(System.out) && !os.equals(System.err);
+ this.os = os;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if(ret=='\n') {
+ ret = 0;
+ if(prev!=',' || (b!='{' && b!='[')) {
+ os.write('\n');
+ for(int i=0;i<indent;++i) {
+ os.write(TWO_SPACE);
+ }
+ }
+ }
+ switch(b) {
+ case '{':
+ case '[':
+ ret = '\n';
+ ++indent;
+ break;
+ case '}':
+ case ']':
+ --indent;
+ os.write('\n');
+ for(int i=0;i<indent;++i) {
+ os.write(TWO_SPACE);
+ }
+ break;
+ case ',':
+ ret = '\n';
+ break;
+
+ }
+ os.write(b);
+ prev = b;
+ }
+ public void resetIndent() {
+ indent = 1;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ os.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if(closeable) {
+ os.close();
+ }
+ }
+
+}
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
index 0000000..7a8c773
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/MaskFormatException.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+@SuppressWarnings("serial")
+public class MaskFormatException extends Exception {
+
+ public MaskFormatException(String string) {
+ super(string);
+ }
+
+}
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
index 0000000..eb148ee
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/MyConsole.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+public interface MyConsole {
+ public String readLine(String fmt, Object ... args);
+ public char[] readPassword(String fmt, Object ... args);
+ public void printf(String fmt, Object ...args);
+}
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
index 0000000..befed88
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/NetMask.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+/*
+ * NetMask - a class to quickly validate whether a given IP is part of a mask, as defined by bytes or standard String format.
+ *
+ * Needs the IPV6 Mask Builder.
+ */
+public class NetMask {
+ private long mask;
+
+ public NetMask(byte[] inBytes) {
+ mask = derive(inBytes);
+ }
+
+ public NetMask(String string) throws MaskFormatException {
+ mask = derive(string,true);
+ }
+
+ public boolean isInNet(byte[] inBytes) {
+ long addr = derive(inBytes);
+ return (mask & addr) == addr;
+ }
+
+ public boolean isInNet(String str) {
+ long addr;
+ try {
+ addr = derive(str,false);
+ return (mask & addr) == addr;
+ } catch (MaskFormatException e) {
+ // will not hit this code;
+ return false;
+ }
+ }
+
+ public static long derive(byte[] inBytes) {
+ long addr = 0L;
+ int offset = inBytes.length*8;
+ for(int i=0;i<inBytes.length;++i) {
+ addr&=(inBytes[i]<<offset);
+ offset-=8;
+ }
+ return addr;
+ }
+
+ public static long derive(String str, boolean check) throws MaskFormatException {
+ long rv=0L;
+ int idx=str.indexOf(':');
+ int slash = str.indexOf('/');
+
+ if(idx<0) { // Not IPV6, so it's IPV4... Is there a mask of 123/254?
+ idx=str.indexOf('.');
+ int offset = 24;
+ int end = slash>=0?slash:str.length();
+ int bits = slash>=0?Integer.parseInt(str.substring(slash+1)):32;
+ if(check && bits>32) {
+ throw new MaskFormatException("Invalid Mask Offset in IPV4 Address");
+ }
+ int prev = 0;
+ long lbyte;
+ while(prev<end) {
+ if(idx<0) {
+ idx = end;
+ }
+ lbyte = Long.parseLong(str.substring(prev, idx));
+ if(check && (lbyte>255 || lbyte<0)) {
+ throw new MaskFormatException("Invalid Byte in IPV4 Address");
+ }
+ rv|=lbyte<<offset;
+ prev = ++idx;
+ idx=str.indexOf('.',prev);
+ offset-=8;
+ }
+ rv|=0x00000000FFFFFFFFL>>bits;
+ }
+ return rv;
+ }
+
+}
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
index 0000000..4a695fb
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/Split.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+/**
+ * Split by Char, optional Trim
+ *
+ * Note: Copied from Inno to avoid linking issues.
+ * Note: I read the String split and Pattern split code, and we can do this more efficiently for a single Character
+ *
+ * 8/20/2015
+ */
+
+public class Split {
+ public static String[] split(char c, String value) {
+ // Count items to preallocate Array (memory alloc is more expensive than counting twice)
+ int count,idx;
+ for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);
+ String[] rv = new String[count];
+ if(count==1) {
+ rv[0]=value;
+ } else {
+ int last=0;
+ count=-1;
+ for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx);
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last);
+ }
+ return rv;
+ }
+
+ public static String[] splitTrim(char c, String value) {
+ // Count items to preallocate Array (memory alloc is more expensive than counting twice)
+ int count,idx;
+ for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);
+ String[] rv = new String[count];
+ if(count==1) {
+ rv[0]=value.trim();
+ } else {
+ int last=0;
+ count=-1;
+ for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx).trim();
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last).trim();
+ }
+ return rv;
+ }
+
+ public static String[] splitTrim(char c, String value, int size) {
+ int idx;
+ String[] rv = new String[size];
+ if(size==1) {
+ rv[0]=value.trim();
+ } else {
+ int last=0;
+ int count=-1;
+ size-=2;
+ for(idx=value.indexOf(c);idx>=0 && count<size;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx).trim();
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last).trim();
+ }
+ return rv;
+ }
+
+}
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
index 0000000..3d57332
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/SubStandardConsole.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+// Substandard, because System.in doesn't do Passwords..
+public class SubStandardConsole implements MyConsole {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ @Override
+ public String readLine(String fmt, Object... args) {
+ String rv;
+ try {
+ System.out.printf(fmt,args);
+ rv = br.readLine();
+ if(args.length==1 && rv.length()==0) {
+ rv = args[0].toString();
+ }
+ } catch (IOException e) {
+ System.err.println("uh oh...");
+ rv = "";
+ }
+ return rv;
+ }
+
+ @Override
+ public char[] readPassword(String fmt, Object... args) {
+ try {
+ System.out.printf(fmt,args);
+ return br.readLine().toCharArray();
+ } catch (IOException e) {
+ System.err.println("uh oh...");
+ return new char[0];
+ }
+ }
+
+ @Override
+ public void printf(String fmt, Object... args) {
+ System.out.printf(fmt, args);
+ }
+}
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
index 0000000..60f3f79
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/TheConsole.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+public class TheConsole implements MyConsole {
+ @Override
+ public String readLine(String fmt, Object... args) {
+ String rv = System.console().readLine(fmt, args);
+ if(args.length>0 && args[0]!=null && rv.length()==0) {
+ rv = args[0].toString();
+ }
+ return rv;
+ }
+
+ @Override
+ public char[] readPassword(String fmt, Object... args) {
+ return System.console().readPassword(fmt, args);
+ }
+
+ public static boolean implemented() {
+ return System.console()!=null;
+ }
+
+ @Override
+ public void printf(String fmt, Object... args) {
+ System.console().printf(fmt, args);
+ }
+}
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
index 0000000..89851aa
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/UserChainManip.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+import com.att.cadi.UserChain;
+
+public class UserChainManip {
+ /**
+ Build an element in the correct format for UserChain.
+ Format:<APP>:<ID>:<protocol>[:AS][,<APP>:<ID>:<protocol>]*
+ @see UserChain
+ */
+ public static StringBuilder build(StringBuilder sb, String app, String id, UserChain.Protocol proto, boolean as) {
+ boolean mayAs;
+ if(!(mayAs=sb.length()==0)) {
+ sb.append(',');
+ }
+ sb.append(app);
+ sb.append(':');
+ sb.append(id);
+ sb.append(':');
+ sb.append(proto.name());
+ if(as && mayAs) {
+ sb.append(":AS");
+ }
+ return sb;
+ }
+
+ public static String idToNS(String id) {
+ if(id==null) {
+ return "";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ char c;
+ int end;
+ boolean first = true;
+ for(int idx = end = id.length()-1;idx>=0;--idx) {
+ if((c = id.charAt(idx))=='@' || c=='.') {
+ if(idx<end) {
+ if(first) {
+ first = false;
+ } else {
+ sb.append('.');
+ }
+ for(int i=idx+1;i<=end;++i) {
+ sb.append(id.charAt(i));
+ }
+ }
+ end=idx-1;
+ if(c=='@') {
+ break;
+ }
+ }
+ }
+ return sb.toString();
+ }
+ }
+}
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
index 0000000..b712e31
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/util/Vars.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.util;
+
+import java.util.List;
+
+public class Vars {
+ /**
+ * Simplified Conversion based on typical use of getting AT&T style RESTful Error Messages
+ * @param text
+ * @param vars
+ * @return
+ */
+ public static String convert(final String text, final List<String> vars) {
+ String[] array = new String[vars.size()];
+ StringBuilder sb = new StringBuilder();
+ convert(sb,text,vars.toArray(array));
+ return sb.toString();
+ }
+ /**
+ * Convert a format string with "%s" into AT&T RESTful Error %1 %2 (number) format
+ * If "holder" is passed in, it is built with full Message extracted (typically for Logging)
+ * @param holder
+ * @param text
+ * @param vars
+ * @return
+ */
+ public static String convert(final StringBuilder holder, final String text, final String ... vars) {
+ StringBuilder sb = null;
+ int idx,index=0,prev = 0;
+
+ if(text.contains("%s")) {
+ sb = new StringBuilder();
+ }
+
+ StringBuilder[] sbs = new StringBuilder[] {sb,holder};
+ boolean replace, clearIndex = false;
+ int c;
+ while((idx=text.indexOf('%',prev))>=0) {
+ replace = false;
+ if(clearIndex) {
+ index=0;
+ }
+ if(sb!=null) {
+ sb.append(text,prev,idx);
+ }
+ if(holder!=null) {
+ holder.append(text,prev,idx);
+ }
+
+ boolean go = true;
+ while(go) {
+ if(text.length()>++idx) {
+ switch(c=text.charAt(idx)) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ index *=10;
+ index +=(c-'0');
+ clearIndex=replace=true;
+ continue;
+ case 's':
+ ++index;
+ replace = true;
+ continue;
+ default:
+ break;
+ }
+ }
+ prev = idx;
+ go=false;
+ if(replace) {
+ if(sb!=null) {
+ sb.append('%');
+ sb.append(index);
+ }
+ if(index<=vars.length) {
+ if(holder!=null) {
+ holder.append(vars[index-1]);
+ }
+ }
+ } else {
+ for(StringBuilder s : sbs) {
+ if(s!=null) {
+ s.append("%");
+ }
+ }
+ }
+ }
+ }
+
+ if(sb!=null) {
+ sb.append(text,prev,text.length());
+ }
+ if(holder!=null) {
+ holder.append(text,prev,text.length());
+ }
+
+ return sb==null?text:sb.toString();
+ }
+
+}
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
index 0000000..a9b171c
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/wsse/Action.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse;
+
+/**
+ * Interface to specify an action deep within a parsing tree on a local object
+ *
+ * We use a Generic so as to be flexible on create what that object actually is. This is passed in at the
+ * root "parse" call of Match. Similar to a "Visitor" Pattern, this object is passed upon reaching the right
+ * point in a parse tree.
+ *
+ *
+ * @param <OUTPUT>
+ */
+interface Action<OUTPUT> {
+ public boolean content(OUTPUT output, String text);
+}
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
index 0000000..657976a
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/wsse/Match.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * Match Class allows you to build an automatic Tree of StAX (or StAX like)
+ * Objects for frequent use.
+ *
+ * OBJECT is a type which you which to do some end Actions on, similar to a Visitor pattern, see Action
+ *
+ * Note: We have implemented with XReader and XEvent, rather than StAX for performance reasons.
+ *
+ * @see Action
+ * @see Match
+ * @see XEvent
+ * @see XReader
+ *
+ *
+ * @param <OUTPUT>
+ */
+//@SuppressWarnings("restriction")
+public class Match<OUTPUT> {
+ private QName qname;
+ private Match<OUTPUT>[] next;
+ private Match<OUTPUT> prev;
+ private Action<OUTPUT> action = null;
+ private boolean stopAfter;
+ private boolean exclusive;
+
+
+ @SafeVarargs
+ public Match(String ns, String name, Match<OUTPUT> ... next) {
+ this.qname = new QName(ns,name);
+ this.next = next;
+ stopAfter = exclusive = false;
+ for(Match<OUTPUT> m : next) { // add the possible tags to look for
+ if(!m.stopAfter)m.prev = this;
+ }
+ }
+
+ public Match<OUTPUT> onMatch(OUTPUT output, XReader reader) throws XMLStreamException {
+ while(reader.hasNext()) {
+ XEvent event = reader.nextEvent();
+ switch(event.getEventType()) {
+ case XMLEvent.START_ELEMENT:
+ QName e_qname = event.asStartElement().getName();
+ //System.out.println("Start - " + e_qname);
+ boolean match = false;
+ for(Match<OUTPUT> m : next) {
+ if(e_qname.equals(m.qname)) {
+ match=true;
+ if(m.onMatch(output, reader)==null) {
+ return null; // short circuit Parsing
+ }
+ break;
+ }
+ }
+ if(exclusive && !match) // When Tag MUST be present, i.e. the Root Tag, versus info we're not interested in
+ return null;
+ break;
+ case XMLEvent.CHARACTERS:
+ //System.out.println("Data - " +event.asCharacters().getData());
+ if(action!=null) {
+ if(!action.content(output,event.asCharacters().getData())) {
+ return null;
+ }
+ }
+ break;
+ case XMLEvent.END_ELEMENT:
+ //System.out.println("End - " + event.asEndElement().getName());
+ if(event.asEndElement().getName().equals(qname)) {
+ return prev;
+ }
+ break;
+ case XMLEvent.END_DOCUMENT:
+ return null; // Exit Chain
+ }
+ }
+ return this;
+ }
+
+ /**
+ * When this Matched Tag has completed, Stop parsing and end
+ * @return
+ */
+ public Match<OUTPUT> stopAfter() {
+ stopAfter = true;
+ return this;
+ }
+
+ /**
+ * Mark that this Object MUST be matched at this level or stop parsing and end
+ *
+ * @param action
+ * @return
+ */
+ public Match<OUTPUT> exclusive() {
+ exclusive = true;
+ return this;
+ }
+
+ public Match<OUTPUT> set(Action<OUTPUT> action) {
+ this.action = action;
+ return this;
+ }
+}
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
index 0000000..dd8af4d
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/wsse/WSSEParser.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.stream.XMLStreamException;
+
+import com.att.cadi.BasicCred;
+
+
+/**
+ * WSSE Parser
+ *
+ * Read the User and Password from WSSE Formatted SOAP Messages
+ *
+ * This class uses StAX so that processing is stopped as soon as the Security User/Password are read into BasicCred, or the Header Ends
+ *
+ * This class is intended to be created once (or very few times) and reused as much as possible.
+ *
+ * It is as thread safe as StAX parsing is.
+ *
+ */
+public class WSSEParser {
+ private static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/";
+ private static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
+ private Match<BasicCred> parseTree;
+ //private XMLInputFactory inputFactory;
+
+ public WSSEParser() {
+ // soap:Envelope/soap:Header/wsse:Security/wsse:UsernameToken/[wsse:Password&wsse:Username]
+ parseTree = new Match<BasicCred>(SOAP_NS,"root", // need a root level to start from... Doesn't matter what the tag is
+ new Match<BasicCred>(SOAP_NS,"Envelope",
+ new Match<BasicCred>(SOAP_NS,"Header",
+ new Match<BasicCred>(WSSE_NS,"Security",
+ new Match<BasicCred>(WSSE_NS,"UsernameToken",
+ new Match<BasicCred>(WSSE_NS,"Password").set(new Action<BasicCred>() {
+ public boolean content(BasicCred bc,String text) {
+ bc.setCred(text.getBytes());
+ return true;
+ }
+ }),
+ new Match<BasicCred>(WSSE_NS,"Username").set(new Action<BasicCred>() {
+ public boolean content(BasicCred bc,String text) {
+ bc.setUser(text);
+ return true;
+ }
+ })
+ ).stopAfter() // if found, end when UsernameToken ends (no further processing needed)
+ )
+ ).stopAfter() // Stop Processing when Header Ends
+ ).exclusive()// Envelope must match Header, and no other. FYI, Body comes after Header short circuits (see above), so it's ok
+ ).exclusive(); // root must be Envelope
+ //inputFactory = XMLInputFactory.newInstance();
+ }
+
+ public XMLStreamException parse(BasicCred bc, InputStream is) throws IOException {
+ try {
+ parseTree.onMatch(bc, new XReader(is));
+ return null;
+ } catch (XMLStreamException e) {
+ return e;
+ }
+ }
+}
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
index 0000000..d023519
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/wsse/XEvent.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * XEvent
+ *
+ * This mechanism mimics a minimal portion of StAX "XMLEvent", enough to work with minimal XReader.
+ *
+ * We implement the same interface, as much as minimally necessary, as XMLEvent for these small usages so as to
+ * be interchangeable in the future, if so desired
+ *
+ *
+ */
+// @SuppressWarnings("restriction")
+public abstract class XEvent {
+
+ public abstract int getEventType();
+
+ public StartElement asStartElement() {
+ return (StartElement)this;
+ }
+
+ public Characters asCharacters() {
+ return (Characters)this;
+ }
+
+ public EndElement asEndElement() {
+ return (EndElement)this;
+ }
+
+ public static abstract class NamedXEvent extends XEvent {
+ private QName qname;
+
+ public NamedXEvent(QName qname) {
+ this.qname = qname;
+ }
+
+ public QName getName() {
+ return qname;
+ }
+ }
+ public static class StartElement extends NamedXEvent {
+
+ public StartElement(String ns, String tag) {
+ super(new QName(ns,tag));
+ }
+
+ @Override
+ public int getEventType() {
+ return XMLEvent.START_ELEMENT;
+ }
+ }
+
+ public static class EndElement extends NamedXEvent {
+ public EndElement(String ns, String tag) {
+ super(new QName(ns,tag));
+ }
+
+ @Override
+ public int getEventType() {
+ return XMLEvent.END_ELEMENT;
+ }
+ }
+
+ public static class Characters extends XEvent {
+ private String data;
+
+ public Characters(String data) {
+ this.data = data;
+ }
+ @Override
+ public int getEventType() {
+ return XMLEvent.CHARACTERS;
+ }
+
+ public String getData() {
+ return data;
+ }
+ }
+
+ public static class StartDocument extends XEvent {
+
+ @Override
+ public int getEventType() {
+ return XMLEvent.START_DOCUMENT;
+ }
+
+ }
+
+ public static class EndDocument extends XEvent {
+
+ @Override
+ public int getEventType() {
+ return XMLEvent.END_DOCUMENT;
+ }
+
+ }
+ public static class Comment extends XEvent {
+ public final String value;
+ public Comment(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public int getEventType() {
+ return XMLEvent.COMMENT;
+ }
+
+ }
+
+}
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
index 0000000..135b28c
--- /dev/null
+++ b/core/src/main/java/com/att/cadi/wsse/XReader.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.stream.XMLStreamException;
+
+/**
+ * XReader
+ * This class works similarly as StAX, except StAX has more behavior than is needed. That would be ok, but
+ * StAX also was Buffering in their code in such as way as to read most if not all the incoming stream into memory,
+ * defeating the purpose of pre-reading only the Header
+ *
+ * This Reader does no back-tracking, but is able to create events based on syntax and given state only, leaving the
+ * Read-ahead mode of the InputStream up to the other classes.
+ *
+ * At this time, we only implement the important events, though if this is good enough, it could be expanded, perhaps to
+ * replace the original XMLReader from StAX.
+ *
+ *
+ */
+// @SuppressWarnings("restriction")
+public class XReader {
+ private XEvent curr,another;
+ private InputStream is;
+ private ByteArrayOutputStream baos;
+ private int state, count, last;
+
+ private Stack<Map<String,String>> nsses;
+
+ public XReader(InputStream is) {
+ this.is = is;
+ curr = another = null;
+ baos = new ByteArrayOutputStream();
+ state = BEGIN_DOC;
+ count = 0;
+ nsses = new Stack<Map<String,String>>();
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ if(curr==null) {
+ curr = parse();
+ }
+ return curr!=null;
+ }
+
+ public XEvent nextEvent() {
+ XEvent xe = curr;
+ curr = null;
+ return xe;
+ }
+
+ //
+ // State Flags
+ //
+ // Note: The State of parsing XML can be complicated. There are too many to cleanly keep in "booleans". Additionally,
+ // there are certain checks that can be better made with Bitwise operations within switches
+ // Keeping track of state this way also helps us to accomplish logic without storing any back characters except one
+ private final static int BEGIN_DOC= 0x000001;
+ private final static int DOC_TYPE= 0x000002;
+ private final static int QUESTION_F= 0x000004;
+ private final static int QUESTION = 0x000008;
+ private final static int START_TAG = 0x000010;
+ private final static int END_TAG = 0x000020;
+ private final static int VALUE= 0x000040;
+ private final static int COMMENT = 0x001000;
+ private final static int COMMENT_E = 0x002000;
+ private final static int COMMENT_D1 =0x010000;
+ private final static int COMMENT_D2 =0x020000;
+ private final static int COMMENT_D3 =0x040000;
+ private final static int COMMENT_D4 =0x080000;
+ // useful combined Comment states
+ private final static int IN_COMMENT=COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2;
+ private final static int COMPLETE_COMMENT = COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3|COMMENT_D4;
+
+
+ private XEvent parse() throws XMLStreamException {
+ Map<String,String> nss = nsses.isEmpty()?null:nsses.peek();
+
+ XEvent rv;
+ if((rv=another)!=null) { // "another" is a tag that may have needed to be created, but not
+ // immediately returned. Save for next parse. If necessary, this could be turned into
+ // a FIFO storage, but a single reference is enough for now.
+ another = null; // "rv" is now set for the Event, and will be returned. Set to Null.
+ } else {
+ boolean go = true;
+ int c=0;
+
+ try {
+ while(go && (c=is.read())>=0) {
+ ++count;
+ switch(c) {
+ case '<': // Tag is opening
+ state|=~BEGIN_DOC; // remove BEGIN_DOC flag, this is possibly an XML Doc
+ XEvent cxe = null;
+ if(baos.size()>0) { // If there are any characters between tags, we send as Character Event
+ String chars = baos.toString().trim(); // Trim out WhiteSpace before and after
+ if(chars.length()>0) { // don't send if Characters were only whitespace
+ cxe = new XEvent.Characters(chars);
+ baos.reset();
+ go = false;
+ }
+ }
+ last = c; // make sure "last" character is set for use in "ParseTag"
+ Tag t = parseTag(); // call subroutine to process the tag as a unit
+ String ns;
+ switch(t.state&(START_TAG|END_TAG)) {
+ case START_TAG:
+ nss = getNss(nss,t); // Only Start Tags might have NS Attributes
+ // Get any NameSpace elements from tag. If there are, nss will become
+ // a new Map with all the previous NSs plus the new. This provides
+ // scoping behavior when used with the Stack
+ // drop through on purpose
+ case END_TAG:
+ ns = t.prefix==null?"":nss.get(t.prefix); // Get the namespace from prefix (if exists)
+ break;
+ default:
+ ns = "";
+ }
+ if(ns==null)
+ throw new XMLStreamException("Invalid Namespace Prefix at " + count);
+ go = false;
+ switch(t.state) { // based on
+ case DOC_TYPE:
+ rv = new XEvent.StartDocument();
+ break;
+ case COMMENT:
+ rv = new XEvent.Comment(t.value);
+ break;
+ case START_TAG:
+ rv = new XEvent.StartElement(ns,t.name);
+ nsses.push(nss); // Change potential scope for Namespace
+ break;
+ case END_TAG:
+ rv = new XEvent.EndElement(ns,t.name);
+ nss = nsses.pop(); // End potential scope for Namespace
+ break;
+ case START_TAG|END_TAG: // This tag is both start/end aka <myTag/>
+ rv = new XEvent.StartElement(ns,t.name);
+ if(last=='/')another = new XEvent.EndElement(ns,t.name);
+ }
+ if(cxe!=null) { // if there is a Character Event, it actually should go first. ow.
+ another = rv; // Make current Event the "another" or next event, and
+ rv = cxe; // send Character Event now
+ }
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ if((state&BEGIN_DOC)==BEGIN_DOC) { // if Whitespace before doc, just ignore
+ break;
+ }
+ // fallthrough on purpose
+ default:
+ if((state&BEGIN_DOC)==BEGIN_DOC) { // if there is any data at the start other than XML Tag, it's not XML
+ throw new XMLStreamException("Parse Error: This is not an XML Doc");
+ }
+ baos.write(c); // save off Characters
+ }
+ last = c; // Some processing needs to know what the last character was, aka Escaped characters... ex \"
+ }
+ } catch (IOException e) {
+ throw new XMLStreamException(e); // all errors parsing will be treated as XMLStreamErrors (like StAX)
+ }
+ if(c==-1 && (state&BEGIN_DOC)==BEGIN_DOC) { // Normally, end of stream is ok, however, we need to know if the
+ throw new XMLStreamException("Premature End of File"); // document isn't an XML document, so we throw exception if it
+ } // hasn't yet been determined to be an XML Doc
+ }
+ return rv;
+ }
+
+ /**
+ * parseTag
+ *
+ * Parsing a Tag is somewhat complicated, so it's helpful to separate this process from the
+ * higher level Parsing effort
+ * @return
+ * @throws IOException
+ * @throws XMLStreamException
+ */
+ private Tag parseTag() throws IOException, XMLStreamException {
+ Tag tag = null;
+ boolean go = true;
+ state = 0;
+ 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
+ String prefix=null,name=null,value=null;
+ baos.reset();
+
+ while(go && (c=is.read())>=0) {
+ ++count;
+ if(quote!=0) { // If we're in a quote, we only end if we hit another quote of the same time, not preceded by \
+ if(c==quote && last!='\\') {
+ quote=0;
+ } else {
+ baos.write(c);
+ }
+ } else if((state&COMMENT)==COMMENT) { // similar to Quote is being in a comment
+ switch(c) {
+ case '-':
+ switch(state) { // XML has a complicated Quote set... <!-- --> ... we keep track if each has been met with flags.
+ case COMMENT|COMMENT_E:
+ state|=COMMENT_D1;
+ break;
+ case COMMENT|COMMENT_E|COMMENT_D1:
+ state|=COMMENT_D2;
+ baos.reset(); // clear out "!--", it's a Comment
+ break;
+ case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2:
+ state|=COMMENT_D3;
+ baos.write(c);
+ break;
+ case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3:
+ state|=COMMENT_D4;
+ baos.write(c);
+ break;
+ }
+ break;
+ case '>': // Tag indicator has been found, do we have all the comment characters in line?
+ if((state&COMPLETE_COMMENT)==COMPLETE_COMMENT) {
+ byte ba[] = baos.toByteArray();
+ tag = new Tag(null,null, new String(ba,0,ba.length-2));
+ baos.reset();
+ go = false;
+ break;
+ }
+ // fall through on purpose
+ default:
+ state&=~(COMMENT_D3|COMMENT_D4);
+ if((state&IN_COMMENT)!=IN_COMMENT) state&=~IN_COMMENT; // false alarm, it's not actually a comment
+ baos.write(c);
+ }
+ } else { // Normal Tag Processing loop
+ switch(c) {
+ case '?':
+ switch(state & (QUESTION_F|QUESTION)) { // Validate the state of Doc tag... <?xml ... ?>
+ case QUESTION_F:
+ state |= DOC_TYPE;
+ state &= ~QUESTION_F;
+ break;
+ case 0:
+ state |=QUESTION_F;
+ break;
+ default:
+ throw new IOException("Bad character [?] at " + count);
+ }
+ break;
+ case '!':
+ if(last=='<') {
+ state|=COMMENT|COMMENT_E; // likely a comment, continue processing in Comment Loop
+ }
+ baos.write(c);
+ break;
+ case '/':
+ state|=(last=='<'?END_TAG:(END_TAG|START_TAG)); // end tag indicator </xxx>, ,or both <xxx/>
+ break;
+ case ':':
+ prefix=baos.toString(); // prefix indicator
+ baos.reset();
+ break;
+ case '=': // used in Attributes
+ name=baos.toString();
+ baos.reset();
+ state|=VALUE;
+ break;
+ case '>': // end the tag, which causes end of this subprocess as well as formulation of the found data
+ go = false;
+ // passthrough on purpose
+ case ' ':
+ case '\t':
+ case '\n': // white space indicates change in internal tag state, ex between name and between attributes
+ if((state&VALUE)==VALUE) {
+ value = baos.toString(); // we're in VALUE state, add characters to Value
+ } else if(name==null) {
+ name = baos.toString(); // we're in Name state (default) add characters to Name
+ }
+ baos.reset(); // we've assigned chars, reset buffer
+ if(name!=null) { // Name is not null, there's a tag in the offing here...
+ Tag t = new Tag(prefix,name,value);
+ if(tag==null) { // Set as the tag to return, if not exists
+ tag = t;
+ } else { // if we already have a Tag, then we'll treat this one as an attribute
+ tag.add(t);
+ }
+ }
+ prefix=name=value=null; // reset these values in case we loop for attributes.
+ break;
+ case '\'': // is the character one of two kinds of quote?
+ case '"':
+ if(last!='\\') {
+ quote=c;
+ break;
+ }
+ // Fallthrough ok
+ default:
+ baos.write(c); // write any unprocessed bytes into buffer
+
+ }
+ }
+ last = c;
+ }
+ int type = state&(DOC_TYPE|COMMENT|END_TAG|START_TAG); // get just the Tag states and turn into Type for Tag
+ if(type==0) {
+ type=START_TAG;
+ }
+ tag.state|=type; // add the appropriate Tag States
+ return tag;
+ }
+
+ /**
+ * getNSS
+ *
+ * If the tag contains some Namespace attributes, create a new nss from the passed in one, copy all into it, then add
+ * This provides Scoping behavior
+ *
+ * if Nss is null in the first place, create an new nss, so we don't have to deal with null Maps.
+ *
+ * @param nss
+ * @param t
+ * @return
+ */
+ private Map<String, String> getNss(Map<String, String> nss, Tag t) {
+ Map<String,String> newnss = null;
+ if(t.attribs!=null) {
+ for(Tag tag : t.attribs) {
+ if("xmlns".equals(tag.prefix)) {
+ if(newnss==null) {
+ newnss = new HashMap<String,String>();
+ if(nss!=null)newnss.putAll(nss);
+ }
+ newnss.put(tag.name, tag.value);
+ }
+ }
+ }
+ return newnss==null?(nss==null?new HashMap<String,String>():nss):newnss;
+ }
+
+ /**
+ * The result of the parseTag method
+ *
+ * Data is split up into prefix, name and value portions. "Tags" with Values that are inside a Tag are known in XLM
+ * as Attributes.
+ *
+ *
+ */
+ public class Tag {
+ public int state;
+ public String prefix,name,value;
+ public List<Tag> attribs;
+
+ public Tag(String prefix, String name, String value) {
+ this.prefix = prefix;
+ this.name = name;
+ this.value = value;
+ attribs = null;
+ }
+
+ /**
+ * add an attribute
+ * Not all tags need attributes... lazy instantiate to save time and memory
+ * @param tag
+ */
+ public void add(Tag attrib) {
+ if(attribs == null) {
+ attribs = new ArrayList<Tag>();
+ }
+ attribs.add(attrib);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ if(prefix!=null) {
+ sb.append(prefix);
+ sb.append(':');
+ }
+ sb.append(name==null?"!!ERROR!!":name);
+
+ char quote = ((state&DOC_TYPE)==DOC_TYPE)?'\'':'"';
+ if(value!=null) {
+ sb.append('=');
+ sb.append(quote);
+ sb.append(value);
+ sb.append(quote);
+ }
+ return sb.toString();
+ }
+ }
+
+}
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
index 0000000..2143e5b
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/JU_AES.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+public class JU_AES {
+
+ @Test
+ public void test() throws Exception {
+ AES aes = new AES();
+ String orig = "I'm a password, really";
+ byte[] passin = orig.getBytes();
+ byte[] encrypted = aes.encrypt(passin);
+ byte[] b64enc = Symm.base64.encode(encrypted);
+ System.out.println(new String(b64enc));
+
+ encrypted = Symm.base64.decode(b64enc);
+ passin = aes.decrypt(encrypted);
+ Assert.assertEquals(orig, new String(passin));
+ }
+
+ @Test
+ public void testInputStream() throws Exception {
+ AES aes = new AES();
+ String orig = "I'm a password, really";
+ ByteArrayInputStream bais = new ByteArrayInputStream(orig.getBytes());
+ CipherInputStream cis = aes.inputStream(bais, true);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64.encode(cis, baos);
+ cis.close();
+
+ byte[] b64encrypted;
+ System.out.println(new String(b64encrypted=baos.toByteArray()));
+
+
+ baos.reset();
+ CipherOutputStream cos = aes.outputStream(baos, false);
+ Symm.base64.decode(new ByteArrayInputStream(b64encrypted),cos);
+ cos.close();
+ Assert.assertEquals(orig, new String(baos.toByteArray()));
+ }
+
+ @Test
+ public void testObtain() throws Exception {
+ byte[] keygen = Symm.baseCrypt().keygen();
+
+ Symm symm = Symm.obtain(new ByteArrayInputStream(keygen));
+
+ String orig ="Another Password, please";
+ String encrypted = symm.enpass(orig);
+ System.out.println(encrypted);
+ String decrypted = symm.depass(encrypted);
+ System.out.println(decrypted);
+ Assert.assertEquals(orig, decrypted);
+ }
+
+}
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
index 0000000..a4ada86
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/lur/test/JU_LocalLur.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.junit.Test;
+
+import com.att.cadi.CredVal.Type;
+import com.att.cadi.Lur;
+import com.att.cadi.Permission;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.config.UsersDump;
+import com.att.cadi.lur.LocalLur;
+import com.att.cadi.lur.LocalPermission;
+
+public class JU_LocalLur {
+
+ @Test
+ public void test() throws IOException {
+ Symm symmetric = Symm.baseCrypt().obtain();
+ LocalLur up;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(Symm.ENC.getBytes());
+ symmetric.enpass("<pass>", baos);
+ PropAccess ta = new PropAccess();
+ Lur ml = up = new LocalLur(ta,"myname:groupA,groupB","admin:myname,yourname;suser:hisname,hername,m1234%"+baos.toString());
+
+ Permission admin = new LocalPermission("admin");
+ Permission suser = new LocalPermission("suser");
+
+ // Check User fish
+ assertTrue(ml.fish(new JUPrincipal("myname"),admin));
+ assertTrue(ml.fish(new JUPrincipal("hisname"),admin));
+ assertFalse(ml.fish(new JUPrincipal("noname"),admin));
+ assertTrue(ml.fish(new JUPrincipal("itsname"),suser));
+ assertTrue(ml.fish(new JUPrincipal("hername"),suser));
+ assertFalse(ml.fish(new JUPrincipal("myname"),suser));
+
+
+ // Check validate password
+ assertTrue(up.validate("m1234",Type.PASSWORD, "<pass>".getBytes()));
+ assertFalse(up.validate("m1234",Type.PASSWORD, "badPass".getBytes()));
+
+ // Check fishAll
+ Set<String> set = new TreeSet<String>();
+ List<Permission> perms = new ArrayList<Permission>();
+ ml.fishAll(new JUPrincipal("myname"), perms);
+ for(Permission p : perms) {
+ set.add(p.getKey());
+ }
+ assertEquals("[admin, groupA, groupB]",set.toString());
+ UsersDump.write(System.out, up);
+ System.out.flush();
+
+ }
+
+ // Simplistic Principal for testing purposes
+ private static class JUPrincipal implements Principal {
+ private String name;
+ public JUPrincipal(String name) {
+ this.name = name;
+ }
+// @Override
+ public String getName() {
+ return name;
+ }
+ }
+
+}
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
index 0000000..f8e911c
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/lur/test/TestAccess.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.lur.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+
+public class TestAccess implements Access {
+ private Symm symm;
+
+ public TestAccess() {
+ symm = Symm.obtain(this);
+ }
+
+ public TestAccess(Symm symmetric) {
+ symm = symmetric;
+ }
+
+ public void log(Level level, Object... elements) {
+ boolean first = true;
+ for(int i=0;i<elements.length;++i) {
+ if(first)first = false;
+ else System.out.print(' ');
+ System.out.print(elements[i].toString());
+ }
+ System.out.println();
+ }
+
+ public void log(Exception e, Object... elements) {
+ e.printStackTrace();
+ log(Level.ERROR,elements);
+ }
+
+ public void setLogLevel(Level level) {
+
+ }
+
+ public ClassLoader classLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ public String getProperty(String string, String def) {
+ String rv = System.getProperty(string);
+ return rv==null?def:rv;
+ }
+
+ public void load(InputStream is) throws IOException {
+
+ }
+
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ }
+
+ @Override
+ public boolean willLog(Level level) {
+ return true;
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object[] elements) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
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
index 0000000..fdafb84
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_Base64.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+import org.junit.Test;
+
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+
+public class JU_Base64 {
+ private static final String encoding = "Man is distinguished, not only by his reason, but by this singular " +
+ "passion from other animals, which is a lust of the mind, that by a " +
+ "perseverance of delight in the continued and indefatigable generation of " +
+ "knowledge, exceeds the short vehemence of any carnal pleasure.";
+
+ private static final String expected =
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\n" +
+ "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\n" +
+ "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\n" +
+ "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\n" +
+ "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";
+
+
+ @Test
+ public void test() throws Exception {
+ // Test with different Padding
+ encode("leas", "bGVhcw==");
+ encode("leasu", "bGVhc3U=");
+ encode("leasur", "bGVhc3Vy");
+ encode("leasure", "bGVhc3VyZQ==");
+ encode("leasure.","bGVhc3VyZS4=");
+
+ // Test with line ends
+ encode(encoding, expected);
+
+ int ITER = 2000;
+ System.out.println("Priming by Encoding Base64 " + ITER + " times");
+ long start = System.nanoTime();
+ for(int i=0;i<ITER;++i) {
+ Symm.base64.encode(encoding);
+ }
+ Float ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/ITER + "ms");
+
+ System.out.println("Priming by Decoding Base64 " + ITER + " times");
+ start = System.nanoTime();
+ for(int i=0;i<ITER;++i) {
+ Symm.base64.decode(expected);
+ }
+ ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/ITER + "ms");
+
+
+ ITER=30000;
+ System.out.println("Encoding Base64 " + ITER + " times");
+ start = System.nanoTime();
+ for(int i=0;i<ITER;++i) {
+ Symm.base64.encode(encoding);
+ }
+ ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/ITER + "ms");
+
+ System.out.println("Decoding Base64 " + ITER + " times");
+ start = System.nanoTime();
+ for(int i=0;i<ITER;++i) {
+ Symm.base64.decode(expected);
+ }
+ ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/ITER + "ms");
+ }
+
+ @Test
+ public void symmetric() throws IOException {
+ System.out.println("Validating Generated Key mechanisms works");
+ String symmetric = new String(Symm.base64.keygen());
+ System.out.println(symmetric);
+ Symm bsym = Symm.obtain(symmetric);
+ String result = bsym.encode(encoding);
+ System.out.println("\nResult:");
+ System.out.println(result);
+ assertEquals(encoding, bsym.decode(result));
+
+ int ITER = 20000;
+ System.out.println("Generating keys " + ITER + " times");
+ long start = System.nanoTime();
+ for(int i=0;i<ITER;++i) {
+ Symm.base64.keygen();
+ }
+ Float ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/ITER + "ms");
+
+ char[] manipulate = symmetric.toCharArray();
+ int spot = new SecureRandom().nextInt(manipulate.length);
+ manipulate[spot]|=0xFF;
+ String newsymmetric = new String(manipulate);
+ assertNotSame(newsymmetric, symmetric);
+ try {
+ bsym = Symm.obtain(newsymmetric);
+ result = bsym.decode(result);
+ assertEquals(encoding, result);
+ } catch (IOException e) {
+ // this is what we want to see if key wrong
+ System.out.println(e.getMessage() + " (as expected)");
+ }
+ }
+
+ private void encode(String toEncode, String expected) throws IOException {
+ System.out.println("-------------------------------------------------");
+ System.out.println(toEncode);
+ System.out.println();
+ System.out.println(expected);
+ System.out.println();
+ String result = Symm.base64.encode(toEncode);
+ System.out.println(result);
+ assertEquals(expected,result);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64.decode(new ByteArrayInputStream(result.getBytes()), baos);
+ result = baos.toString(Config.UTF_8);
+ System.out.println(result);
+ assertEquals(toEncode,result);
+
+ }
+}
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
index 0000000..c30d944
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_BufferedServletInputStream.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import static junit.framework.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.att.cadi.BufferedServletInputStream;
+
+public class JU_BufferedServletInputStream {
+
+ @Test
+ public void testByteRead() throws Exception {
+ FileInputStream fis = new FileInputStream("test/CBUSevent.xml");
+ BufferedServletInputStream bsis = new BufferedServletInputStream(fis);
+ try {
+ bsis.mark(0);
+ int c;
+ byte aa[] = new byte[260];
+ for(int i=0;i<aa.length;++i) {
+ c = bsis.read();
+ if(c>=0) {
+ aa[i]=(byte)c;
+ }
+ }
+ System.out.println(new String(aa));
+
+ bsis.reset();
+
+ byte bb[] = new byte[400];
+ for(int i=0;i<bb.length;++i) {
+ c = bsis.read();
+ if(c>=0) {
+ bb[i]=(byte)c;
+ }
+ }
+ System.out.println(new String(bb));
+
+ } finally {
+ bsis.close();
+ fis.close();
+ }
+ }
+
+ @Test
+ public void testByteArray() throws Exception {
+ FileInputStream fis = new FileInputStream("test/CBUSevent.xml");
+ BufferedServletInputStream bsis = new BufferedServletInputStream(fis);
+ try {
+ bsis.mark(0);
+ byte aa[] = new byte[260];
+ bsis.read(aa);
+ System.out.println(new String(aa));
+
+ bsis.reset();
+
+ byte bb[] = new byte[400];
+ bsis.read(bb);
+ System.out.println(new String(bb));
+
+ } finally {
+ bsis.close();
+ fis.close();
+ }
+ }
+
+ @Test
+ public void testDoubleRead() throws Exception {
+ FileInputStream fis = new FileInputStream("test/CBUSevent.xml");
+ BufferedServletInputStream bsis = new BufferedServletInputStream(fis);
+ try {
+ bsis.mark(0);
+ byte aa[] = new byte[260];
+ bsis.read(aa);
+ System.out.println(new String(aa));
+
+ bsis.reset();
+
+ byte bb[] = new byte[400];
+ bsis.read(bb);
+ System.out.println(new String(bb));
+
+ } finally {
+ bsis.close();
+ fis.close();
+ }
+ }
+
+ @Test
+ public void testByteArray2() throws Exception {
+ FileInputStream fis = new FileInputStream("test/CBUSevent.xml");
+ try {
+ BufferedServletInputStream bsis = new BufferedServletInputStream(fis);
+ byte[] content = null;
+ byte aa[] = new byte[500];
+ for(int i=0;i<2000;++i) {
+ bsis.mark(0);
+ bsis.read(aa,0,260);
+ if(i==0)System.out.println(new String(aa));
+
+ bsis.reset();
+
+ bsis.read(aa,0,aa.length);
+ if(i==0) {
+ System.out.println(new String(aa));
+ content = aa;
+ aa = new byte[400];
+ }
+ bsis = new BufferedServletInputStream(new ByteArrayInputStream(content));
+
+ }
+
+ System.out.println(new String(aa));
+
+ } finally {
+ fis.close();
+ }
+ }
+
+ // "Bug" 4/22/2013
+ // Some XML code expects Buffered InputStream can never return 0... This isn't actually true, but we'll accommodate as far
+ // as we can.
+ // Here, we make sure we set and read the Buffered data, making sure the buffer is empty on the last test...
+ @Test
+ public void issue04_22_2013() throws IOException {
+ String testString = "We want to read in and get out with a Buffered Stream seamlessly.";
+ ByteArrayInputStream bais = new ByteArrayInputStream(testString.getBytes());
+ BufferedServletInputStream bsis = new BufferedServletInputStream(bais);
+ try {
+ bsis.mark(0);
+ byte aa[] = new byte[testString.length()]; // 65 count... important for our test (divisible by 5);
+
+ int read;
+ for(int i=0;i<aa.length;i+=5) {
+ read = bsis.read(aa, i, 5);
+ assertEquals(5,read);
+ }
+ System.out.println(new String(aa));
+
+ bsis.reset();
+
+ byte bb[] = new byte[aa.length];
+ read = 0;
+ for(int i=0;read>=0;i+=read) {
+ read = bsis.read(bb,i,5);
+ switch(i) {
+ case 65:
+ assertEquals(read,-1);
+ break;
+ default:
+ assertEquals(read,5);
+ }
+ }
+ System.out.println(new String(bb));
+ assertEquals(testString,new String(aa));
+ assertEquals(testString,new String(bb));
+
+ } finally {
+ bsis.close();
+ bais.close();
+ }
+
+ }
+
+
+}
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
index 0000000..c3f6d77
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_Capacitor.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import static junit.framework.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.att.cadi.Capacitor;
+
+public class JU_Capacitor {
+ @Test
+ public void testA() {
+ Capacitor cap = new Capacitor();
+
+ for(int iter=0;iter<200;++iter) {
+ for(int i=0;i<20;++i) {
+ cap.put((byte)('a'+i));
+ }
+ cap.setForRead();
+ byte[] array = new byte[20];
+ for(int i=0;i<20;++i) {
+ array[i]=(byte)cap.read();
+ }
+ assertEquals("abcdefghijklmnopqrst",new String(array));
+ assertEquals(-1,cap.read());
+ cap.done();
+ }
+ }
+
+ public final static String TEST_DATA =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" +
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
+ @Test
+ public void testB() {
+ Capacitor cap = new Capacitor();
+ byte[] arrayA = TEST_DATA.getBytes();
+ System.out.println(arrayA.length);
+ for(int iter=0;iter<200;++iter) {
+ for(int i=0;i<arrayA.length;++i) {
+ cap.put(arrayA[i]);
+ }
+ cap.setForRead();
+ assertEquals(TEST_DATA.length(),cap.available());
+ byte[] arrayB = new byte[arrayA.length];
+ for(int i=0;i<arrayB.length;++i) {
+ arrayB[i]=(byte)cap.read();
+ }
+ assertEquals(TEST_DATA,new String(arrayB));
+ assertEquals(-1,cap.read());
+ cap.done();
+ }
+ }
+
+ @Test
+ public void testC() {
+ Capacitor cap = new Capacitor();
+ byte[] arrayA = TEST_DATA.getBytes();
+ System.out.println(arrayA.length);
+ for(int iter=0;iter<200;++iter) {
+ cap.put(arrayA,0,arrayA.length);
+ cap.setForRead();
+ assertEquals(TEST_DATA.length(),cap.available());
+ byte[] arrayB = new byte[arrayA.length];
+ assertEquals(arrayA.length,cap.read(arrayB,0,arrayB.length));
+ assertEquals(TEST_DATA,new String(arrayB));
+ assertEquals(-1,cap.read());
+ cap.done();
+ }
+ }
+
+
+ @Test
+ public void testD() {
+ StringBuffer sb = new StringBuffer();
+ for(int i=0;i<300;++i) {
+ sb.append(TEST_DATA);
+ sb.append("###FILLER##");
+ }
+ String td = sb.toString();
+ Capacitor cap = new Capacitor();
+ byte[] arrayA = td.getBytes();
+ System.out.println(arrayA.length);
+ for(int iter=0;iter<200;++iter) {
+ cap.put(arrayA,0,arrayA.length);
+ cap.setForRead();
+ assertEquals(td.length(),cap.available());
+ byte[] arrayB = new byte[arrayA.length];
+ assertEquals(arrayA.length,cap.read(arrayB,0,arrayB.length));
+ assertEquals(td,new String(arrayB));
+ assertEquals(-1,cap.read());
+ cap.done();
+ }
+ }
+
+ @Test
+ public void testE() {
+ Capacitor cap = new Capacitor();
+
+ String b = "This is some content that we want to read";
+ byte[] a = b.getBytes();
+ byte[] c = new byte[b.length()]; // we want to use this to test reading offsets, etc
+
+ for(int i=0;i<a.length;i+=11) {
+ cap.put(a, i, Math.min(11,a.length-i));
+ }
+ cap.reset();
+ int read;
+ for(int i=0;i<c.length;i+=read) {
+ read = cap.read(c, i, Math.min(3,c.length-i));
+ if(read<0) break;
+ }
+
+ assertEquals(b, new String(c));
+
+
+ }
+
+
+}
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
index 0000000..85e4209
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_Hash.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import org.junit.Test;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Hash;
+
+import junit.framework.Assert;
+
+public class JU_Hash {
+
+ @Test
+ public void test() throws CadiException {
+ String init = "m82347@csp.att.com:kumquat8rie@#Tomatos3";
+ String hashed = Hash.toHex(init.getBytes());
+ System.out.println(hashed);
+ byte[] ba = Hash.fromHex(hashed);
+ String recon = new String(ba);
+ System.out.println(recon);
+ Assert.assertEquals(init, recon);
+
+ init =hashed.substring(1);
+ try {
+ hashed = Hash.fromHex(init).toString();
+ Assert.fail("Should have thrown Exception");
+ } catch (CadiException e) {
+
+ }
+
+ init = hashed.replace('1', '~');
+ try {
+ hashed = Hash.fromHex(init).toString();
+ Assert.fail("Should have thrown Exception");
+ } catch (CadiException e) {
+
+ }
+ }
+
+}
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
index 0000000..68c7dc8
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_Passcode.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+
+import org.junit.Test;
+
+import com.att.cadi.CmdLine;
+import com.att.cadi.Symm;
+
+import junit.framework.Assert;
+
+public class JU_Passcode {
+ @Test
+ public void test() throws Exception {
+ int iterations = 0;
+ long start = System.nanoTime();
+ int gens= 800, en_de=2000;
+ for(int j=0;j<gens;++j) {
+ CmdLine.main(new String[] {"keygen","tempkey"});
+
+ Symm symm;
+ File fi = new File("tempkey");
+ Assert.assertEquals(2074, fi.length());
+ FileInputStream fis = new FileInputStream(fi);
+
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ fis.close();
+ }
+ String samples[] = {"activevos","ThisIsATestPassword","I have spaces","I have 's, /s and &s and _s"};
+ ByteArrayOutputStream baos;
+ for(int i=0;i<en_de;++i) {
+ String password = samples[i%samples.length];
+ baos = new ByteArrayOutputStream();
+ symm.enpass(password, baos);
+ String pass = baos.toString();
+ byte[] array = baos.toByteArray();
+ for(int k=0;k<array.length;++k) {
+ byte ch = array[k];
+// for(int k=0;k<pass.length();++k) {
+// char ch = pass.charAt(k);
+ if(!(Character.isLetter(ch) || Character.isDigit(ch) || ch=='-' || ch=='_' || ch=='=')) {
+ throw new Exception("Yikes, have a bad character..." + ch + '(' + (int)ch + ')');
+ }
+ }
+ baos = new ByteArrayOutputStream();
+ symm.depass(pass, baos);
+ Assert.assertEquals(password,baos.toString());
+ Assert.assertEquals(password,symm.depass(pass));
+ ++iterations;
+ }
+ symm.enpass("activevos", System.out);
+ System.out.println();
+ }
+ float ms = (System.nanoTime()-start)/1000000F;
+ System.out.println("Ran " + iterations + " Encrypt/Decrypt cycles + " + gens + " keygens");
+
+ System.out.println("Total: " + ms + "ms");
+ System.out.println("Avg: " + ms/iterations + "ms");
+ System.out.println("Avg Gen + " + en_de + " Encrypt/Decrypt cycles: " + ms/gens + "ms");
+
+
+ }
+
+}
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
index 0000000..40b9266
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_UserChainManip.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import com.att.cadi.util.UserChainManip;
+
+public class JU_UserChainManip {
+
+ @Test
+ public void test() {
+ assertEquals("",UserChainManip.idToNS(null));
+ assertEquals("",UserChainManip.idToNS(""));
+ assertEquals("",UserChainManip.idToNS("something"));
+ assertEquals("",UserChainManip.idToNS("something@@"));
+ assertEquals("",UserChainManip.idToNS("something@@."));
+ assertEquals("com",UserChainManip.idToNS("something@com"));
+ assertEquals("com.random",UserChainManip.idToNS("something@random.com"));
+ assertEquals("com.random",UserChainManip.idToNS("@random.com"));
+ assertEquals("com.random",UserChainManip.idToNS("something@random.com."));
+ assertEquals("com.random",UserChainManip.idToNS("something@..random...com..."));
+ assertEquals("com.random.this",UserChainManip.idToNS("something@this.random.com"));
+ }
+
+}
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
index 0000000..daf2c0f
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/JU_Vars.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import com.att.cadi.util.Vars;
+
+public class JU_Vars {
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Test
+ public void test() {
+ StringBuilder holder = new StringBuilder();
+ String str,bstr;
+ assertEquals(str = "set %1 to %2",Vars.convert(holder,str, "a","b"));
+ assertEquals("set a to b",holder.toString());
+ assertEquals(str,Vars.convert(null,str, "a","b"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr="set %s to %s", "a","b"));
+ assertEquals("set a to b",holder.toString());
+ assertEquals(str,Vars.convert(null,bstr, "a","b"));
+
+ holder.setLength(0);
+ assertEquals(str = "%1=%2",Vars.convert(holder,str, "a","b"));
+ assertEquals("a=b",holder.toString());
+ assertEquals(str,Vars.convert(null,str, "a","b"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr="%s=%s", "a","b"));
+ assertEquals("a=b",holder.toString());
+ assertEquals(str,Vars.convert(null,bstr, "a","b"));
+
+ holder.setLength(0);
+ assertEquals(str = "%1%2",Vars.convert(holder,str, "a","b"));
+ assertEquals("ab",holder.toString());
+ assertEquals(str ,Vars.convert(null,str, "a","b"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr="%s%s", "a","b"));
+ assertEquals("ab",holder.toString());
+ assertEquals(str ,Vars.convert(null,bstr, "a","b"));
+
+
+ holder.setLength(0);
+ assertEquals(str = " %1=%2 ",Vars.convert(holder,str, "a","b"));
+ assertEquals(" a=b ",holder.toString());
+ assertEquals(str ,Vars.convert(null,str, "a","b"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr = " %s=%s ", "a","b"));
+ assertEquals(" a=b ",holder.toString());
+ assertEquals(str ,Vars.convert(null,bstr, "a","b"));
+
+ holder.setLength(0);
+ assertEquals(str = " %1%2%10 ",Vars.convert(holder,str, "a","b","c","d","e","f","g","h","i","j"));
+ assertEquals(" abj ",holder.toString());
+ assertEquals(str,Vars.convert(null,str, "a","b","c","d","e","f","g","h","i","j"));
+ holder.setLength(0);
+ assertEquals(str=" %1%2%3 ",Vars.convert(holder,bstr = " %s%s%s ", "a","b","c","d","e","f","g","h","i","j"));
+ assertEquals(" abc ",holder.toString());
+ assertEquals(str,Vars.convert(null,bstr, "a","b","c","d","e","f","g","h","i","j"));
+
+
+ holder.setLength(0);
+ assertEquals(str = "set %1 to %2",Vars.convert(holder,str, "Something much","larger"));
+ assertEquals("set Something much to larger",holder.toString());
+ assertEquals(str,Vars.convert(null,str,"Something much","larger"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr="set %s to %s", "Something much","larger"));
+ assertEquals("set Something much to larger",holder.toString());
+ assertEquals(str,Vars.convert(null,bstr, "Something much","larger"));
+
+ holder.setLength(0);
+ assertEquals(str = "Text without Vars",Vars.convert(holder,str));
+ assertEquals(str,holder.toString());
+ assertEquals(str = "Text without Vars",Vars.convert(null,str));
+
+
+ holder.setLength(0);
+ assertEquals(str = "Not %1 Enough %2 Vars %3",Vars.convert(holder,str, "a","b"));
+ assertEquals("Not a Enough b Vars ",holder.toString());
+ assertEquals(str ,Vars.convert(null,str, "a","b"));
+ holder.setLength(0);
+ assertEquals(str,Vars.convert(holder,bstr="Not %s Enough %s Vars %s", "a","b"));
+ assertEquals("Not a Enough b Vars ",holder.toString());
+ assertEquals(str ,Vars.convert(null,bstr, "a","b"));
+
+ holder.setLength(0);
+ assertEquals(str = "!@#$%^*()-+?/,:;.",Vars.convert(holder,str, "a","b"));
+ assertEquals(str,holder.toString());
+ assertEquals(str ,Vars.convert(null,str, "a","b"));
+
+ holder.setLength(0);
+ bstr = "%s !@#$%^*()-+?/,:;.";
+ str = "%1 !@#$%^*()-+?/,:;.";
+ assertEquals(str,Vars.convert(holder,bstr, "Not Acceptable"));
+ assertEquals("Not Acceptable !@#$%^*()-+?/,:;.",holder.toString());
+ assertEquals(str ,Vars.convert(null,bstr, "Not Acceptable"));
+
+ }
+
+}
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
index 0000000..53729b4
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/test/Test.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.test;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A Class to run on command line to determine suitability of environment for certain TAFs.
+ *
+ * For instance, CSP supports services only in certain domains, and while dynamic host
+ * lookups on the machine work in most cases, sometimes, names and IPs are unexpected (and
+ * invalid) for CSP because of multiple NetworkInterfaces, etc
+ *
+ *
+ */
+public class Test {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("CADI/TAF test");
+
+ String hostName = InetAddress.getLocalHost().getCanonicalHostName();
+
+ System.out.println(" Your automatic hostname is reported as \"" + hostName + "\"\n");
+ String[] two;
+
+ for(String str : args) {
+ two = str.split("=");
+ if(two.length==2) {
+ if("hostname".equals(two[0])) {
+ hostName = two[1];
+ System.out.println(" You have overlaid the automatic hostname with \"" + hostName + "\"\n");
+ }
+ }
+ }
+ if(hostName.endsWith("vpn.cingular.net"))
+ System.out.println(" This service appears to be an AT&T VPN address. These VPNs are typically\n" +
+ " (and appropriately) firewalled against incoming traffic, and likely cannot be accessed.\n" +
+ " For best results, choose a machine that is not firewalled on the ports you choose.\n");
+
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
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
index 0000000..a262780
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/wsse/test/JU_WSSE_Read.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse.test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.junit.Test;
+
+import com.att.cadi.BasicCred;
+import com.att.cadi.BufferedServletInputStream;
+import com.att.cadi.wsse.WSSEParser;
+
+public class JU_WSSE_Read {
+
+ @Test
+ public void test() {
+ try {
+ final BasicCred bc = new BasicCred() {
+
+ private String user;
+ private byte[] password;
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public void setCred(byte[] passwd) {
+ this.password = passwd;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public byte[] getCred() {
+ return password;
+ }
+ };
+
+ WSSEParser wp = new WSSEParser();
+
+ FileInputStream fis;
+ fis = new FileInputStream("test/example.xml");
+ BufferedServletInputStream is = new BufferedServletInputStream(fis);
+ try {
+ is.mark(1536);
+ try {
+ assertNull(wp.parse(bc, is));
+ } finally {
+ is.reset();
+ assertEquals(814,is.buffered());
+ }
+ String password = new String(bc.getCred());
+ System.out.println("CadiWrap credentials are: " + bc.getUser() + ", " + password);
+ assertEquals("some_user", bc.getUser());
+ assertEquals("some_password", password);
+
+ } finally {
+ fis.close();
+ }
+
+ // CBUS (larger)
+ fis = new FileInputStream("test/CBUSevent.xml");
+ is = new BufferedServletInputStream(fis);
+ try {
+ is.mark(1536);
+ try {
+ assertNull(wp.parse(bc, is));
+ } finally {
+ is.reset();
+ assertEquals(667,is.buffered());
+ }
+ String password = new String(bc.getCred());
+ System.out.println("CadiWrap credentials are: " + bc.getUser() + ", " + password);
+ assertEquals("none", bc.getUser());
+ assertEquals("none", password);
+
+ } finally {
+ fis.close();
+ }
+
+ // Closed Stream
+ fis = new FileInputStream("test/example.xml");
+ fis.close();
+ bc.setCred(null);
+ bc.setUser(null);
+ XMLStreamException ex = wp.parse(bc, fis);
+ assertNotNull(ex);
+ assertNull(bc.getUser());
+ assertNull(bc.getCred());
+
+
+ fis = new FileInputStream("test/exampleNoSecurity.xml");
+ try {
+ bc.setCred(null);
+ bc.setUser(null);
+ assertNull(wp.parse(bc, fis));
+ assertNull(bc.getUser());
+ assertNull(bc.getCred());
+ } finally {
+ fis.close();
+ }
+
+ fis = new FileInputStream("test/exampleBad1.xml");
+ try {
+ bc.setCred(null);
+ bc.setUser(null);
+ assertNull(wp.parse(bc, fis));
+ assertNull(bc.getUser());
+ assertNull(bc.getCred());
+ } finally {
+ fis.close();
+ }
+
+ XMLStreamException e = wp.parse(bc, new ByteArrayInputStream("Not XML".getBytes())); // empty
+ assertNotNull(e);
+
+ e = wp.parse(bc, new ByteArrayInputStream("".getBytes())); // empty
+ assertNotNull(e);
+
+
+ long start, count = 0L;
+ int iter = 30000;
+ File f = new File("test/CBUSevent.xml");
+ fis = new FileInputStream(f);
+ is = new BufferedServletInputStream(fis);
+ is.mark(0);
+ try {
+ while(is.read()>=0);
+ } finally {
+ fis.close();
+ }
+
+ for(int i=0;i<iter;++i) {
+ start = System.nanoTime();
+ is.reset();
+ try {
+ assertNull(wp.parse(bc, is));
+ } finally {
+ count += System.nanoTime()-start;
+ }
+ }
+ float ms = count/1000000f;
+ System.out.println("Executed " + iter + " WSSE reads from Memory Stream in " + ms + "ms. " + ms/iter + "ms per trans");
+
+ // SPECIFIC ISSUES
+
+ fis = new FileInputStream("test/error2013_04_23.xml");
+ try {
+ bc.setCred(null);
+ bc.setUser(null);
+ assertNull(wp.parse(bc, fis));
+ assertNull(bc.getUser());
+ assertNull(bc.getCred());
+ } finally {
+ fis.close();
+ }
+ } catch(Exception e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+}
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
index 0000000..7f38d94
--- /dev/null
+++ b/core/src/test/java/com/att/cadi/wsse/test/JU_XReader.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * ============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.
+ * *
+ ******************************************************************************/
+package com.att.cadi.wsse.test;
+
+import java.io.FileInputStream;
+
+import javax.xml.stream.events.XMLEvent;
+
+import org.junit.Test;
+
+import com.att.cadi.wsse.XEvent;
+import com.att.cadi.wsse.XReader;
+
+public class JU_XReader {
+ @Test
+ public void test() throws Exception {
+ FileInputStream fis = new FileInputStream("test/CBUSevent.xml");
+ try {
+ XReader xr = new XReader(fis);
+ while(xr.hasNext()) {
+ XEvent xe = xr.nextEvent();
+ switch(xe.getEventType()) {
+ case XMLEvent.START_DOCUMENT:
+ System.out.println("Start Document");
+ break;
+ case XMLEvent.START_ELEMENT:
+ System.out.println("Start Event: " + xe.asStartElement().getName());
+ break;
+ case XMLEvent.END_ELEMENT:
+ System.out.println("End Event: " + xe.asEndElement().getName());
+ break;
+ case XMLEvent.CHARACTERS:
+ System.out.println("Characters: " + xe.asCharacters().getData());
+ break;
+ case XMLEvent.COMMENT:
+ System.out.println("Comment: " + ((XEvent.Comment)xe).value);
+ break;
+ }
+ }
+ } finally {
+ fis.close();
+ }
+
+ }
+
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
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>